bzoj复习

bzoj复习

bzoj复习

1 1001

此题其实是一道网络流的裸题,不过也可以用最短路解决。
此处有网络流和dijstra的code。

#include <cstdio>
#include <cstring>
const int M=1000*1000*6+20,N=1000*1000+10;
char inb[1<<16],*ins=inb,*ine=inb;
#define getc() ((ins==ine&&(ine=(ins=inb)+fread(inb,1,1<<16,stdin),ins==ine))?EOF:*ins++)
inline int geti() {
    register int a; register char c;
    while(c=getc(),c<'0');a=c-'0';
    while(c=getc(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return a;
}
int to[M],nxt[M],C[M],head[N],tote;
#define adde(a,b,c) {\
    to[tote]=b,nxt[tote]=head[a],C[tote]=c;\
    head[a]=tote++;\
}
#define min(a,b) (a<b?a:b)
int S,T,d[N],dt[N];
int dfs(int u,int flow) {
    if(u==T||!flow) return flow;
    int r=0,t,v;
    for(int i=head[u];~i;i=nxt[i])
        if(d[v=to[i]]+1==d[u]&&C[i]) {
            t=dfs(v,min(C[i],flow));
            r+=t,flow-=t;
            C[i]-=t,C[i^1]+=t;
            if(!flow||d[S]>T) return r;
        }
    if(!(--dt[d[u]])) d[S]=T+1;
    ++dt[++d[u]]; return r;
}
inline int SAP() {
    int *l=dt,*r=dt;
    register int ans=0,i;
    *r++=T; d[T]=1;
    while(l<r) {
        for(i=head[*l];~i;i=nxt[i])
            if(!d[to[i]]) d[*r++=to[i]]=d[*l]+1;
        ++l;
    }
    memset(dt,0,T+2<<2);
    for(i=S;i<=T;++i)
        ++dt[d[i]];
    while(d[S]<T+1) ans+=dfs(S,0x7f7f7f7f);
    return ans;
}
int main() {
    register int n=geti(),m=geti(),i,j,k;
    S=1,T=n*m;
    memset(head,-1,T+1<<2);
    for(i=1;i<=n;++i)
        for(j=1;j^m;++j) {
            k=geti();
            adde((i-1)*m+j,(i-1)*m+j+1,k);
            adde((i-1)*m+j+1,(i-1)*m+j,k);
        }
    for(i=1;i^n;++i)
        for(j=1;j<=m;++j) {
            k=geti();
            adde((i-1)*m+j,i*m+j,k);
            adde(i*m+j,(i-1)*m+j,k);
        }
    for(i=1;i^n;++i)
        for(j=1;j^m;++j) {
            k=geti();
            adde((i-1)*m+j,i*m+j+1,k);
            adde(i*m+j+1,(i-1)*m+j,k);
        }
    printf("%d\n",SAP());
    return 0;
}
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
char inb[1<<16],*ins=inb,*ine=inb;
#define getc() ((ins==ine&&(ine=(ins=inb)+fread(inb,1,1<<16,stdin),ins==ine))?EOF:*ins++)
inline int geti() {
    register int a; register char c;
    while(c=getc(),c<'0');a=c-'0';
    while(c=getc(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return a;
}
#define N 2000000
struct E{int to,v;E*nxt;}CD[N*5],*cd=CD,*head[N];
#define adde(a,b,c) (cd->v=c,cd->to=b,cd->nxt=head[a],head[a]=cd++)
int d[N];
#define pr pair<int,int>
priority_queue< pr, vector< pr >,greater < pr > >heap;
int main() {
    int n,m; scanf("%d%d",&n,&m);
    register int S=0,T=(n-1)*(m-1)*2+1;
    if(n==1|m==1) {
        register int ans=1<<30,a;
        while(scanf("%d",&a)==1) if(a<ans) ans=a;
        printf("%d\n",ans);
        return 0;
    }
    register int e=1,f=2,i,j,a,b,c;
    for(i=0;i^n;++i)
        for(j=1;j^m;++j) {
            c=geti();
            if(!i) a=T,b=f,f+=2;
            else if(i==n-1) a=e,b=0,e+=2;
            else a=e,b=f,e+=2,f+=2;
            adde(a,b,c);adde(b,a,c);
        }
    e=1,f=2;
    for(i=1;i^n;++i)
        for(j=0;j^m;++j) {
            c=geti();
            if(!j) a=0,b=e,e+=2;
            else if(j==m-1) a=f,b=T,f+=2;
            else a=e,b=f,e+=2,f+=2;
            adde(a,b,c);adde(b,a,c);
        }
    e=1,f=2;
    for(i=1;i^n;++i)
        for(j=1;j^m;++j) {
            c=geti();
            adde(e,f,c);adde(f,e,c);
            e+=2,f+=2;
        }
    memset(d,127,sizeof d);
    while(!heap.empty()) heap.pop();
    heap.push(make_pair(*d=0,0));
    E*it;
    while(!heap.empty()) {
        a=heap.top().second,c=heap.top().first; heap.pop();
        if(c^d[a]) continue;
        for(it=head[a];it;it=it->nxt)
            if(c+it->v<d[b=it->to]) heap.push(make_pair(d[b]=c+it->v,b));
    }
    printf("%d\n",d[T]);
    return 0;
}

2 1002

此题的推导比较麻烦,用基尔霍矩阵计算生成树个数,经过一系列推导可以得到$F(n) = 3 * F(n - 1) - F(n - 2) + 2$。
具体推导可见http://vfleaking.blog.163.com/blog/static/17480763420119685112649/

#include <cstdio>
int a[20],b[20],c[20],n;
#define ba 1000000
int main() {
    scanf("%d",&n);
    if(n<3) return puts(n<2?"1":"5"),0;
    register int i,la=1,lb=1,lc=1;
    *a=1,*b=5; n-=2;
    while(n--) {
        //c=3*b-a+2
        for(i=0;i<lb;++i) c[i]=b[i]*3;
        for(i=0;i<lb;++i) c[i+1]+=c[i]/ba,c[i]%=ba;
        for(lc=lb;c[lc];++lc); *c+=2;
        for(i=0;i<lc;++i) {
            c[i]-=a[i];
            if(c[i]<0) --c[i+1],c[i]+=ba;
        }
        while(!c[lc-1]) --lc;
        for(i=0;i<lb;++i)a[i]=b[i];la=lb;
        for(i=0;i<lc;++i)b[i]=c[i];lb=lc;
    }
    printf("%d",c[lc-1]);
    for(i=lc-2;~i;--i) printf("%06d",c[i]);
    return 0;
}

3 1003

此题比较简单,就是一个dp+最短路。

#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
inline int geti() {
    register int a; register char c;
    while(c=getchar(),c<'0');a=c-'0';
    while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return a;
}
int dp[102],c[102][102],vis[102],d[21];
struct E{int to,v;E*nxt;}CD[100*100+2],*cd=CD,*head[102];
inline void cmin(int&a,int b){b<a?a=b:1;}
#define pr pair<int,int>
priority_queue< pr, vector< pr >,greater < pr > >heap;
inline int dijstra(int sta,int t) {
    memset(d,127,sizeof d);
    while(!heap.empty()) heap.pop();
    heap.push(make_pair(*d=0,0));
    int s,dis; E*it;
    while(!heap.empty()) {
        s=heap.top().second,dis=heap.top().first; heap.pop();
        if(dis^d[s]) continue;
        for(it=head[s];it;it=it->nxt)
            if(!(sta&(1<<it->to))&&dis+it->v<d[it->to])
                heap.push(make_pair(d[it->to]=dis+it->v,it->to));
    }
    return (d[t]^0x7f7f7f7f)?d[t]:-1;
}
int main() {
    register int n=geti(),m=geti(),k=geti(),e=geti(),i,j,x;
    while(e--) {
        i=geti()-1,j=geti()-1,x=geti();
        cd->v=x,cd->to=j,cd->nxt=head[i],head[i]=cd++;
        cd->v=x,cd->to=i,cd->nxt=head[j],head[j]=cd++;
    }
    for(e=geti();e;--e) {
        x=geti()-1,i=geti(),j=geti();
        for(;i<=j;++i)vis[i]|=1<<x;
    }
    memset(c,-1,sizeof c);
    for(i=1;i<=n;++i) {
        x=0;
        for(j=i;j<=n;++j) {
            x|=vis[j];
            if((c[i][j]=dijstra(x,m-1))<0) break;
        }
    }
    dp[0]=0,dp[1]=c[1][1];
    for(i=2;i<=n;++i) {
        dp[i]=(~c[1][i])?(c[1][i]*i):0x7f7f7f7f;
        for(j=i;j;--j)
            if(~c[j][i]) cmin(dp[i],dp[j-1]+k+(i-j+1)*c[j][i]);
            else break;
    }
    printf("%d\n",dp[n]);
    return 0;
}

4 1004

这是一道群论的裸题,需要用到burnside定理得出公式$ans=\segma Cal(Changei) * |G|-1$。

#include <cstdio>
#include <cstring>
inline int geti() {
    register int a; register char c;
    while(c=getchar(),c<'0');a=c-'0';
    while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return a;
}
int dp[22][22][22],change[100][61],vis[61],vis_clock,d[61];
int sr,sb,sg,n,p;
#define inc(a,b) for((a)+=(b);(a)>=p;(a)-=p)
inline int Cal(int*a) {
    memset(dp,0,sizeof dp);
    register int s=0,i,j,k,t;
    ++vis_clock;
    for(i=1;i<=n;++i)
        if(vis[i]^vis_clock) {
            d[s]=0;
            for(j=i;vis[j]^vis_clock;j=a[j])
                vis[j]=vis_clock,++d[s];
            ++s;
        }
    dp[0][0][0]=1;
    for(--s;~s;--s)
        for(t=d[s],i=sr;~i;--i)
            for(j=sb;~j;--j)
                for(k=sg;~k;--k) {
                    if(i>=t) inc(dp[i][j][k],dp[i-t][j][k]);
                    if(j>=t) inc(dp[i][j][k],dp[i][j-t][k]);
                    if(k>=t) inc(dp[i][j][k],dp[i][j][k-t]);
                }
    return dp[sr][sb][sg];
}
int main() {
    sr=geti(),sb=geti(),sg=geti();
    register int m=geti(),i,j; p=geti();
    n=sr+sb+sg;
    for(i=0;i<m;++i) for(j=1;j<=n;++j) change[i][j]=geti();
    for(i=1;i<=n;++i) change[m][i]=i;
    ++m;
    int ans=0;
    for(i=0;i<m;++i)
        for(ans+=Cal(change[i]);ans>=p;ans-=p);
    for(i=m,j=p-2;j;j>>=1,i=i*i%p)if(j&1)ans=ans*i%p;
    printf("%d\n",ans);
    return 0;
}

5 1005

此题需要用到prufer序列,之后再结合组合数就好了。

#include <cstdio>
#define SIZE 169
#define ba 10000
const int p[SIZE] = {
    0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,
    79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,
    193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,
    313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,
    443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,
    587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,
    719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,
    859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997
};
inline int geti() {
    register int a; register char c,f=0;
    while(c=getchar(),c<'0')f|=c=='-';a=c-'0';
    while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return f?-a:a;
}
int e[SIZE],Ans[3000];
inline void Fac(const int &n,const bool&k) {
    register int i,j;
    for(i=1;i^SIZE;++i)
        for(j=p[i];j<=n;j*=p[i])
            k?(e[i]+=n/j):(e[i]-=n/j);
}
int main() {
    register int n=geti(),i,len=n-2,m=0,t;
    for(i=0;i<n;++i) {
        t=geti();
        if(!t||len<t-1) return puts("0"),0;
        if(t<0) {++m;continue;}--t;
        Fac(len,1); Fac(t,0); Fac(len-t,0);
        len-=t;
    }
    if(len) {
        for(i=1;(i^SIZE)&&1<m;++i)
            while(!(m%p[i])) m/=p[i],e[i]+=len;
    }
    Ans[1]=len=1;
    for(i=1;i^SIZE;++i)
        while(e[i]--) {
            for(t=1;t<=len;++t) Ans[t]*=p[i];
            for(t=1;t<=len;++t) if(Ans[t]>=ba) Ans[t+1]+=Ans[t]/ba,Ans[t]%=ba;
            while(Ans[len+1]) {
                if(Ans[len]>=ba) Ans[len+1]+=Ans[len]/ba,Ans[len]%=ba;
                ++len;
            }
        }
    for(printf("%d",Ans[len]),i=len-1;i;--i) printf("%04d",Ans[i]);
    return 0;
}

6 1006

此题请查看cdq的论文,此处为$O(n+m)$解法。

#include <cstdio>
#include <cstring>
inline int geti() {
    register int a; register char c;
    while(c=getchar(),c<'0');a=c-'0';
    while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return a;
}
#define N 10005
#define M 3000005
struct E{int to;E*nxt;}CD[M],*cd=CD,*head[N],*st[N];
inline void adde(int a,int b) {cd->to=b,cd->nxt=head[a],head[a]=cd++;}
inline void ins(int a,int b) {cd->to=b,cd->nxt=st[a],st[a]=cd++;}
int d[N],col[N],q[N],vis[N];
int main() {
#ifndef ONLINE_JUDGE
    freopen("1006.in","r",stdin);
    freopen("1006.out","w",stdout);
#endif
    register int n=geti(),m=geti(),i,j,mx,v; E*it;
    while(m--) adde(i=geti(),j=geti()),adde(j,i);
    mx=m=0;
    for(i=1;i<=n;++i) ins(0,i);
    while(m<n) {
        if(!st[mx]) {--mx; continue;}
        if(vis[st[mx]->to]) {st[mx]=st[mx]->nxt; continue;}
        v=st[mx]->to;
        vis[v]=1; q[m++]=v;
        st[mx]=st[mx]->nxt;
        for(it=head[v];it;it=it->nxt)
            if(!vis[j=it->to]) {
                (++d[j]>mx)?mx=d[j]:1;
                ins(d[j],j);
            }
    }
    memset(vis,0,sizeof vis);
    for(mx=0,i=0;i<n;++i) {
        v=q[i];
        for(it=head[v];it;it=it->nxt)
            vis[col[it->to]]=v;
        for(j=1;;++j)if(vis[j]^v)break;
        if((col[v]=j)>mx) mx=j;
    }
    printf("%d\n",mx);
    return 0;
}

7 1007

一道比较裸的凸包,网传可以用半平面交写,但我不会。

#include <cstdio>
#include <algorithm>
char inb[1<<16],*ins=inb,*ine=inb;
#define getc() ((ins>=ine&&(ine=(ins=inb)+fread(inb,1,1<<16,stdin),ins>=ine))?EOF:*ins++)
inline int geti() {
    register int a; register char c,f=0;
    while(c=getc(),c<'0')f|=c=='-';a=c-'0';
    while(c=getc(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return f?-a:a;
}
#define N 50005
struct D{int a,b,id;}p[N],sta[N];
inline bool operator < (const D&x,const D&y){return (x.a^y.a)?x.a<y.a:x.b<y.b;}
bool ans[N]; char oub[N<<3],ous[10],*oue=oub;
inline void outi(int x) {
    register char tp=0;
    while(x)ous[++tp]=x%10,x/=10;
    for(;tp;--tp)*oue++=ous[tp]+'0';
    *oue++=' ';
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("1007.in","r",stdin);
    freopen("1007.out","w",stdout);
#endif
    register int n=geti(),i,tp;
    register D x;
    for(i=1;i<=n;++i){
        p[i].a=geti();
        p[i].b=geti();
        p[i].id=i;
    }
    std::sort(p+1,p+n+1);
    sta[tp=0].a=0x7f7f7f7f;
    for(i=1;i<=n;++i) {
        for(x=p[i];tp;) {
            if(sta[tp].a==x.a) --tp;
            if(1<tp&&(sta[tp-1].b-x.b+0LL)*(sta[tp].a-sta[tp-1].a+0LL)<=(sta[tp-1].b-sta[tp].b+0LL)*(x.a-sta[tp-1].a+0LL))--tp;
            else break;
        }
        sta[++tp]=x;
    }
    for(i=1;i<=tp;++i)ans[sta[i].id]=1;
    for(i=1;i<=n;++i)if(ans[i])outi(i);
    fwrite(oub,1,oue-oub,stdout);
    return 0;
}

8 1008

此题比较简单,用总数减去不可能越狱的情况数就是答案。 不可能的情况有$m*(m-1)n-1$,这样就可以得到答案了。

#include <cstdio>
const long long mo=100003;
inline long long pow(long long b,long long n) {
    register long long r=1LL;
    for(;n;n>>=1,b=b*b%mo) if(n&1) r=r*b%mo;
    return r;
}
int main() {
    long long n,m,ans;
    scanf("%lld%lld",&m,&n);
    m%=mo;
    ans=pow(m,n);
    ans-=m*pow(m-1,n-1);
    ans%=mo;
    if(ans<0) ans+=mo;
    printf("%lld\n",ans);
    return 0;
}

9 1009

此题是一道比较简单的题,用kmp求出下一步的转移,之后矩阵快速幂就好了。

#include <cstdio>
int n,m,mo,a[25][25],b[25][25],c[25][25],nxt[25];
char s[25];
#define inc(a,b) for(a+=b;a>=mo;a-=mo)
inline void mul(int (&x)[25][25],int (&y)[25][25]) {
    register int i,j,k;
    for(i=0;i<m;++i)
        for(j=0;j<m;++j) {
            c[i][j]=0;
            for(k=0;k<m;++k)
                c[i][j]=(c[i][j]+x[i][k]*y[k][j])%mo;
        }
    for(i=0;i<m;++i)
        for(j=0;j<m;++j)
            x[i][j]=c[i][j];
}
int main() {
    register int i,j=0,t;
    for(scanf("%d%d%d%s",&n,&m,&mo,s+1),i=2;i<=m;++i) {
        while(j&&(s[j+1]^s[i]))j=nxt[j];
        nxt[i]=(s[i]==s[j+1])?(++j):j;
    }
    for(i=0;i<m;++i)
        for(j=0;j<10;++j) {
            for(t=i;t&&(s[t+1]^j+'0');t=nxt[t]);
            if(((s[t+1]==j+'0')?++t:t)^m)++b[t][i]<mo?1:b[t][i]=0;
        }
    for(i=0;i<m;++i)a[i][i]=1;
    for(;n;n>>=1,mul(b,b))if(n&1)mul(a,b);
    for(t=0,i=0;i<m;++i)inc(t,a[i][0]);
    return printf("%d\n",t),0;
}

10 1010

此题是一道斜率优化的裸题,比较简单。

#include <cstdio>
inline int geti() {
    register int a; register char c,f=0;
    while(c=getchar(),c<'0')f|=c=='-';a=c-'0';
    while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return f?-a:a;
}
#define N 50005
long long g[N],dp[N],C; int q[N];
inline long long S(int i,int j){return (g[i]-g[j])<<1;}
inline long long G(int i,int j){return dp[i]-dp[j]+(g[i]-g[j])*(g[i]+g[j]+(C<<1));}
int main() {
    register int n=geti(),i,j,l=1,r=1;
    C=geti()+1;
    register long long s=0;
    q[1]=0;
    for(i=1;i<=n;++i) {
        s+=geti(); g[i]=s+i;
        while(l<r&&G(q[l+1],q[l])<=S(q[l+1],q[l])*g[i])++l;
        j=q[l];
        dp[i]=dp[j]+(g[i]-g[j]-C)*(g[i]-g[j]-C);
        while(l<r&&G(i,q[r])*S(q[r],q[r-1])<=G(q[r],q[r-1])*S(i,q[r]))--r;
        q[++r]=i;
    }
    printf("%lld\n",dp[n]);
    return 0;
}

11 1011

此题太神了,用5%的误差来优化时间。 正解t应取2000左右,不过取20也可以过。

#include <cmath>
#include <cstdio>
inline int geti() {
    register int a; register char c;
    while(c=getchar(),c<'0');a=c-'0';
    while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return a;
}
#define N 100002
#define t 20
int m[N]; double f[N];
int main() {
    register int i,j,l,r,n=geti();
    double a; scanf("%lf",&a);
    for(i=1;i<=n;++i)m[i]=geti(),f[i]=0.0;
    for(i=1;i<=t;++i)
        for(j=1,r=floor(a*i);j<=r;++j)
            f[i]+=1.0*m[i]*m[j]/(i-j);
    for(i=t+1;i<=n;++i) {
        l=floor(a*(i-t)),r=floor(a*i);
        for(j=l+1;j<=r;++j) f[i]+=1.0*m[i]*m[j]/(i-j);
        f[i]+=m[i]*f[i-t]/m[i-t]*(i-t-1.0*l/2)/(i-1.0*l/2);
    }
    for(i=1;i<=n;++i) printf("%.6lf\n",f[i]);
    return 0;
}

12 1012

此题一眼看是一道数据结构,不过仔细想想可以用单调栈搞。

#include <cstdio>
#include <algorithm>
inline int geti() {
    register int a; register char c;
    while(c=getchar(),c<'0');a=c-'0';
    while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return a;
}
int q[200001],v[200001];
int main() {
    register int m=geti(),d=geti(),t=0,x,len=0,tp=0;
    register char c;
    while(m--) {
        while(c=getchar(),c<'A'); x=geti();
        if(c^'A')
printf("%d\n",t=v[*std::lower_bound(q+1,q+tp+1,len-x+1)]);
        else {
            x=(x+t)%d; v[++len]=x;
            while(tp&&v[q[tp]]<=x)--tp;
            q[++tp]=len;
        }
    }
    return 0;
}

13 1013

此题可以根据距离建立方程,之后guass消元就好了。

#include <cmath>
#include <cstdio>
#include <algorithm>
int n; double a[11][11],p[11];
inline void guass() {
    register int i,j,k,id; register double mx,t;
    for(i=0;i<n;++i) {
        mx=-1;
        for(j=i;j<n;++j) if(mx<fabs(a[j][i]))mx=a[id=j][i];
        if(i^id)for(j=i;j<=n;++j)std::swap(a[i][j],a[id][j]);
        t=a[i][i];
        for(j=i+1;j<=n;++j) a[i][j]/=t;
        for(j=0;j<n;++j)
            if(i^j) for(t=a[j][i],k=1;k<=n;++k)
                        a[j][k]-=t*a[i][k];
    }
}
int main() {
    register int i,j;
    double t;
    scanf("%d",&n);
    for(i=0;i<n;++i)scanf("%lf",p+i);
    for(i=0;i<n;++i)
    for(j=0;j<n;++j) {
        scanf("%lf",&t);
        a[i][j]=2*(t-p[j]);
        a[i][n]+=t*t-p[j]*p[j];
    }
    guass();
    for(i=0;i<n;++i)printf("%.3lf%c",a[i][n],"\n "[i+1<n]);
    return 0;
}

14 1014

此题用二分加哈希计算LCQ,之后用spaly维护哈希值还是比较简单的。

#include <cstdio>
#include <cstring>
inline int geti() {
    register int a; register char c;
    while(c=getchar(),c<'0');a=c-'0';
    while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return a;
}
#define ui unsigned int
#define N 100050
#define ba 257
ui p[N];
struct node {
    ui ha; int siz; char c;
    node *fa,*ch[2];
}CD[N],*cd=CD,*root,*nil;
inline void maintain(node*(&u)) {
    if(u==nil) return;
    u->siz=u->ch[0]->siz+u->ch[1]->siz+1;
    u->ha=u->ch[0]->ha+u->c*p[u->ch[0]->siz]+u->ch[1]->ha*p[u->ch[0]->siz+1];
}
inline void rot(node*(&u)) {
    node *f=u->fa,*ff=f->fa;
    int d=u==f->ch[1];
    if((f->ch[d]=u->ch[d^1])!=nil) f->ch[d]->fa=f;
    f->fa=u,u->ch[d^1]=f;
    if((u->fa=ff)!=nil) ff->ch[f==ff->ch[1]]=u;
    maintain(f);maintain(u);
}
inline void splay(node*(&u),node*(&target)) {
    while(u->fa!=target){
        if(u->fa->fa==target){rot(u);break;}
        if((u==u->fa->ch[1])^(u->fa==u->fa->fa->ch[1]))rot(u);
        else rot(u->fa);rot(u);
    }if(target==nil)root=u;
}
inline node*kth(int k){
    node*u=root;
    while(k&&u!=nil){
        if(u->ch[0]->siz>=k)u=u->ch[0];
        else if(u->ch[0]->siz+1==k) return u;
        else k-=u->ch[0]->siz+1,u=u->ch[1];
    }return u;
}
inline void ins(int k,char ch) {
    node *l=kth(k); cd->c=ch;
    cd->ch[0]=nil,cd->ch[1]=l->ch[1];
    cd->fa=l,cd->ch[1]->fa=cd;
    l->ch[1]=cd; maintain(cd);
    while(l!=nil) {maintain(l);l=l->fa;}
    ++cd;
}
inline void upd(int k,char ch){
    node*u=kth(k);u->c=ch;
    while(u!=nil){maintain(u);u=u->fa;}
}
inline ui quy(int l,int r){
    node*lu=kth(l-1),*ru=kth(r+1);
    splay(lu,nil);splay(ru,lu);
    return ru->ch[0]->ha;
}
char initstring[N];
node*build(int l,int r){
    if(l>r)return nil;
    int m=l+r>>1;node*u=cd++;
    u->c=initstring[m];
    if((u->ch[0]=build(l,m-1))!=nil)u->ch[0]->fa=u;
    if((u->ch[1]=build(m+1,r))!=nil)u->ch[1]->fa=u;
    maintain(u);return u;
}
int main() {
    initstring[1]='~';
    scanf("%s",initstring+2);
    register int cl=strlen(initstring+2),i,j,mi,l,r,an,m;
    for(*p=i=1;i^N;++i)p[i]=p[i-1]*ba;
    initstring[cl+2]='!';
    cd->fa=cd->ch[0]=cd->ch[1]=cd;
    cd->ha=cd->siz=cd->c=0;nil=cd++;
    root=build(1,cl+2);root->fa=nil;
    register char ch;
    for(m=geti();m;--m){
        while(ch=getchar(),ch<'A');
        if(ch=='Q'){
            i=geti()+1,j=geti()+1;
            if(kth(i)->c!=kth(j)->c){puts("0");continue;}
            for(an=l=1,r=cl-(i<j?j:i)+2;l<=r;){
                mi=l+r>>1;
                if(quy(i,i+mi-1)==quy(j,j+mi-1))l=(an=mi)+1;
                else r=mi-1;
            }printf("%d\n",an);
        }else{
            j=ch=='R';cl+=j^1;
            i=geti()+1;while(ch=getchar(),ch<'a');
            j?upd(i,ch):ins(i,ch);
        }
    }return 0;

15 1015

此题用并查集离线搞一下就好了。

#include <cstdio>
inline int geti() {
    register int a; register char c;
    while(c=getchar(),c<'0');a=c-'0';
    while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return a;
}
#define N 400005
int f[N],blo,d[N],ANS[N];
bool mark[N],can[N];
inline int gf(int u){
    register int en;
    for(en=u;f[en]^en;en=f[en]);
    for(register int t;u^en;t=f[u],f[u]=en,u=t);
    return en;
}

struct E{int to;E*nt;}CD[N],*cd=CD,*hd[N];
#define adde(a,b) (cd->to=b,cd->nt=hd[a],hd[a]=cd++)
inline void ins(int u) {
    register int v;
    for(register E*it=hd[u];it;it=it->nt)
        if(can[it->to]&&(gf(u)^(v=gf(it->to))))
            --blo,f[v]=gf(u);
}
int main() {
    register int n=geti(),m=geti(),i,a,b;
    for(i=0;i<n;++i)f[i]=i;
    while(m--){a=geti(),b=geti();adde(a,b),adde(b,a);}
    register int*ans,*t=d;
    for(i=0,m=geti();i<m;++i)mark[*t++=geti()]=1;
    for(i=0;i<n;++i)
        if(!mark[i])++blo,can[i]=1,ins(i);
    ans=ANS+m;
    *ans--=blo;
    for(i=m;i;--i) {
        can[a=*--t]=1;
        ++blo;ins(a);
        *ans--=blo;
    }
    for(i=0;i<=m;++i)printf("%d\n",*++ans);
    return 0;
}

16 1016

此题需要用到关于最小生成树的一些基本性质哦。
由Kruskal算法不难得出对于一个图的不同最小生成树,其同一边权的边数相同。
这样我们就可以得出此题解法了。

#include <cstdio>
#include <cstring>
#include <algorithm>
inline int geti() {
    register int a; register char c;
    while(c=getchar(),c<'0');a=c-'0';
    while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return a;
}
#define mo 31011
struct E{int u,v,w;}e[1002];
inline bool operator < (const E&a,const E&b){return a.w<b.w;}
int L[1002],R[1002],C[1002],f[102],sum,x;
inline int gf(int u) {
    while(f[u]^u)u=f[u];
    return u;
}
void dfs(int cur,int t) {
    if(R[x]<cur){sum+=t==C[x];return;}
    int p=gf(e[cur].u),q=gf(e[cur].v);
    if(p^q){
        f[p]=q;
        dfs(cur+1,t+1);
        f[p]=p,f[q]=q;
    }
    dfs(cur+1,t);
}
int main() {
    register int i,cnt=0,cedge=0,p,q;
    register int n=geti(),m=geti(),ans=1;
    for(i=0;i<m;++i)e[i].u=geti(),e[i].v=geti(),e[i].w=geti();
    std::sort(e,e+m);
    for(i=1;i<=n;++i)f[i]=i;
    for(i=0;i<m;++i) {
        if(e[i-1].w<e[i].w)R[cnt]=i-1,R[++cnt]=i;
        if((p=gf(e[i].u))^(q=gf(e[i].v)))
            f[p]=q,++C[cnt],++cedge;
    }R[cnt]=m;
    if(cedge<n-1)return puts("0"),0;
    for(i=1;i<=n;++i)f[i]=i;
    for(x=1;x<=cnt;++x) {
        sum=0; dfs(L[x],0);
        ans=ans*sum%mo;
        for(i=L[x];i<=R[x];++i)
            if((p=gf(e[i].u))^(q=gf(e[i].v)))f[p]=q;
    }
    return printf("%d\n",ans),0;
}

17 1018

此题用线段树维护联通性,每个联通只考虑用区间内的道路而不用外面的,之后一个个考虑就好了。
此题代码容易出错,要仔细些。

#include <cstdio>
#include <cstring>
inline int geti() {
    register int a; register char c;
    while(c=getchar(),c<'0');a=c-'0';
    while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
    return a;
}
#define ls u<<1
#define rs u<<1|1
#define MID int mid=l+r>>1
struct D{bool a0,a1,b0,b1,c0,c1;}C[200005];
bool edge[3][100005]; char ts[10];
void build(int u,int l,int r) {
    if(l>=r) {
        C[u].b0=C[u].b1=true;
        return;
    }
    MID;
    build(ls,l,mid);build(rs,mid+1,r);
}
D pluse(const D&a,const D&b,const bool&x,const bool&y) {
    D r;
    r.a0=a.a0||(a.b0&&a.b1&&x&&y&&b.a0);
    r.a1=b.a1||(b.b0&&b.b1&&x&&y&&a.a1);
    r.b0=(a.b0&&x&&b.b0)||(a.c0&&y&&b.c1);
    r.b1=(a.b1&&y&&b.b1)||(a.c1&&x&&b.c0);
    r.c0=(x&&a.b0&&b.c0)||(y&&a.c0&&b.b1);
    r.c1=(y&&a.b1&&b.c1)||(x&&a.c1&&b.b0);
    return r;
}
void upd(int u,int l,int r,int p) {
    if(l>=r) {
        C[u].b0=C[u].b1=true;
        C[u].a0=C[u].a1=C[u].c0=C[u].c1=edge[2][p];
        return;
    }
    MID;
    if(p<=mid)upd(ls,l,mid,p);else upd(rs,mid+1,r,p);
    C[u]=pluse(C[ls],C[rs],edge[0][mid],edge[1][mid]);
}
D quy(int u,int l,int r,int x,int y) {
    if(l>=x&&r<=y)return C[u];
    MID;
    if(y<=mid)return quy(ls,l,mid,x,y);
    if(x>mid)return quy(rs,mid+1,r,x,y);
    return pluse(quy(ls,l,mid,x,mid),quy(rs,mid+1,r,mid+1,y),edge[0][mid],edge[1][mid]);
}
int main() {
    register int c=geti(),r1,c1,r2,c2;
    build(1,1,c);
    register D t1,t2,t3;
    register bool ok;
    while(scanf("%s",ts)^EOF) {
        if(*ts=='E')break;
        r1=geti()-1,c1=geti(),r2=geti()-1,c2=geti();
        if(c2<c1)r1^=r2^=r1^=r2,c1^=c2^=c1^=c2;
        if(*ts=='O') {
            if(r1>r2)r1^=r2^=r1^=r2,c1^=c2^=c1^=c2;
            if(r1<r2)edge[2][c1]=1;
            else edge[r1][c1]=1;
            upd(1,1,c,c1);
        } else if(*ts=='C') {
            if(r1>r2)r1^=r2^=r1^=r2,c1^=c2^=c1^=c2;
            if(r1<r2)edge[2][c1]=0;
            else edge[r1][c1]=0;
            upd(1,1,c,c1);
        } else {
            t1=quy(1,1,c,1,c1);
            t2=quy(1,1,c,c1,c2);
            t3=quy(1,1,c,c2,c);
            if(r1&&r2) {
                ok=t2.b1||(t1.a1&&t2.c0)||(t2.c1&&t3.a0);
                ok|=t1.a1&&t2.b0&&t3.a0;
            }else if(!r1^r2) {
                ok=t2.b0||(t1.a1&&t2.c1)||(t2.c0&&t3.a0);
                ok|=t1.a1&&t2.b1&&t3.a0;
            }else if(r1) {
                ok=t2.c1||(t1.a1&&t2.b0)||(t2.b1&&t3.a0);
                ok|=t1.a1&&t2.c0&&t3.a0;
            }else {
                ok=t2.c0||(t1.a1&&t2.b1)||(t2.b0&&t3.a0);
                ok|=t1.a1&&t2.c1&&t3.a0;
            }
            puts(ok?"Y":"N");
        }
    }
    return 0;
}

18 1066

网络流裸题,直接拆点就好了。

#include <cstdio>
#include <cstring>
inline int rd() {
    register char c;
    while(c=getchar(),c<'0');
    return c-'0';
}
char mp[22][22];
#define M 100000
int to[M],nt[M],C[M],hd[810],te;
#define adde(a,b,c) (to[te]=b,nt[te]=hd[a],C[te]=c,hd[a]=te++)
int d[810],dt[810],la[810],S,T,r,c,d2,hx[810],hy[810];
inline bool rid(int dx,int dy){return dx*dx+dy*dy<=d2;}
int dfs(int u,int flow) {
    if(u==T||!flow) return flow;
    int r=0,t;
    for(int&i=la[u];~i;i=nt[i])
        if(d[u]==d[to[i]]+1&&C[i]>0) {
            t=dfs(to[i],flow<C[i]?flow:C[i]);
            r+=t,flow-=t;
            C[i]-=t,C[i^1]+=t;
            if(!flow||d[S]>T+1)return r;
        }
    la[u]=hd[u];
    if(!(--dt[d[u]])) d[S]=T+2;
    ++dt[++d[u]]; return r;
}
inline int SAP() {
    register int *l=dt,*r=dt,i;
    *r++=T; d[T]=1;
    while(l<r) {
        for(i=hd[*l];~i;i=nt[i])
            if(!d[to[i]]) d[*r++=to[i]]=d[*l]+1;
        ++l;
    }
    memset(dt,0,sizeof dt);
    for(i=S;i<=T;++i)++dt[d[i]],la[i]=hd[i];
    i=0;
    while(d[S]<T+2)i+=dfs(S,0x7f7f7f7f);
    return i;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("1066.in","r",stdin);
#endif
    int d;
    scanf("%d%d%d",&r,&c,&d);
    d2=d*d;
    memset(hd,-1,sizeof hd);
    register int i,j,k,cnt=0,tp=0;
    for(i=0;i<r;++i)
        for(j=0;j<c;++j)
            if(k=rd()) {
                ++tp; hx[tp]=i,hy[tp]=j;
                adde(tp,tp+1,k);adde(tp+1,tp,0);
                ++tp;
            }
    for(i=0;i<r;++i) {
        scanf("%s",mp[i]);
        for(j=0;j<c;++j)cnt+=mp[i][j]=='L';
    }
    S=0,T=tp+1;
    for(i=1;i<tp;i+=2) {
        for(j=i+2;j<tp;j+=2)
            if(rid(hx[i]-hx[j],hy[i]-hy[j])) {
                adde(i+1,j,cnt),adde(j,i+1,0);
                adde(j+1,i,cnt),adde(i,j+1,0);
            }
        if(mp[hx[i]][hy[i]]=='L')adde(S,i,1),adde(i,S,0);
        if(hx[i]<d||hy[i]<d||r-hx[i]<=d||c-hy[i]<=d)adde(i+1,T,cnt),adde(T,i+1,0);
    }
    printf("%d\n",cnt-SAP());
    return 0;
}

19 2756

此题中我们可以很明显的发现最终形成的数具有单调性,所以可以二分。
之后用网络流进行check。
注意棋盘为奇数是要特判。

#include <cstdio>
#include <cstring>
char inb[1<<16],*ins=inb,*ine=inb;
#define getc() ((ins==ine&&(ine=(ins=inb)+fread(inb,1,1<<16,stdin),ins==ine))?EOF:*ins++)
inline int geti() {
    register int a; register char c,f=0;
    while(c=getc(),c<'0'||'9'<c)f|=c=='-';a=c-'0';
    while(c=getc(),!(c<'0'||'9'<c))a=(a<<3)+(a<<1)+c-'0';
    return f?-a:a;
}
#define N 1610
#define M 20000
const long long inf=1LL<<50;
int d[N],dt[N],S,T,la[N];
int to[M],nt[M],hd[N],n,m,te;
long long C[M];
int mp[42][42],idx[42][42];
inline void adde(int a,int b,long long c) {
    to[te]=b;nt[te]=hd[a];C[te]=c;hd[a]=te++;
    to[te]=a;nt[te]=hd[b];C[te]=0;hd[b]=te++;
}
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
long long dfs(int u,long long flow) {
    if(u==T||!flow)return flow;
    long long r=0,t;
    for(int&i=la[u];~i;i=nt[i])
        if(d[u]==d[to[i]]+1&&C[i]>0) {
            t=dfs(to[i],flow<C[i]?flow:C[i]);
            r+=t,flow-=t;
            C[i]-=t,C[i^1]+=t;
            if(d[S]>T+1||!flow)return r;
        }
    la[u]=hd[u];
    if(!(--dt[d[u]]))d[S]=T+2;
    ++dt[++d[u]];return r;
}
inline bool check(long long x) {
    memset(hd,-1,sizeof hd);
    int i,j,k,_i,_j; te=0;
    long long t=0,st=0;
    for(i=1;i<=n;++i)
        for(j=1;j<=m;++j)
            if((i+j)&1) {
                adde(S,idx[i][j],x-mp[i][j]);
                st+=x-mp[i][j];
                for(k=0;k^4;++k) {
                    _i=i+dx[k],_j=j+dy[k];
                    if(_i<1||_j<1||_i>n||_j>m)continue;
                    adde(idx[i][j],idx[_i][_j],inf);
                }
            }else adde(idx[i][j],T,x-mp[i][j]);
    i=j=0;dt[j++]=T;
    memset(d,0,sizeof d);
    d[T]=1;
    while(i<j) {
        k=dt[i++];
        for(_i=hd[k];~_i;_i=nt[_i])
            if(!d[to[_i]])d[dt[j++]=to[_i]]=d[k]+1;
    }
    memset(dt,0,sizeof dt);
    for(i=S;i<=T;++i)++dt[d[i]],la[i]=hd[i];
    while(d[S]<T+2)t+=dfs(S,inf);
    return st==t;
}
#define getskip(a) (a*n*m-s0-s1)>>1
int main() {
    int __=geti(),i,j,id;
    long long s0,s1,mv,l,r,mi,an;
    while(__--) {
        n=geti(),m=geti();
        s0=s1=0LL;mv=-inf;
        for(id=0,i=1;i<=n;++i)
            for(j=1;j<=m;++j) {
                if((mp[i][j]=geti())>mv)mv=mp[i][j];
                if((i+j)&1)s1+=mp[i][j];
                else s0+=mp[i][j];
                idx[i][j]=++id;
            }
        S=0,T=++id;
        if(n*m&1) {
            l=s0-s1;
            if(l>=mv&&check(l))printf("%lld\n",getskip(l));
            else puts("-1");
        }else {
            if(s0^s1){puts("-1");continue;}
            for(l=mv,r=inf;l<=r;) {
                mi=l+r>>1;
                if(check(mi))r=(an=mi)-1;
                else l=mi+1;
            }
            printf("%lld\n",getskip(an));
        }
    }
    return 0;
}
posted @ 2016-12-08 22:21  cycleke  阅读(197)  评论(0)    收藏  举报