C
题意:有n个不同版本的野兽,定义属性:第 i 个野兽有 i 个眼睛和 h[i] 个角,你可以任意从中选择一个野兽进行进化,每次进化角数量必须增加,而且进化后假设有a 个眼睛 b个角,假设h[i]=b,那么abs(a-i)<=w,否则不能进化,求最多的进化次数。
思路:从大到小枚举h[i]的值,设d[i]为从第 i 个野兽开始进化所能得到的答案,如果对于 j,h[j]<h[i]且abs(i-j)<=w,那么d[j]=max(d[j],d[i]+1)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5010;
int x[maxn],y[maxn];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
#endif
int n,w,ans,p = 0;
cin >> n >> w;
for(int i = 1;i <= n; i++)
{
cin >> x[i];
if(x[i] > x[p])
p = i;
}
for(int k = 1;k <= n; k++)
{
for(int i = 1;i <= n; i++)
{
if(x[i] < x[p] && abs(i - p) <= w)
{
y[i] = max(y[i],y[p] + 1);
ans = max(ans,y[i]);
}
}
x[p] = maxn;
p = 0;
for(int i = 1;i <= n; i++)
if(x[i] != maxn && x[i] > x[p])
p = i;
}
cout << ans << endl;
return 0;
}
D
题意:有n个房子的坐标,你要建立公交车站,使得每个房子离最近的车站不过10公里,求最少的车站。
思路:直接贪心,从左往右遍历房子,如果一个房子没被覆盖,就在他右边10公里建车站即可。
#include<bits/stdc++.h>
using namespace std;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
int ans = 0,index = -100;
for(int i = 0;i < n; i++)
{
int x;
cin >> x;
if(x > index + 10)
{
index = x + 10;
ans++;
}
}
cout << ans << endl;
}
return 0;
}
G
题意:给一些有向边,如果两个点可以互达,那么这两个点属于同一组,求你给有向图分组。
思路:就是强连通裸题,裸的Tarjan。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
struct Edge
{
int to,next;
}edge[maxn];
int head[maxn],tot,low[maxn],dfn[maxn],Stack[maxn],belong[maxn];
int Index,top,scc;
bool Instack[maxn];
void add(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void Tarjan(int u)
{
int v;
low[u] = dfn[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for(int i = head[u];i != -1;i = edge[i].next)
{
v = edge[i].to;
if(!dfn[v])
{
Tarjan(v);
if(low[u] > low[v])
low[u] = low[v];
}
else if(Instack[v] && low[u] > dfn[v])
low[u] = dfn[v];
}
if(low[u] == dfn[u])
{
scc++;
do{
v = Stack[--top];
Instack[v] = false;
belong[v] = scc;
}
while(v != u);
}
}
void solve(int n)
{
memset(dfn,0, sizeof(dfn));
memset(Instack,false, sizeof(false));
Index = scc = top = 0;
for(int i = 0;i < n; i++)
if(!dfn[i])
Tarjan(i);
}
void init()
{
tot = 0;
memset(head,-1, sizeof(head));
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while (t--)
{
init();
int n,m;
cin >> n >> m;
for(int i = 0;i < m; i++)
{
int x,y;
cin >> x >> y;
add(x,y);
}
solve(n);
cout << scc << endl;
}
return 0;
}
L
题意:求一个最大的子矩阵,子矩阵的和要么为0要么为1。
一种单调队列的思想,卡读入,常规读入会超时
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
char c[maxn][maxn];
int sum[maxn][maxn],ans[maxn][maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d %d",&n,&m);
for(int i = 1;i <= n; i++)
{
for(int j = 1;j <= m; j++)
{
c[i][j] = getchar();
while(c[i][j] != '0' && c[i][j] != '1')
c[i][j] = getchar();
sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + (c[i][j] == '1');
}
}
int mx = 0;
for(int i = 1;i <= n; i++)
{
for(int j = 1;j <= m; j++)
{
ans[i][j] = ans[i-1][j-1] - 1;
if(ans[i][j] < 1)
ans[i][j] = 1;
while(i + ans[i][j] <= n && j + ans[i][j] <= m && (sum[i + ans[i][j]][j + ans[i][j]] - sum[i-1][j + ans[i][j]] - sum[i + ans[i][j]][j - 1] + sum[i - 1][j - 1] <= 1))
ans[i][j]++;
mx = max(mx,ans[i][j]);
}
}
printf("%d\n",mx);
}
return 0;
}