BZOJ3632:外太空旅行 随机化算法

思路:

直接随机出很多排列,然后按照顺序贪心加入当前的团,然后每一次更新答案.

不过这为什么是对的呢?

...

...

...

...

...

...

这个问题比较高深,等我变厉害了再来解释解释.

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<cstdlib>
using namespace std;
int G[51][51],seq[51],in[51];
int main(){
    int n;scanf("%d",&n);
    int a,b;while(scanf("%d%d",&a,&b)==2)G[a][b]=G[b][a]=1;
    register int i,j;
    for(i=1;i<=n;++i)seq[i]=i;
    int res=0;
    for(int T=1;T<=5000;++T){
        for(i=1;i<=n;++i)swap(seq[i],seq[rand()%i+1]);
        int nowans=0;memset(in,0,sizeof in);
        for(i=1;i<=n;++i){
            bool ok=1;
            for(j=1;j<i;++j)if(in[seq[j]]&&!G[seq[i]][seq[j]]){ok=0;break;}
            if(ok)in[seq[i]]=1,++nowans;
        }
        res=max(res,nowans);
    }
    printf("%d",res);
    return 0;
}

BZOJ3442:学习小组 费用流

思路:

一开始YY了一个上下界最小费用流,结果有负圈...看来只有消圈姿势对才能搞了.

其实只有一个问题就是如何用最大流来限制参加的人数尽可能多,我们可以连接:

\[S->i~Maxcap=k~Cost=0\]

\[i->T~Maxcap=k-1~Cost=0\]

这样就确保了最大流中每个人必定会走\(1\)的流量.

剩下的就水了.

#include<cstdio>
#include<cstring>
#include<cctype>
#include<climits>
#include<algorithm>
#include<queue>
using namespace std;
 
#define INF 0x3f3f3f3f
 
int cnt;
struct CostFlowSolver{
    int head[210],next[2000010],end[2000010],flow[2000010],cost[2000010],ind;
    int d[210],ld[210],lb[210];bool inq[210];queue<int>q;
    inline void reset(){ind=0,memset(head,-1,sizeof head);}
    inline void addedge(int a,int b,int f,int c){int q=ind++;end[q]=b,next[q]=head[a],head[a]=q,flow[q]=f,cost[q]=c;}
    inline void make(int a,int b,int f,int c){addedge(a,b,f,c),addedge(b,a,0,-c);}
    inline bool spfa(int S,int T){
        memset(d,0x3f,sizeof d),d[S]=0,inq[S]=1,q.push(S);
        while(!q.empty()){
            int i=q.front();q.pop(),inq[i]=0;for(int j=head[i];j!=-1;j=next[j])if(flow[j]&&d[end[j]]>d[i]+cost[j]){
                d[end[j]]=d[i]+cost[j],ld[end[j]]=i,lb[end[j]]=j;if(!inq[end[j]])inq[end[j]]=1,q.push(end[j]);
            }
        }return d[T]!=INF;
    }
    inline int Mincost(int S,int T){
        int res=0,Min,i;
        while(spfa(S,T)){for(Min=INF,i=T;i^S;i=ld[i])Min=min(Min,flow[lb[i]]);for(i=T;i^S;i=ld[i])flow[lb[i]]-=Min,flow[lb[i]^1]+=Min;res+=Min*d[T];}
        return res;
    }
}SteinsGate;
 
int c[110],f[110];
int main(){
    int n,m,k;scanf("%d%d%d",&n,&m,&k);register int i,j;
    for(i=1;i<=m;++i)scanf("%d",&c[i]);for(i=1;i<=m;++i)scanf("%d",&f[i]);
 
    cnt=n+m;int S=0,T=++cnt;
    SteinsGate.reset();
    for(i=1;i<=n;++i)SteinsGate.make(S,i,k,0);
    for(i=1;i<=n;++i)if(k>1)SteinsGate.make(i,T,k-1,0);
    int x;for(i=1;i<=n;++i)for(j=1;j<=m;++j){scanf("%1d",&x);if(x)SteinsGate.make(i,n+j,1,-f[j]);}
    for(j=1;j<=m;++j)for(i=1;i<=n;++i)SteinsGate.make(n+j,T,1,c[j]*(2*i-1));
 
    printf("%d",SteinsGate.Mincost(S,T));
    return 0;
}

BZOJ2502:清理雪道 上下界网络流

思路:

比较一眼.

长了一个姿势,就是有源汇有上下界网络最小流求法.

首先求可行流,得到满足下界需要的流量,就是从原来的汇流回原来的源的流量(\(C_1\)).

这不见得是最小的.

因此我们删去原来的源和原来的汇之间的边,再求一次从原来的汇到原来的源的最大流(\(C_2\)),也即退掉尽可能多的流量.

由于下界是不会退流的.

显而易见(?).\(C_1-C_2\)就是答案.

据称有时候这样做还会出问题?

大家一起来围观Kanari神犇:详细的~~~~网址如下:

http://blog.csdn.net/huzecong/article/details/8631748

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
 
#define INF 0x3f3f3f3f
 
int cnt;
struct MaxflowSolver{
    int head[110],next[80010],end[80010],flow[80010],ind;
    int d[110],gap[110],stk[110],top,cur[110];
    inline void reset(){ind=0,memset(head,-1,sizeof head);}
    inline void addedge(int a,int b,int f){int q=ind++;end[q]=b,next[q]=head[a],head[a]=q,flow[q]=f;}
    inline void make(int a,int b,int f){addedge(a,b,f),addedge(b,a,0);}
    inline void bfs(int T){
        static int q[110];int fr=0,ta=0;
        memset(d,-1,sizeof d),memset(gap,0,sizeof gap),++gap[d[T]=0],q[ta++]=T;
        while(fr^ta){
            int i=q[fr++];for(int j=head[i];j!=-1;j=next[j])if(d[end[j]]==-1)++gap[d[end[j]]=d[i]+1],q[ta++]=end[j];
        }
    }
    inline int Maxflow(int S,int T){
        int res=0,u=S,Min,ins,i;top=0,bfs(T),memcpy(cur,head,sizeof cur);
        while(d[S]<cnt+1){
            if(u==T){
                for(Min=INF,i=0;i<top;++i)if(flow[stk[i]]<Min)Min=flow[stk[i]],ins=i;
                for(res+=Min,i=0;i<top;++i)flow[stk[i]]-=Min,flow[stk[i]^1]+=Min;
                u=end[stk[top=ins]^1];
            }
            if(u!=T&&!gap[d[u]-1])break;
            bool find=0;
            for(int&j=cur[u];j!=-1;j=next[j])if(flow[j]&&d[u]==d[end[j]]+1){find=1,ins=j;break;}
            if(find){stk[top++]=cur[u]=ins,u=end[ins];}
            else{
                Min=cnt+1;for(int j=head[u];j!=-1;j=next[j])if(flow[j]&&d[end[j]]<Min)Min=d[end[j]],cur[u]=j;
                if(!--gap[d[u]])break;++gap[d[u]=Min+1];
                if(u!=S)u=end[stk[--top]^1];
            }
        }return res;
    }
}SteinsGate;
 
int main(){
    int n;scanf("%d",&n);
    register int i,j;
    cnt=n;int SS=0,ST=++cnt,S=++cnt,T=++cnt;
     
    int t,x;SteinsGate.reset();
    for(i=1;i<=n;++i){
        SteinsGate.make(S,i,INF);
        SteinsGate.make(i,T,INF);
        scanf("%d",&t);
        while(t--)scanf("%d",&x),SteinsGate.make(SS,x,1),SteinsGate.make(i,ST,1),SteinsGate.make(i,x,INF);
    }
    SteinsGate.make(T,S,INF);
     
    int res;
    SteinsGate.Maxflow(SS,ST);
    for(j=SteinsGate.head[S];j!=-1;j=SteinsGate.next[j])if(SteinsGate.end[j]==T)res=SteinsGate.flow[j],SteinsGate.flow[j]=SteinsGate.flow[j^1]=0;
    printf("%d",res-SteinsGate.Maxflow(T,S));
     
    return 0;
}

BZOJ3876:[Ahoi2014]支线剧情 有上下界网络流

思路:

首先建立有上下界的网络流模型:

\[S->1~cap=[0,INF]~cost=0\]

\[i->T~cap=[0,INF]~cost=0(1\leq{i}\leq{n})\]

\[x->y~cap=[1,INF]~cost=w_{x->y}(ForEach x->y)\]

显然是有源汇的上下界网络流模型,我们对下界不为0的边拆边变成只有上界的网络流模型:

设立附加源\(SS\),附加汇\(\ST),则对于:

\[a->b~cap=[l,r]~cost=w_{a->b}\]

我们这样转化:

(1)\[SS->b~Maxcap=l~cost=w_{a->b}\]

(2)\[a->ST~Maxcap=l~cost=0\]

(3)\[a->b~Maxcap=r-l~cost=w_{a->b}\]

注意:(1)(2)中只有一种边的费用为原来费用,另一种边的费用为0.(至于为什么这样连先挖坑)

我们还需要连:

\[T->S~Maxcap=INF~cost=0\]

然后就可以用最小费用最大流水过了.(有时间试试单纯形)

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
 
#define INF 0x3f3f3f3f
 
int cnt;
queue<int>q;
struct Solver{
    int head[5100],next[50010],end[50010],flow[50010],cost[50010],ind;
    int d[5100],used[5100],slack[5100],id;bool inq[5100];
    inline void reset(){ind=0,id=1,memset(head,-1,sizeof head);}
    inline void addedge(int a,int b,int f,int c){int q=ind++;end[q]=b,next[q]=head[a],head[a]=q,flow[q]=f,cost[q++]=c;}
    inline void make(int a,int b,int f,int c){addedge(a,b,f,c),addedge(b,a,0,-c);}
    inline void spfa(int S,int T){
        memset(d,0x3f,sizeof d),d[S]=0,inq[S]=1,q.push(S);
        while(!q.empty()){
            int i=q.front();q.pop(),inq[i]=0;
            for(int j=head[i];j!=-1;j=next[j])if(flow[j]&&d[end[j]]>d[i]+cost[j]){
                d[end[j]]=d[i]+cost[j];
                if(!inq[end[j]])inq[end[j]]=1,q.push(end[j]);
            }
        }for(int i=0;i<=cnt;++i)d[i]=d[T]-d[i];
    }
    inline bool Newlabel(){
        int Min=INF;for(int i=0;i<=cnt;++i)if(used[i]!=id&&slack[i]<Min)Min=slack[i];
        if(Min==INF)return 0;
        for(int i=0;i<=cnt;++i)if(used[i]==id)used[i]=-1,d[i]+=Min;return 1;
    }
    int Getflow(int p,int T,int maxflow){
        if(p==T)return maxflow;
        used[p]=id;
        for(int j=head[p];j!=-1;j=next[j]){
            if(flow[j]&&used[end[j]]!=id&&d[end[j]]+cost[j]==d[p]){
                int to=Getflow(end[j],T,maxflow<flow[j]?maxflow:flow[j]);if(to){flow[j]-=to,flow[j^1]+=to;return to;}
            }else if(flow[j])slack[end[j]]=min(slack[end[j]],d[end[j]]+cost[j]-d[p]);
        }return 0;
    }
    int Mincost(int S,int T){
        int res(0),get;spfa(S,T);
        do{
            memset(slack,0x3f,sizeof slack);
            while((get=Getflow(S,T,INF)))res+=d[S]*get,++id;
        }
        while(Newlabel());
        return res;
    }
}SteinsGate;
int main(){
    #ifndef ONLINE_JUDGE
    freopen("tt.in","r",stdin);
    #endif
 
    int n;scanf("%d",&n);
    cnt=n;int SS=0,ST=++cnt,S=++cnt,T=++cnt;
    SteinsGate.reset();
 
    int t,a,c;register int i,j;
    SteinsGate.make(S,1,INF,0);
    for(i=1;i<=n;++i){
        SteinsGate.make(i,T,INF,0);
        scanf("%d",&t);
        while(t--)scanf("%d%d",&a,&c),SteinsGate.make(SS,a,1,c),SteinsGate.make(i,ST,1,0),SteinsGate.make(i,a,INF,c);
    }
    SteinsGate.make(T,S,INF,0);
 
    printf("%d",SteinsGate.Mincost(SS,ST));
 
    return 0;
}

BZOJ2119:股市的预测 分治+后缀数组

思路:

一种分治的神做法.建议去看原论文[2011年集训队作业]

#include<map>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
 
#define INF 0x3f3f3f3f
 
#define N 50010
 
int n,lim;
 
int len[N];
inline void pre(int n){
    for(int i=2;i<=n;++i)len[i]=len[i>>1]+1;
}
 
int Read[N],s[N],ss[N],v[N],nv[N],q[N],c[N];
inline bool cmp(int x,int y,int hl,int n){
    return v[x]==v[y]&&((x+hl>n&&y+hl>n)||(x+hl<=n&&y+hl<=n&&v[x+hl]==v[y+hl]));
}
struct SuffixArray{
    int rk[N],h[N],sa[N],rmqh[N][16];
    inline void Init(int s[],int n,int m){
        int i,j,k,hl,id;
        for(i=1;i<=m;++i)c[i]=0;
        for(i=1;i<=n;++i)++c[v[i]=s[i]];
        for(i=2;i<=m;++i)c[i]+=c[i-1];
        for(i=n;i>=1;--i)sa[c[v[i]]--]=i;
        for(int d=1;;++d){
            for(hl=1<<(d-1),id=0,i=n-hl+1;i<=n;++i)q[++id]=i;
            for(i=1;i<=n;++i)if(sa[i]>hl)q[++id]=sa[i]-hl;
            for(i=1;i<=m;++i)c[i]=0;
            for(i=1;i<=n;++i)++c[v[q[i]]];
            for(i=2;i<=m;++i)c[i]+=c[i-1];
            for(i=n;i>=1;--i)sa[c[v[q[i]]]--]=q[i];
            for(i=m=1;i<=n;++m,i=j+1){
                for(j=i;j!=n&&cmp(sa[j],sa[j+1],hl,n);++j);
                for(k=i;k<=j;++k)nv[sa[k]]=m;
            }
            if(--m==n)break;
            for(i=1;i<=n;++i)v[i]=nv[i];
        }
         
        for(i=1;i<=n;++i)rk[sa[i]]=i;
        for(i=1;i<=n;++i){
            if(rk[i]==1)continue;
            j=max(0,h[rk[i-1]]-1);
            while(i+j<=n&&sa[rk[i]-1]+j<=n&&s[i+j]==s[sa[rk[i]-1]+j])++j;
            h[rk[i]]=j;
        }
        for(i=1;i<=n;++i)rmqh[i][0]=h[i];
        for(j=1;j<=15;++j)for(i=1;i+(1<<j)-1<=n;++i)rmqh[i][j]=min(rmqh[i][j-1],rmqh[i+(1<<(j-1))][j-1]);
    }
    inline int askrmq(int l,int r){
        return min(rmqh[l][len[r-l+1]],rmqh[r-(1<<len[r-l+1])+1][len[r-l+1]]);
    }
    inline int getlcp(int x,int y){
        int lins=min(rk[x],rk[y]),rins=max(rk[x],rk[y]);
        if(lins==rins)return n-x+1;
        else return askrmq(lins+1,rins);
    }
}Steins,revSteins;
 
inline int lcp(int x,int y){
    return Steins.getlcp(x,y);
}
inline int lcs(int x,int y){
    return revSteins.getlcp(n-x+1,n-y+1);
}
inline bool same(int l1,int l2,int len){
    return lcp(l1,l2)>=len;
}
 
map<int,int>M;int sav[N];
 
long long res;
inline void SteinsGate(int l,int r){
    if(r-l+1<lim+2)return;
    int mid=(l+r)>>1;
    SteinsGate(l,mid),SteinsGate(mid+1,r);
    int prelen,suflen,insl,insr,nowlen;
    for(prelen=0;prelen<lim;++prelen){
        suflen=lim-1-prelen;
        insl=mid-prelen,insr=mid+suflen;
        if(insl>=l&&insr<=r)
            for(nowlen=1;insl-nowlen>=l&&insr+nowlen<=r;++nowlen)if(same(insl-nowlen,insr+1,nowlen))++res;
    }
    int lins,rins,anotherins,Lcp,Lcs,up,down;
    for(anotherins=l;anotherins<=r;++anotherins){
        if((anotherins>mid&&anotherins-mid-1>=lim)||(mid>anotherins&&mid-anotherins-1>=lim)){
            lins=min(mid,anotherins),rins=max(mid,anotherins);
            Lcp=lcp(lins,rins),Lcs=lcs(lins,rins);
            down=-INF,up=INF;
            down=max(down,rins-Lcs-lim+1);//rins-(x+m-1)<=lcs
            up=min(up,lins+Lcp);//x-lins<=lcp
            down=max(down,l-lim+rins-lins);//lins-(rins-(x+m-1))+1>=l
            up=min(up,r+1+lins-rins);//rins+(x-lins)-1<=r
            down=max(down,lins+1),up=min(up,rins-1);//lins<=x<=rins
            down=max(down,lins+2-lim),up=min(up,rins-lim);//lins<=x+m-1<=rins
            if(down<=up){
                res+=up-down+1;
                if(anotherins<mid&&down==anotherins+1)--res;
            }
        }
    }
}
 
int main(){
    #ifndef ONLINE_JUDGE
    freopen("tt.in","r",stdin);
    #endif
    scanf("%d%d",&n,&lim);register int i;
    for(i=0;i<n;++i)scanf("%d",&Read[i]);
    for(--n,i=1;i<=n;++i)s[i]=Read[i]-Read[i-1];
     
    for(i=1;i<=n;++i)sav[i]=s[i];sort(sav+1,sav+n+1);
    int id=0;for(sav[0]=-INF,i=1;i<=n;++i)if(sav[i]!=sav[i-1])M[sav[i]]=++id;
    for(i=1;i<=n;++i)s[i]=M[s[i]];
    for(i=n;i>=1;--i)ss[i]=s[n+1-i];
     
    pre(n),Steins.Init(s,n,id),revSteins.Init(ss,n,id);
     
    SteinsGate(1,n);
     
    cout<<res<<endl;
     
    return 0;
}

BZOJ2795:[Poi2012]A Horrible Poem 暴力+hash(&&BZOJ2890)

思路:

一开始的暴力非常容易:对于每一组询问直接暴力枚举答案即可.易知答案仅可能是字串长度的约数,再利用hash\(O(1)\)判断.因此单组询问的复杂度\(O(\sqrt{n})\).这种方法比较卡常数.

其实,存在一种更加科学的方法.

我们将长度分解质因数,考虑每个质因子的幂次.这样即可在\(O(logn)\)的时间内出解.十分科学.

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
 
#define INF 0x3f3f3f3f
 
namespace Fio{
    inline int getc(){
        static const int L=1<<15;static char buf[L],*S=buf,*T=buf;
        if(S==T){T=(S=buf)+fread(buf,1,L,stdin);if(S==T)return EOF;}
        return*S++;
    }
    template<typename T>inline void Get(T&x){
        int c;while(!isdigit(c=getc()));x=c-'0';while(isdigit(c=getc()))x=(x<<1)+(x<<3)+c-'0';
    }
    char buf[20000000],*o=buf;
    template<typename T>inline void Print(T x){
        static int stk[100];
        if(x<0)x=-x,*o++='-';
        if(!x)*o++=48;else{int top=0;for(;x;x/=10)stk[++top]=x%10;for(int i=top;i;--i)*o++=48+stk[i];}
        *o++='\n';
    }
    inline void Final(){fwrite(buf,1,o-buf,stdout);}
}
 
#define N 500010
 
typedef long long LL;
static const int seed=131;
static const int mod=(1e9)+9;
 
int n,f[N],mi[N];char s[N];
 
inline int get(int l,int r){
    return (f[l]-(LL)f[r+1]*mi[r-l+1]%mod+mod)%mod;
}
inline bool same(int l1,int r1,int l2,int r2){
    return get(l1,r1)==get(l2,r2);
}
 
int p[N],minp[N],cnt;bool np[N];
inline void pre(int n){
    register int i,j;
    for(i=2;i<=n;++i){
        if(!np[i])p[++cnt]=minp[i]=i;
        for(j=1;j<=cnt&&p[j]*i<=n;++j){
            np[i*p[j]]=1,minp[i*p[j]]=min(minp[i],p[j]);
            if(i%p[j]==0)break;
        }
    }
}
 
inline int Solve(int l,int r){
    int len=r-l+1;if(len==1)return 1;
    int tmp=len,res=len;
    while(tmp!=1){
        int nowp=minp[tmp],ans=1,calclen=len,t=1;
        while(1){
            if(calclen==len||same(l,l+(len-calclen)-1,r-(len-calclen)+1,r))ans=max(ans,t);
            if(calclen%nowp!=0)break;
            t*=nowp,calclen/=nowp;
        }
        for(res/=ans;tmp%nowp==0;tmp/=nowp);
    }
    return res;
}
int main(){
    using namespace Fio;
    scanf("%d",&n);scanf("%s",s+1);
    register int i;
    for(i=n;i>=1;--i)f[i]=((LL)seed*f[i+1]+s[i]-'a')%mod;
    for(mi[0]=1,i=1;i<=n;++i)mi[i]=(LL)mi[i-1]*seed%mod;
    pre(n);
     
    int m;Get(m);int l,r;
    while(m--){
        Get(l),Get(r);
        Print(Solve(l,r));
    }
    Final();
    return 0;
}

BZOJ3174:[Tjoi2013]拯救小矮人 贪心+dp

思路:

假设在能逃出相同多数目的小矮人的情况下,我们更愿意让逃生能力更强的小矮人留到最后.

逃生能力就是指\(a_i+b_i\),也即在下面垫的总高度确定时更容易达到更高的高度.

这样我们就有了一个贪心选择顺序,我们设\(f[i]\)表示逃生了\(i\)个小矮人时下面垫的总高度的最大值,并依据这个判定能否再逃出一人即可.

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
 
#define N 2010
struct Case{int a,b;bool operator<(const Case&B)const{return a+b<B.a+B.b;}}S[N];
 
int f[N];
int main(){
    int n,m;scanf("%d",&n);register int i,j;for(i=1;i<=n;++i)scanf("%d%d",&S[i].a,&S[i].b);
    sort(S+1,S+n+1);
    scanf("%d",&m);
    memset(f,-1,sizeof f);for(f[0]=0,i=1;i<=n;++i)f[0]+=S[i].a;
    int ans=0;
    for(i=1;i<=n;++i){
        for(j=ans;j>=0;--j){
            if(f[j]+S[i].b>=m)f[j+1]=max(f[j+1],f[j]-S[i].a);
             
        }if(f[ans+1]>=0)++ans;
    }
    printf("%d\n",ans);
    return 0;
}

BZOJ2799:[Poi2012]Salaries 贪心

思路:

我们维护以每一个节点为根的子树内部有多少个没有确定权值的点,另外,我们利用一个数组维护每个权值已经给了哪个节点.

我们从小到大遍历每个权值,若这个权值当前并没有确定给哪个节点,则将其压入栈中;否则我们在对应节点的子树中进行一系列确定操作:

我们维护栈中有多少个权值,以及有多少个自由权值.(这个是什么一会再说)

若未确定的节点数正好等于当前的自由权值数与栈中的权值总数,显而易见这些权值都应该分配给这棵子树.但是只有只有一个儿子的情况才能确定这个权值.所以我们不断在链上去找即可.这个过程可能确定了一些权值,随后我们将栈清空,并令自由权值的数目为0.因为他们只能被拘束在这颗子树内,而不能去别的地方.

若不然,我们将自由权值及栈中的权值分配给这棵子树所需要的数目,剩下的全部变成自由权值.

我们发现栈中的权值和自由权值很像,但是为什么不都搞成自由权值,而是非要维护一个栈呢?

这个问题显而易见:自由权值都是可以互相交换的(等价的),而栈中的元素显然不是!

于是\(O(n)\)水.

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
 
namespace Fio{
    inline int getc(){
        static const int L=1<<15;static char buf[L],*S=buf,*T=buf;
        if(S==T){T=(S=buf)+fread(buf,1,L,stdin);if(S==T)return EOF;}
        return*S++;
    }
    template<typename T>inline void Get(T&x){
        int c;while(!isdigit(c=getc()));x=c-'0';while(isdigit(c=getc()))x=(x<<1)+(x<<3)+c-'0';
    }
}
 
#define N 1000010
vector<int>v[N];
int pa[N],w[N];
int q[N],fr,ta,ins[N],size[N],stk[N],top,tot,sum;
int main(){
    int n;Fio::Get(n);
    register int i,j;
    for(i=1;i<=n;++i){
        Fio::Get(pa[i]),Fio::Get(w[i]);if(i==pa[i])w[i]=n;
        if(w[i])q[ta++]=i,ins[w[i]]=i;else v[pa[i]].push_back(i);
    }
    int u;
    while(fr<ta){
        u=q[fr++];
        for(j=0;j<v[u].size();++j)q[ta++]=v[u][j];
    }
    for(i=n-1;i>=0;--i){
        u=q[i];
        size[u]=1;
        for(j=0;j<v[u].size();++j)size[u]+=size[v[u][j]];
    }
    int tot=0;
    for(i=1;i<=n;++i){
        if(!(u=ins[i])){stk[++top]=i;continue;}
        int sum=0,ac=0,pretop=top;
        for(j=0;j<v[u].size();++j)sum+=size[v[u][j]];
        if(sum==tot+top){
            for(;v[u].size()==1&&top;u=v[u][0])
                ins[w[v[u][0]]=stk[top--]]=v[u][0],++ac,--sum;
            if(sum)tot=top=0;
        }
        else{
            if(sum)tot=tot+top-sum,top=0;
        }
    }
    for(i=1;i<=n;++i)printf("%d\n",w[i]);
    return 0;
}

 

Cena以及Lemon SpecialJudge的姿势

这能算是普及?只是自己留一个存档.

有需要的就来自己脑补吧.

UPD:留一个lemon的对应参数说明:

Special Judge参数传送说明:
argv[1]: 标准输入文件
argv[2]: 选手输出文件
argv[3]: 标准输出文件
argv[4]: 本测试点满分
argv[5]: 分数输出文件(必须创建),仅一行,包含一个非负整数,表示得分。
argv[6]: 额外信息文件(可以不创建)

#include <cstdio>
#include <cstring>
#include <cstdlib>
FILE *fscore, *freport, *fstd, *fin, *fout;

inline void getScore(int x) {
	fprintf(fscore, "%d", x);
}

char s[2010], output[2010], tmp[1000000], *o = tmp;
inline int Judge() {
	fscanf(fin, "%s", s);
	int len = strlen(s);
	
	fscanf(fout, "%s", output);
	int len_out = strlen(output);
	
	int std_len;
	fscanf(fstd, "%d", &std_len);
	if (len_out != std_len)
		return 1;
	
	register int i, j, k, p, q;
	for(i = 0; i < len_out; ++i)
		if (output[i] != '$' && output[i] != '*' && !(output[i] >= 'a' && output[i] <= 'z'))
			return 2;
	if (output[len_out - 1] != '$')
		return 2;

	for(i = 0; i < len_out; ) {
		if (!(output[i] >= 'a' && output[i] <= 'z'))
			return 2;
		for(j = i; output[j] != '$'; ++j);
		for(k = i; output[k] != '*' && output[k] != '$'; ++k);
		for(p = k; p <= j; ++p)
			if (output[p] != '$' && output[p] != '*')
				return 2;
		for(p = 1; p <= j - k + 1; ++p)
			for(q = i; q < k; ++q)
				*o++ = output[q];
		i = j + 1;
	}
	
	int outputlen = o - tmp;
	if (outputlen != len)
		return 3;
	for(i = 0; i < len; ++i)
		if (tmp[i] != s[i])
			return 3;
	
	return 0;
}

int main(int argc, char *argv[]) {
	fscore = fopen("score.log", "w");
	freport = fopen("report.log", "w");
	
	fstd = fopen(argv[2], "r"); //测试点标准输出文件
	
	fin = fopen("compress.in", "r");
	fout = fopen("compress.out", "r"); //用户输入、输出文件
	
	if (!fout) {
		getScore(0);
		fprintf(freport, "Empty File!");
	}
	else {
		int res = Judge();
		if (res == 0)
			getScore(10), fprintf(freport, "Right Output!");
		else if (res == 1)
			getScore(0), fprintf(freport, "Wrong Length!");
		else if (res == 2)
			getScore(0), fprintf(freport, "Wrong Format!");
		else if (res == 3)
			getScore(0), fprintf(freport, "Wrong Change!");
	}
	
	fclose(fscore);
	fclose(freport);
	
	return 0;
}
#include<bits/stdc++.h>

FILE *fscore,*freport,*fstd,*fin,*fout;

inline void GetScore(int d){
	fprintf(fscore,"%d",d);
}
inline void End(){
	fclose(fscore),fclose(freport);
}

int d[1010],x[1000010],y[1000010];
inline void work(int a,int b){
	d[b]-=d[a],d[a]*=2;
}
int main(int argc,char*argv[]){
	fscore=fopen(argv[5],"w");//得分文件
	freport=fopen(argv[6],"w");//报告文件
	fstd=fopen(argv[3],"r");//标准输出
	fin=fopen(argv[1],"r");//标准输入
	fout=fopen(argv[2],"r");//用户输出
	
	int stdans;fscanf(fstd,"%d",&stdans);
	int yourans;
	if(fscanf(fout,"%d",&yourans)==0){
		fprintf(freport,"No output.");
		GetScore(0);
		End();return 0;
	}
	
	if(stdans==-1){
		if(yourans!=-1){
			fprintf(freport,"No solution but you output an ans");
			GetScore(0);
			End();return 0;
		}
		else{
			fprintf(freport,"OK"),GetScore(10);
			End();return 0;
		}
	}
	else{
		if(yourans==-1){
			fprintf(freport,"There exists some solutions but you output no ans");
			GetScore(0);
			End();return 0;
		}
		else if(yourans<0){
			fprintf(freport,"Wrong:T<0");
			GetScore(0);
			End();return 0;
		}
		else if(yourans>1000000){
			fprintf(freport,"Too many operates");
			GetScore(0);
			End();return 0;
		}
		else{
			int n;register int i;
			fscanf(fin,"%d",&n);
			for(i=1;i<=n;++i)fscanf(fin,"%d",&d[i]);

			for(i=1;i<=yourans;++i){
				if(fscanf(fout,"%d%d",&x[i],&y[i])!=2){
					fprintf(freport,"output Not enough");
					GetScore(0);
					End();return 0;
				}
			}
			
			int cash;
			if(fscanf(fout,"%d",&cash)==1){
				fprintf(freport,"Too many output");
				GetScore(0);
				End();return 0;
			}
			
			for(i=1;i<=yourans;++i){
				if(x[i]==y[i]){
					fprintf(freport,"Wrong at Line%d:x=y",i+1);
					GetScore(0);
					End();return 0;
				}
				else if(d[x[i]]>d[y[i]]){
					fprintf(freport,"Wrong at Line%d:a[x]>a[y]",i+1);
					GetScore(0);
					End();return 0;
				}
				else work(x[i],y[i]);
			}
			
			int last=0;
			for(i=1;i<=n;++i)if(d[i]>0)++last;
			if(last==2){
				fprintf(freport,"OK"),GetScore(10);
				End();return 0;
			}
			else{
				fprintf(freport,"yourlast=%d,and it's larger then 2",last),GetScore(0);
				End();return 0;
			}
		}
	}
	return 0;
}

BZOJ3028:食物 生成函数

思路:

对于一个数列\(f_0,f_1,f_2,...\),我们可以对应的构造一个多项式函数\(f_0+f_1{x}+f_2{x^2}+...\),也即若我们可以知道函数的\(x^n\)项系数,就能知道\(f_n\).

一眼看起来并没有什么用处,实际上有的多项式函数可以化为十分简洁的形式.

例如\(f_0=f_1=f_2=...=1\),其对应的多项式函数为\(1+x+x^2+x^3+...\).

由于我们只在意式子的"型",因此可以利用方便的等比数列来表示:

\[\frac{1-x^{\infty}}{1-x}\]

若\(|x|<1\),则可以化为:

\[\frac{1}{1-x}\]

事实上我们不必在意\(x\)的范围,仅仅是看重形式便可以了.

对于这道题目的计数问题,我们仅需搞出所有限制的多项式,然后将它们相乘.

最终经过一些化简得到:

\[\frac{x}{(1-x)^4}\]

接下来有一种处理方法就是暴力泰勒展开(就是无限求导),感觉不可能找到规律(至少我是不会).

然后又一种方法就是再进行变形:

\[x(1+x+x^2+...)^4\]

求上式的\(x^n\)次项的系数.于是变成简单的组合数问题.

#include<cstdio>
#include<cstring>
#include<cctype>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;

char s[510];
int main(){
	scanf("%s",s);int len=strlen(s);register int i,j;
	int t=0;for(i=0;i<len;++i)t=(t*10+s[i]-'0')%10007;
	int res=t;res=res*(t+1)%10007,res=res*(t+2)%10007;
	res=res*1668%10007;
	printf("%d",res);
	return 0;
}