WC2016自测

挑战NPC

原题链接
爆搜20分,贪心10分,网络流30分

//挑战NPC
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
inline char gc()
{
    static char now[1<<16],*S,*T;
    if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
    return *S++;
}
inline int read()
{
    int x=0; char ch=gc();
    while(ch<'0'||'9'<ch) ch=gc();
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x;
}
int const N=420;
int const INF=0x7FFFFFFF;
int n,m,e;
int edCnt,h[N];
struct edge{int v,c,nxt;} ed[N*N];
void edAdd(int u,int v,int c)
{
    edCnt++; ed[edCnt].v=v,ed[edCnt].c=c,ed[edCnt].nxt=h[u],h[u]=edCnt;
    edCnt++; ed[edCnt].v=u,ed[edCnt].c=0,ed[edCnt].nxt=h[v],h[v]=edCnt;
}
int ans1,link1[N],cnt1[N],link[N];
void check()
{
    memset(cnt1,0,sizeof cnt1);
    int res=0;
    for(int i=1;i<=n;i++) cnt1[link[i]]++;
    for(int i=1;i<=m;i++) if(cnt1[i]<=1) res++; else if(cnt1[i]>3) return;
    if(res>ans1) ans1=res,memcpy(link1,link,sizeof link);
}
void dfs(int u)
{
    if(u>n) check();
    for(int i=h[u];i;i=ed[i].nxt) link[u]=ed[i].v-n,dfs(u+1);
}
void work1()
{
    ans1=-1; dfs(1);
    printf("%d
",ans1);
    for(int i=1;i<=n;i++) printf("%d ",link1[i]);
    printf("
");
}
void work2()
{
    int ans2=m; if(n>m) ans2-=(n-m+1)/2;
    printf("%d
",ans2);
    for(int i=1;i<=ans2&&i<=n;i++) printf("%d ",i);
    for(int i=1;i<=n-ans2;i++) printf("%d ",ans2+(i+2)/3);
    printf("
");
}
int s,t;
int dpt[N]; int op,cl,q[N];
bool bfs()
{
    memset(dpt,0,sizeof dpt);
    op=cl=0; dpt[q[++cl]=s]=1;
    while(op<cl)
    {
        int u=q[++op]; if(u==t) break;
        for(int i=h[u];i;i=ed[i].nxt)
        {
            int v=ed[i].v,c=ed[i].c;
            if(!dpt[v]&&c) dpt[q[++cl]=v]=dpt[u]+1;
        }
    }
    return dpt[t];
}
int fill(int u,int in)
{
    if(u==t||in==0) return in;
    int out=0;
    for(int i=h[u];i;i=ed[i].nxt)
    {
        int v=ed[i].v,c=ed[i].c;
        if(dpt[v]!=dpt[u]+1||!c) continue;
        int fl=fill(v,min(in-out,c));
        if(fl==0) dpt[v]=0;
        else out+=fl,ed[i].c-=fl,ed[i^1].c+=fl;
        if(in==out) return out;
    }
    return out;
}
int Dinic()
{
    int res=0;
    while(bfs()) res+=fill(s,INF);
    return res;
}
void work3()
{
    s=0,t=n+m+1;
    for(int i=1;i<=n;i++) edAdd(s,i,1);
    int edCnt1=edCnt+1;
    for(int i=1;i<=m;i++) edAdd(n+i,t,1);
    int flow=Dinic(),ans3=m;
    if(flow!=n)
    {
        for(int i=2;i<=edCnt1;i++) ed[i].c=(i&1)?0:1;
        for(int i=edCnt1;i<=edCnt;i++) ed[i].c=(i&1)?0:3;
        Dinic(); ans3=0;
        for(int i=h[t];i;i=ed[i].nxt) if(ed[i].c<=1) ans3++;
    }
    printf("%d
",ans3);
    for(int u=1;u<=n;u++)
        for(int i=h[u];i;i=ed[i].nxt)
            if(ed[i].c==0&&ed[i].v!=s) {printf("%d ",ed[i].v-n); break;}
    printf("
"); return;
}
int main()
{
    freopen("npc.in","r",stdin);
    int task=read();
    while(task--)
    {

    n=read(),m=read(),e=read();
    edCnt=1; memset(h,0,sizeof h);
    for(int i=1;i<=e;i++) {int u=read(),v=read(); edAdd(u,v+n,1);}
    if(e<=25) work1();
    else if(e==n*m) work2();
    else work3();

    }
    return 0;
}

论战捆竹竿

原题链接
竹竿之间的捆绑可以看做在字符串后面续一段,这要求求出所有相同的前缀与后缀。转化为了给出若干个正整数,求[1,w]中有多少个数能被这些数的和表达出来。

//论战捆竹竿
#include <cstdio>
#include <cstring>
int const N=5e5+10;
int n,lim; char s[N];
int sa[N],rank[N<<1],h[N];
int cnt[N],tmp[N],rank1[N];
int min(int x,int y) {return x<y?x:y;}
bool add[N],f[N];
int tCnt,t[N];
int main()
{
    freopen("jie.in","r",stdin);
    int task; scanf("%d",&task);
    while(task--)
    {

    scanf("%d%d",&n,&lim);
    scanf("%s",s+1);
    if(lim<n) {printf("0
"); continue;}
    memset(cnt,0,sizeof cnt); memset(rank,0,sizeof rank);
    for(int i=1;i<=n;i++) cnt[s[i]]=1;
    for(int i='a';i<='z';i++) cnt[i]+=cnt[i-1];
    for(int i=1;i<=n;i++) rank[i]=cnt[s[i]];
    int k=0;
    for(int L=1;k<n;L<<=1)
    {
        memset(cnt,0,sizeof cnt);
        for(int i=1;i<=n;i++) cnt[rank[i+L]]++;
        for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1];
        for(int i=n;i>=1;i--) tmp[cnt[rank[i+L]]--]=i;
        memset(cnt,0,sizeof cnt);
        for(int i=1;i<=n;i++) cnt[rank[tmp[i]]]++;
        for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1];
        for(int i=n;i>=1;i--) sa[cnt[rank[tmp[i]]]--]=tmp[i];
        k=0; memcpy(rank1,rank,sizeof rank1);
        for(int i=1;i<=n;i++)
        {
            if(rank1[sa[i]]!=rank1[sa[i-1]]||rank1[sa[i]+L]!=rank1[sa[i-1]+L]) k++;
            rank[sa[i]]=k;
        }
    }
    k=0; memset(h,0,sizeof h);
    for(int i=1;i<=n;i++)
    {
        if(--k<0) k=0;
        if(rank[i]==1) {h[1]=0; continue;}
        while(s[i+k]==s[sa[rank[i]-1]+k]) k++;
        h[rank[i]]=k;
    }
    int len=N; memset(add,false,sizeof add);
    for(int i=rank[1]-1;i>=1;i--)
        if((len=min(len,h[i+1]))==n-sa[i]+1) add[sa[i]-1]=true;
    len=N;
    for(int i=rank[1]+1;i<=n;i++)
        if((len=min(len,h[i]))==n-sa[i]+1) add[sa[i]-1]=true;
    add[n]=true;
    for(int i=1;i<=n;i++)
        if(add[i]) for(int j=i<<1;j<=n;j+=i) add[j]=false;
    tCnt=0;
    for(int i=1;i<=n;i++) if(add[i]) t[++tCnt]=i;
    memset(f,false,sizeof f); f[n]=true;
    for(int i=n;i<=lim;i++)
        if(f[i]) for(int j=1;j<=tCnt;j++) f[i+t[j]]=true;
    int ans=0;
    for(int i=n;i<=lim;i++) if(f[i]) ans++;
    printf("%d
",ans);
    for(int i=1;i<=tCnt;i++) printf("%d ",t[i]);

    }
    return 0;
}

鏖战表达式

原题链接
友情提示这字念鏖(áo)。并不会做。
k=1可以用可持久化平衡树搞?可惜我不会。

原文地址:https://www.cnblogs.com/VisJiao/p/8485741.html