在这里写下每题的答案吧
1.纸牌均分问题的贪心
由于最左边只能由其右边填补,所以考虑从左边开始遍历,遇到不等于平均值的就从右边补就行了。
代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int N=1005;
int n;
int a[N];

int main() {
    cin>>n;
    ll sum=0;
    for(int i=1;i<=n;i++) {
        cin>>a[i];
        sum+=a[i];
    }
    ll k=sum/n;
    int ans=0;
    for(int i=1;i<=n;i++) {
        if (a[i]<k) {
            a[i+1]-=(k-a[i]);
            a[i]=k;
            ans++;
        }
        if (a[i]>k) {
            a[i+1]+=(a[i]-k);
            a[i]=k;
            ans++;
        }
    }
    cout<<ans;
    return 0;
}

时间复杂度O(n)
2.这题直接dfs就好了,设置一个vis数组记录哪些点被遍历过了,如果遇到vis[x]==0的情况,把其子树中vis[x]==0的点全置1就好了。
代码:

#include<bits/stdc++.h>
#define pb push_back
#define SZ(x) (int)x.size()
using namespace std;

const int N=100005;
int n,x,q,num;
int vis[N];
vector<int> g[N];


void dfs(int x) {
    int len=SZ(g[x]);
    for(int i=0;i<len;i++) {
        int v=g[x][i];
        if (!vis[v]) {
            num++;
            vis[v]=1;
            dfs(v);
        }
    }
}

int main() {
    cin>>n;
    for(int i=1;i<n;i++) {
        cin>>x;
        g[x].pb(i);
    }
    cin>>q;
    int sum=n;
    while(q--) {
        scanf("%d",&x);
        if (!vis[x]) {
            num=1;
            vis[x]=1;
            dfs(x);
            sum-=num;
            printf("%d\n",sum);
        }
        else {
            printf("%d\n",sum);
        }
    }
    return 0;
}

时间复杂度O(n)
3.按照x.dy.c<y.cx.d排序,如果相等的话,id小的在前面。
代码:

#include<bits/stdc++.h>
#define FULL(x,y) memset(x,y,sizeof(x))
#define ll long long
#define SZ(x) (int)x.size()
#define pb push_back
using namespace std;

const int N=1005;

struct node {
    int c,d,id;
}no[N];

bool cmp(const node& x, const node& y) {
    if (x.d*y.c==y.d*x.c) return x.id < y.id;
    return x.d*y.c < y.d*x.c;
}

int n;

int main() {
    cin>>n;
    for(int i=1;i<=n;i++) {
        cin>>no[i].d>>no[i].c;
        no[i].id=i;
    }
    sort(no+1,no+1+n,cmp);
    for(int i=1;i<=n;i++) {
        cout<<no[i].id<<' ';
    }
    return 0;
}

时间复杂度O(nlogn)。
4.这题应该dp,令dp[i][j]表示以i为结尾且与前面的数相乘%2021==j的最长长度,则有状态转移方程:
dp[i][(a[i]*a[j])%2021]=max(dp[i][(a[i]*a[j])%2021], dp[j][a[i]]+1),当dp[j][a[i]]!=0。且还需维护总数,令开一个cnt[i][j]数组维护。
代码:

#include<bits/stdc++.h>
using namespace std;

const int N=1005;
int n;
int a[N],dp[N][2021],cnt[N][2021],f[N][2021];

int main() {
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
//初始化
    for(int i=1;i<=n;i++) {
        for(int j=i-1;j>=1;j--) {
            dp[i][(a[i]*a[j])%2021]=2;
            f[i][(a[i]*a[j])%2021]++;
        }
    }
//dp
    for(int i=3;i<=n;i++) {
        for(int j=i-1;j>=2;j--) {
            if (dp[j][a[i]]) {
                dp[i][(a[i]*a[j])%2021]=max(dp[i][(a[i]*a[j])%2021],dp[j][a[i]]+1);
            }
        }
//维护数量
        for(int j=i-1;j>=2;j--) {
            if (dp[i][(a[i]*a[j])%2021]==dp[j][a[i]]+1) {
                if (dp[j][a[i]]==2)cnt[i][(a[i]*a[j])%2021]+=f[j][a[i]];
                else cnt[i][(a[i]*a[j])%2021]+=cnt[j][a[i]];
            }
        }
    }
    int ans=0,sum=0;
    for(int i=1;i<=n;i++) {
        for(int j=0;j<2021;j++) {
            if (dp[i][j]>=3) ans=max(ans,dp[i][j]);
        }
    }
    for(int i=1;i<=n;i++) {
        for(int j=0;j<2021;j++) {
            if (dp[i][j]==ans) sum+=cnt[i][j];
        }
    }
    if (ans!=0)cout<<sum<<endl<<ans<<endl;
    else cout<<0<<endl<<0<<endl;
    return 0;
}

时间复杂度O(n^2)。