2017-10-18离线赛

大体状况

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 long

void 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 100000
int 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 1000000
struct 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 long

void 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 1004
int 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 0x3f3f3f3f

struct 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 long

void 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 200004
int 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 2000000044

void 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;
}

总结

保持你的决心!(不

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值