Codeforces Round #708(Unrated on Div. 2)

好不容易打一场CF结果unrated了,不过这场体验极差确实该unrated,感觉是div3难度

A

签到,先把所有第一次出现的数从小到大排序,剩下的随便排

B

按a[i]%m分类,然后特判0组和m/2(m为偶数时)的组,然后剩下的两两配对即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int n,m,ans,a[N];
int solve(int x,int y)
{
    if(x<y)swap(x,y);
    if(!x)return 0;
    if(x==y)return 1;
    return x-y;
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++)a[i]=0;
        for(int i=1,x;i<=n;i++)scanf("%d",&x),a[x%m]++;
        ans=0;
        if(a[0])ans++;
        for(int i=1;i<=m/2;i++)
        if(m%2==0&&i==m/2&&a[i])ans++;
        else ans+=solve(a[i],a[m-i]);
        printf("%d\n",ans);
    }
}
View Code

C

真正的签到题,k=3时,如果为奇数则是1 n/2 n/2,为4的倍数则是n/4 n/4 n/2,其余情况为2 n/2-1 n/2-1

D

本场最难的题,但依旧很水,就是个O(n^2)的DP,每次搜到i时从i-1往1搜,先反着改变状态,再正着改变状态

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5005;
int n,tag[N],a[N];
ll ans,f[N];
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&tag[i]);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),f[i]=0;
        ans=0;
        for(int i=2;i<=n;i++)
        for(int j=i-1;j;j--)
        if(tag[i]!=tag[j])
        {
            ll tmp=f[j];
            f[j]=max(f[j],f[i]+abs(a[i]-a[j]));
            f[i]=max(f[i],tmp+abs(a[i]-a[j]));
        }
        for(int i=1;i<=n;i++)ans=max(ans,f[i]);
        printf("%lld\n",ans);
    }
}
View Code

E

首先把每个数的所有平方因子去掉,问题就变成了判断序列中不存在相同的2个数,要注意的是判断平方因子时只需要扫到a[i]^(1/3)而不是a[i]^(1/2),否则会被卡常数。k=0时直接搜索即可。考虑k>0,等价于将此数删去,先预处理c[i][j],表示从i开始,删去至多j个数最远走到哪里,这个可以扫描j然后再扫描i发现答案单调就用2-pointers处理,然后直接背包DP即可,复杂度O(n((a[i])^(1/3)+k^2)),其实或许很可能有更优化的做法,但是能过就行了。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+7;
int n,k,ans,a[N],c[N][21],f[N][21];
short b[N*10];
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        for(int i=1,x,y;i<=n;i++)
        {
            scanf("%d",&x),y=1;
            for(int j=2;j*j*j<=x;j++)
            {
                while(x%(j*j)==0)x/=j*j;
                while(x%j==0)x/=j,y*=j;
            }
            int xx=sqrt(x);
            if(xx*xx==x)a[i]=y;else a[i]=x*y;
        }
        for(int i=0;i<=k;i++)
        {
            for(int j=1;j<=n;j++)b[a[j]]=0;
            int p=0,num=0;
            for(int j=1;j<=n;j++)
            {
                if(j>1)
                {
                    if(--b[a[j-1]])--num;
                }
                while(num<=i&&p<=n)if(b[a[++p]]++)++num;
                c[j][i]=p;
            }
        }
        for(int i=2;i<=n+1;i++)for(int j=0;j<=k;j++)f[i][j]=n;
        for(int i=1;i<=n;++i)
        for(int j=0;j<=k;++j)
        if(f[i][j]<n)
        for(int t=0;j+t<=k;++t)
        f[c[i][t]][j+t]=min(f[c[i][t]][j+t],f[i][j]+1);
        ans=f[n+1][0];
        for(int i=1;i<=k;i++)ans=min(ans,f[n+1][i]);
        printf("%d\n",ans);
    }
}
View Code

很没意思的一场,想为下个月初的ICPC练手,可是却是这样垃圾的题目,垃圾到我这种老年痴呆选手都能AK。

posted @ 2021-03-18 08:55  hfctf0210  阅读(225)  评论(0编辑  收藏  举报