Codeforces Round #662 (Div. 2)

AB

签到

C

开始还写个假的模拟法,后来发现可以直接贪心,从大到小枚举答案x,发现相同数的个数不超过n/x+1,且等于n/x+1的不超过n%x即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int n,m,ans,a[N],b[N],c[N];
bool check(int x)
{
    int num=n/x,mx=n%x;
    if(a[1]>num+1)return 0;
    if(m>mx&&a[mx+1]>num)return 0;
    return 1;
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n+1;i++)a[i]=b[i]=c[i]=0;
        for(int i=1,x;i<=n;i++)scanf("%d",&x),b[x]++;
        m=ans=0;
        for(int i=1;i<=n;i++)if(b[i])a[++m]=b[i];
        sort(a+1,a+m+1),reverse(a+1,a+m+1);
        for(int i=n-1;~i;i--)
        if(check(i+1)){ans=i;break;}
        printf("%d\n",ans);
    }
}
View Code

D

b[i][j]表示从i,j格开始向左右两边扩展(相同字符可以扩展)的最大的长度,c[i][j]表示从i,j格开始向上下两边扩展(相同字符可以扩展)的最大的长度。然后扫描每一个格子时用线段树,细节有点多,看我代码应该能完全懂,复杂度O(nmlogn)

#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int N=2200;
int n,m,d[N],mn[N<<2],lazy[N<<2],b[N][N],c[N][N];
ll ans;
char a[N][N];
void sol1(int i,int l,int r){for(int j=l;j<=r;j++)b[i][j]=min(j-l,r-j);}
void sol2(int j,int l,int r){for(int i=l;i<=r;i++)c[i][j]=min(i-l,r-i);}
void build(int l,int r,int rt)
{
    lazy[rt]=0;
    if(l==r){mn[rt]=d[l];return;}
    int mid=l+r>>1;
    build(lson),build(rson);
    mn[rt]=min(mn[rt<<1],mn[rt<<1|1]);
}
void pushdown(int rt)
{
    int v;
    if(lazy[rt])
    v=lazy[rt],mn[rt<<1]+=v,lazy[rt<<1]+=v,mn[rt<<1|1]+=v,lazy[rt<<1|1]+=v,lazy[rt]=0;
}
void update(int L,int R,int v,int l,int r,int rt)
{
    if(L<=l&&r<=R){mn[rt]+=v,lazy[rt]+=v;return;}
    pushdown(rt);
    int mid=l+r>>1;
    if(L<=mid)update(L,R,v,lson);
    if(R>mid)update(L,R,v,rson);
    mn[rt]=min(mn[rt<<1],mn[rt<<1|1]);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
    if(n==1||m==1){printf("%d",n*m);return 0;}
    for(int i=1;i<=n;i++)
    {
        int l=1,r;
        for(r=2;r<=m;r++)if(a[i][r]!=a[i][r-1])sol1(i,l,r-1),l=r;
        sol1(i,l,m);
    }
    for(int j=1;j<=m;j++)
    {
        int l=1,r;
        for(r=2;r<=n;r++)if(a[r][j]!=a[r-1][j])sol2(j,l,r-1),l=r;
        sol2(j,l,n);
    }
    for(int j=1;j<=m;j++)
    {
        for(int i=1;i<=n;i++)d[i]=b[i][j]+i-1;
        build(1,n,1);
        for(int i=1;i<=n;i++)
        {
            ans+=min(c[i][j],min(min(i-1,n-i),mn[1]))+1;
            if(i<n)update(1,i,1,1,n,1),update(i+1,n,-1,1,n,1);
        }
    }
    printf("%lld",ans);
}
View Code

E

E1口胡了一个O(串长^2),感觉是后缀数组+DP,但老年选手写不来

用KD-Tree打的,rank55 rating+=104 上橙啦

posted @ 2020-08-08 08:30  hfctf0210  阅读(174)  评论(0编辑  收藏  举报