2017-10-18离线赛
来源:互联网 发布:2017淘宝售假申诉成功 编辑:程序博客网 时间:2024/06/07 21:53
大体状况
220/300
正常一些了。
前十都是210~230= =A12两题,
最后一题的DP有一点点Bug然后没了10分。。
T1 snum
分析
这种按位相加的东西显然可以拆数字来预处理。
取一个Base,预处理出Base内的S数值。
对于一个大数,拆分成若干个Base以内的数,
然后直接算出来。
因为
即每隔
复杂度约为
还有简单一些的方法。
注意到
有
直接DFS得出所有满足条件的S数,
然后判断是否在范围内即可,
复杂度为
其实打表的话会发现最后在范围内只有
那么换种方法打表,即打表得出所有S数,然后二分查找得到答案。
复杂度为
代码
打的表就删掉了= =
#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状态定义。
即定义
i后已给菜的状态压缩为j,
最后一个给的人是
然后这个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;}
总结
保持你的决心!(不
- 2017-10-18离线赛
- 2017-10-18离线赛总结
- 2017-10-10离线赛
- 2017-10-07离线赛
- 2017-10-09离线赛
- 2017-10-06离线赛
- 2017-10-12离线赛
- 2017-10-15离线赛
- 2017-10-16离线赛
- 2017-10-17离线赛
- 2017-10-10离线赛总结
- 2017-10-3离线赛小结
- 2017-10-4离线赛总结
- 2017-10-6离线赛总结
- 2017-10-7离线赛题解
- 2017-10-7离线赛总结
- 2017-10-8离线赛总结
- 2017-10-9离线赛总结
- ASP.NET WebAPi之断点续传下载(中)
- java 排列组合
- 西南科技大学OJ题 最简单的C程序0612
- emf文件解析处理EMR_RESERVED_108格式记录
- Shell中怎么获取当前日期和时间
- 2017-10-18离线赛
- Scala学习笔记-控制结构和函数(1)
- 继承
- 搭建Git服务器
- 1019. 数字黑洞 (20)
- Android进阶之路
- C#Json的解析与取值
- StringUtils源码
- Swift语言基础小习题(包含答案)-只适合菜鸟.