2017-10-18离线赛

来源:互联网 发布:2017淘宝售假申诉成功 编辑:程序博客网 时间:2024/06/07 21:53

大体状况

220/300
正常一些了。
前十都是210~230= =A12两题,
最后一题的DP有一点点Bug然后没了10分。。

T1 snum

分析

这种按位相加的东西显然可以拆数字来预处理。
取一个Base,预处理出Base内的S数值。
对于一个大数,拆分成若干个Base以内的数,
然后直接算出来。
因为R109,有一种想法是分块打表,
即每隔106取一个答案,然后前缀和处理。
复杂度约为O(25106)
还有简单一些的方法。
注意到S(x2)918
S(x2)12
直接DFS得出所有满足条件的S数,
然后判断是否在范围内即可,
复杂度为O(9i=2Stirling1(12,i))左右。
其实打表的话会发现最后在范围内只有7116个答案。
那么换种方法打表,即打表得出所有S数,然后二分查找得到答案。
复杂度为O(2log27116),对于极多组数据可有效求解。

代码

打的表就删掉了= =

#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define chkmin(a,b) a=min(a,b)#define chkmax(a,b) a=max(a,b)#define LL long longvoid Rd(int &res){    char c;res=0;    while((c=getchar())<48);    do res=(res<<3)+(res<<1)+(c^48);    while((c=getchar())>47);}#define Base 100000int St[Base+44];int S1(LL x){    int Res=0;    while(x)        Res+=x%10,x/=10;    return Res;}int S2(LL x){    int Res=0;    while(x)        Res+=St[x%Base],x/=Base;    return Res;}int Sum,L,R;struct P80{    void Solve(){        int Ans=0;        REP(i,L,R+1){            int p=S2(i),t=S2(1ll*i*i);            if(p*p==t)Ans++;        }        printf("%d\n",Ans);    }}P80;int List[]={存放你隔10^6打一个答案的表};#define LBs 1000000struct P100{    void Solve(){        int Ans=List[R/LBs];        REP(i,R/LBs*LBs+1,R+1){            int p=S2(i),t=S2(1ll*i*i);            if(p*p==t)Ans++;        }        L--;        if(L){            Ans-=List[L/LBs];            REP(i,L/LBs*LBs+1,L+1){                int p=S2(i),t=S2(1ll*i*i);                if(p*p==t)Ans--;            }        }        printf("%d\n",Ans);    }}P100;int main(){    Rd(L),Rd(R);    REP(i,1,Base+1) St[i]=S1(i);    if(R<=100000)P80.Solve();    else P100.Solve();    return 0;}

T2 dining

分析

看这个数据范围就可以得出DP状态定义。
即定义DPi,j,k为到i,
i后已给菜的状态压缩为j,
最后一个给的人是i+k8
然后这个DP看起来状态很多跑得很慢但是有很多是无用的,
因此速度还算不错。
就是转移起来有点麻烦,
需要判断可行性(不过不影响复杂度)。

代码

比赛中从19:30调到21:00才弄好,花费时间有点久了。

#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define chkmin(a,b) a=min(a,b)#define chkmax(a,b) a=max(a,b)#define LL long longvoid Rd(int &res){    char c;res=0;    while((c=getchar())<48);    do res=(res<<3)+(res<<1)+(c^48);    while((c=getchar())>47);}#define M 1004int C,n,T[M],B[M];int Cost(int t1,int t2){    if(t1==M)return 0;    else return (t1|t2)-(t1&t2);}#define INF 0x3f3f3f3fstruct P30{    bool Vis[M];    int Ans,Bst[M],Use[M];    bool Check(){        REP(i,1,n+1) if(!Vis[i])            REP(j,i+B[i],n+1)if(Vis[j])return 0;        return 1;    }    void DFS(int x,int t,int Now){        if(!Check())return;        if(x==n){            if(Ans>Now){                Ans=Now;                REP(i,0,n)                    Bst[i]=Use[i];            }            return;        }        REP(i,1,n+1) if(!Vis[i]){            Vis[i]=1,Use[x]=i;            DFS(x+1,T[i],Now+Cost(t,T[i]));            Vis[i]=0;        }    }    void Solve(){        Ans=INF;        DFS(0,M,0);        printf("%d\n",Ans);//      REP(i,0,n)cerr<<Bst[i]<<' ';cerr<<endl;    }}P30;struct P100{    #define N 264    int DP[M][N][18];    #define INF 0x3f3f3f3f    int Bas[14];    void Solve(){        memset(DP,63,sizeof(DP));        REP(k,1,14)Bas[k]=(1<<k)-1;        int Val;        T[0]=M,B[0]=1;        DP[0][1][8]=0;        REP(i,0,n+1) REP(j,0,1<<B[i])                REP(k,0,B[i]+8) if( (Val=DP[i][j][k]) !=INF ){                    bool Flag=0;                    REP(q,9,B[i]+8)if(i+q-8<=n && !(j&(1<<q-8))){                        if(j>>q-8+B[i+q-8]){Flag=1;break;}                    }                    if(Flag)continue;//                  cerr<<i<<","<<j<<","<<k<<":"<<Val<<endl;                    REP(q,1,8)                        if((j&Bas[q])==Bas[q])                            chkmin(DP[i+q][j>>q][k-q],Val);                        else break;                    REP(q,8,B[i]+8) if(i+q-8<=n && !(j&(1<<q-8)))                        chkmin(DP[i][j|(1<<q-8)][q],Val+Cost(T[i+k-8],T[i+q-8]));                }        int Ans=INF;        REP(i,0,8)chkmin(Ans,DP[n+1][0][i]);        printf("%d\n",Ans);    }}P100;int main(){    Rd(C);    while(C--){        Rd(n);        REP(i,1,n+1)Rd(T[i]),Rd(B[i]),B[i]++;//      if(n<=20)P30.Solve();//      else        P100.Solve();    }    return 0;}

T3 color

分析

P10

暴力只给10分= =

P30

第3、4组中没有对简单路径的长度作限制。
因此可以简单地树形DP写掉

P100

这种有关路径长度的问题一般可以考虑点分治。
求出重心后,考虑按顺序加入每一棵子树。
那么这棵子树最后的颜色就是当前扫描到的这条边。
为了方便操作(不写树套树以及减少复杂度),
在开始时令颜色相同的边加入时相连。
维护两棵主席树。
然后记录上一种颜色,
如果当前颜色与上一种颜色不同则合并两棵主席树,然后弄一棵新的。
然后就是对每个点查询可用的最大答案来更新。

代码

#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define chkmin(a,b) a=min(a,b)#define chkmax(a,b) a=max(a,b)#define LL long longvoid Rd(int &res){    char c;res=0;    while((c=getchar())<48);    do res=(res<<3)+(res<<1)+(c^48);    while((c=getchar())>47);}#define M 200004int n,m,L,R;int Next[M<<1],V[M<<1],C[M<<1],Head[M],tot;void Add_Edge(int u,int v,int c){    Next[++tot]=Head[u],V[Head[u]=tot]=v,C[tot]=c;}#define LREP(i,A) for(int i=Head[A];i;i=Next[i])int Val[M];bool Mark[M];int Dis[M],Num;int Sz[M];int RT,Rts;int Len[M],Sum[M],Cnt;#define INF 2000000044void DFS(int A,int f,int d,int lc){    int B;    Len[Cnt]=d,Sum[Cnt++]=Dis[A];    Sz[A]=1;    LREP(i,A)if((B=V[i])!=f && !Mark[B])        Dis[B]=Dis[A]+(lc!=C[i])*Val[C[i]],DFS(B,A,d+1,C[i]),Sz[A]+=Sz[B];}void GetRT(int A,int f){    int B,Mxf=0;    Sz[A]=1;    LREP(i,A)if((B=V[i])!=f && !Mark[B]){        GetRT(B,A);        Sz[A]+=Sz[B];        chkmax(Mxf,Sz[B]);    }    chkmax(Mxf,Num-Sz[A]);    if(Mxf<Rts)Rts=Mxf,RT=A;}int Ans;int Lp[M*20],Rp[M*20],Mx[M*20],trp;#define lson l,mid,Lp[p]#define rson mid+1,r,Rp[p]void Up(int p){    Mx[p]=max(Mx[Lp[p]],Mx[Rp[p]]);}void Insert(int l,int r,int &p,int old,int a,int t){    p=++trp;    Mx[p]=max(Mx[old],t);    if(l==r)return;    int mid=l+r>>1;    if(a<=mid)Rp[p]=Rp[old],Insert(lson,Lp[old],a,t);    else Lp[p]=Lp[old],Insert(rson,Rp[old],a,t);}int Query(int l,int r,int p,int a,int b){    if(!p || l>b || r<a)return -INF;    if(a<=l&&r<=b)return Mx[p];    int mid=l+r>>1;    return max(Query(lson,a,b),Query(rson,a,b));}int Merge(int l,int r,int p,int q){    if(!p || !q)return p|q;    if(l==r){        chkmax(Mx[p],Mx[q]);        return p;    }    int mid=l+r>>1;     Lp[p]=Merge(lson,Lp[q]);    Rp[p]=Merge(rson,Rp[q]);    Up(p);    return p;}void Solve(int Pos,int TSz){    if(TSz<=L)return;    Rts=INF;    Num=TSz;    GetRT(Pos,0);    Mark[RT]=1;    trp=0;    int A,lastC=-1,Rtx=0,Rty=0;    LREP(i,RT)if(!Mark[A=V[i]]){        Dis[A]=Val[C[i]];        Cnt=0;        DFS(A,RT,1,C[i]);        if(lastC!=C[i])Rtx=Merge(1,Rts,Rtx,Rty),Rty=0;        if(Rtx){            REP(j,0,Cnt){                int d=Len[j],s=Sum[j];                if(L<=d && d<=R)chkmax(Ans,s);                chkmax(Ans,Query(1,Rts,Rtx,L-d,R-d)+s);             }        }        if(Rty){            REP(j,0,Cnt){                int d=Len[j],s=Sum[j];                if(L<=d && d<=R)chkmax(Ans,s);                chkmax(Ans,Query(1,Rts,Rty,L-d,R-d)+s-Val[C[i]]);             }        }        REP(j,0,Cnt) Insert(1,Rts,Rty,Rty,Len[j],Sum[j]);        lastC=C[i];    }    LREP(i,RT) if(!Mark[A=V[i]])        Solve(A,Sz[A]);}struct Edge{int u,v;};vector<Edge>E[M];int main(){    Rd(n),Rd(m),Rd(L),Rd(R);    REP(i,1,m+1)scanf("%d",&Val[i]);    REP(i,1,n){        int u,v,c;        Rd(u),Rd(v),Rd(c);        E[c].push_back((Edge){u,v});    }    REP(i,1,m+1){        REP(j,0,E[i].size()){            Edge e=E[i][j];            Add_Edge(e.u,e.v,i);            Add_Edge(e.v,e.u,i);        }    }    Mx[0]=Ans=-INF;    Solve(1,n);    printf("%d\n",Ans);    return 0;}

总结

保持你的决心!(不

原创粉丝点击