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;
}