这么好的整数场,就终结了我连续莫名考好的记录。
功德圆满了。。。
还是炸了啊。而且炸的还挺厉害(自己又上不去自己粘的榜单啦)
说实在的这场考试做的非常差劲。虽说分数不算特别低但是表现是真的特别差。
T1看错数据范围,数组开小。
真的我以后只要不MLE还是多开一点数组吧不会锅的。
而且好好看题好好看数据范围!!!
T2乱搞+剪枝,数据水就过了。
关键是T3。如果T3打个特别简单的暴力拿40就滚的话就是并列rank1了(虽说在文件评测下skyh多了5分会变成rank2)
但是因为正解很好想,想到了正解就没有打暴力。
一个半小时,到死也没调出来。
不要那么自信啊喂你那么菜老老实实打暴力啊先!!!
临考前出这么多问题,也不知道我是要怎样。
改。改就是了。
T1:组合
根据题目暗示可以抽象成图论。
然后发现就是一个有/无向图欧拉路板子。及时重置fir数组以及当前枚举的边i。(就是当前弧优化)
板子,看代码就好了,这真的没法说。
注意数据范围以及n和m的含义不要看反,不要想当然以为nm同级。
1 #include2 #define gg return puts("NO"),0 3 int t,n,m,cnt=1,fir[2000005],l[2000005],to[2000005],in[2000005],out[2000005],deg[2000005]; 4 int al[2000005],S,E,el[2000005],ans[2000005],tp; 5 void dfs(int p){ 6 al[p]=1; 7 for(int i=fir[p];i;i=l[i])if(!al[to[i]])dfs(to[i]); 8 } 9 void DFS(int p){ 10 for(int i=fir[p];i;)if(!el[i]){ 11 el[i]=1;fir[p]=l[i]; 12 if(t==1)el[i^1]=1; 13 DFS(to[i]); 14 ans[++tp]=i;i=fir[p]; 15 }else fir[p]=i=l[i]; 16 } 17 void link(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;in[b]++;out[a]++;} 18 int main(){ 19 freopen("merge.in","r",stdin); 20 freopen("merge.out","w",stdout); 21 scanf("%d%d%d",&t,&n,&m); 22 if(t==1){ 23 for(int i=1,x,y;i<=m;++i)scanf("%d%d",&x,&y),link(x,y),link(y,x); 24 for(int i=1;i<=n;++i)if(in[i]&1) 25 if(!S)S=i;else if(!E)E=i;else gg; 26 if(!S)for(int i=1;i<=n;++i)if(in[i])S=i; 27 dfs(S); 28 for(int i=1;i<=n;++i)if(!al[i]&&in[i])gg; 29 puts("YES"); 30 DFS(S); 31 while(tp)printf("%d ",(ans[tp]>>1)*(ans[tp]&1?-1:1)),tp--; 32 }else{ 33 for(int i=1,x,y;i<=m;++i)scanf("%d%d",&x,&y),link(x,y); 34 for(int i=1;i<=n;++i) 35 if(in[i]==out[i]+1){if(!E)E=i;else gg;} 36 else if(in[i]+1==out[i]){if(!S)S=i;else gg;} 37 else if(in[i]!=out[i])gg; 38 if(!S)for(int i=1;i<=n;++i)if(out[i])S=i; 39 dfs(S); 40 for(int i=1;i<=n;++i)if(!al[i]&&in[i])gg; 41 puts("YES"); 42 DFS(S); 43 while(tp)printf("%d ",ans[tp]-1),tp--; 44 } 45 }
T2:统计
观察大样例,发现到了后来操作约等于没操作,只有很少的情况下会真正进行操作。
统计每个数后面有几个比它小的,如果没有那么就不操作。
这个统计可以在求逆序对时求出。
1 #include2 #include 3 int a[200005],n,m,cnt[200005],t[200005],r[200005],rp[200005],tp;long long ans; 4 void add(int p,int w=1){for(;p<=n;p+=p&-p)t[p]+=w;} 5 int ask(int p,int a=0){for(;p;p^=p&-p)a+=t[p];return a;} 6 void cal(int p){tp=0; 7 for(int i=p;i<=n;++i)if(a[i]<=a[p])r[++tp]=a[i],rp[tp]=i; 8 std::sort(r+1,r+1+tp); 9 for(int i=1;i<=tp;++i)a[rp[i]]=r[i]; 10 for(int i=1;i<=n;++i)t[i]=0; 11 for(int i=n;i>=p;--i)ans-=cnt[i],ans+=(cnt[i]=ask(a[i]-1)),add(a[i]); 12 } 13 int main(){ 14 freopen("count.in","r",stdin); 15 freopen("count.out","w",stdout); 16 scanf("%d%d",&n,&m); 17 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 18 for(int i=n;i;--i)ans+=(cnt[i]=ask(a[i]-1)),add(a[i]); 19 printf("%lld ",ans); 20 while(m--){ 21 int x;scanf("%d",&x); 22 if(cnt[x])cal(x); 23 printf("%lld ",ans); 24 } 25 }
然而其实复杂度并不好,需要用线段树或链表优化这个过程。
T3:点亮
首先声明:题解傻逼了那个不是方案数那个是最优转移值。。。
至今不知道考场上打的怎么错了。
猜测随机数据生成的树与完全二叉树相近,其实差不多,只不过2变成了e,log变成了ln。
考虑每一个点对最终答案的贡献。
枚举u,再枚举所有点v,得到lca(u,v),根据u和lca(u,v)就可以知道贡献是a[u][v]还是b[u][v]还是0。
所以预处理之后其实贡献就与v无关了,只与u和lca有关。
因为随机树的深度期望为$ln \ n$(实际测试点里稍大,为14)
所以可以状压祖先链上所有的点,1表示这个点的子树里点亮的点大于等于一半。
然后就可以根据祖先链上的情况判断每个点在现在情况下的贡献了。
然后状态定义就是dp[i][j][k]表示以i为根的子树里已经有j个点被点亮了,此时i的祖先链上的状态为k。
然后就可以dp了。转移就是经典的子树归并(所以可能需要滚动dp数组或者使用辅助数组,其实也可以不用)。
形式也很简单,什么DP[p][S+s][j]=max(dp[p][S][j]+dp[son][s][k])什么的。
状态数挺多的,得拿vector来resize存。
没什么好说的。初值-inf。该预处理的预处理。
然后就是代码细节问题。。。不是很好调,真的。。。
话说我感觉我这个$O(n^2)$递推求出所有点对的lca还是挺帅的(仅适用于这种f[i]
1 #include
注意那个pre数组的预处理,这个不能在里面枚举祖先状态时再枚举每一个点暴力求,会退化成$O(n^3)$
1 #include2 #include 3 #include 4 using namespace std; 5 #define inf -66666666 6 int max(int a,int b){return a>b?a:b;} 7 int read(){ 8 register int nt=0,p=0;register char ch=getchar(); 9 while(ch<'0'||ch>'9')nt=ch=='-',ch=getchar(); 10 while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-'0',ch=getchar(); 11 return nt?-p:p; 12 } 13 int n,f[1005],a[1005][1005],b[1005][1005],lca[1005][1005]; 14 int fir[1005],l[1005],to[1005],cnt,sz[1005],Dep[1005],DP[1005][32767]; 15 vector<int>dp[1005][1005]; 16 void link(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;} 17 void DFS(int p){ 18 sz[p]=1;Dep[p]=Dep[f[p]]+1; 19 for(int i=fir[p];i;i=l[i])DFS(to[i]),sz[p]+=sz[to[i]]; 20 } 21 void dfs(int p){int dep=Dep[p],alsz=1,S=(1< 1; 22 for(int i=0;i<=sz[p];++i)dp[p][i].resize(S+1),dp[p][i].resize(S+1); 23 for(int i=0;i<=sz[p];++i)for(int j=0;j<1< inf; 24 for(int j=0;j<1< j){ 25 dp[p][0][j]=dp[p][1][j]=0; 26 for(int i=1;i<=n;++i)if(!(j&1< 1))dp[p][0][j]+=a[p][i]; 27 for(int i=1;i<=n;++i)if(j&1< 1)dp[p][1][j]+=b[p][i]; 28 } 29 for(int i=fir[p];i;i=l[i]){int t=to[i]; 30 dfs(t); 31 for(int i=0;i<=alsz+sz[t];++i)for(int j=0;j<1< inf; 32 for(int x=0;x<=alsz;++x)for(int j=0;j<=sz[t];++j)for(int k=0;k<1< k) 33 DP[x+j][k]=max(DP[x+j][k],dp[p][x][k]+max(dp[t][j][k],dp[t][j][k+S+1])); 34 for(int i=0;i<=alsz+sz[t];++i)for(int j=0;j<1< DP[i][j]; 35 36 alsz+=sz[t]; 37 } 38 for(int i=0;i<=sz[p];++i)for(int j=0;j<1< j) 39 if(i 1< 1)dp[p][i][j]=inf; 40 else if(i>=sz[p]-i&&!(j&1< 1))dp[p][i][j]=inf; 41 } 42 int main(){ 43 freopen("light.in","r",stdin); 44 freopen("light.out","w",stdout); 45 n=read(); 46 for(int i=2;i<=n;++i)f[i]=read(),link(f[i],i); 47 for(int i=1;i<=n;++i){ 48 for(int j=1;jread(); 49 for(int j=i+1;j<=n;++j)a[i][j]=read(),b[i][j]=read(); 50 } 51 for(int i=1;i<=n;++i)lca[i][i]=i; 52 for(int i=1;i<=n;++i)for(int j=1;jlca[f[i]][j]; 53 for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)lca[i][j]=lca[j][i]; 54 DFS(1); 55 for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)lca[i][j]=Dep[lca[i][j]]; 56 dfs(1); 57 int ans=inf; 58 for(int i=0;i<=sz[1];++i)ans=max(ans,max(dp[1][i][0],dp[1][i][1])); 59 printf("%d\n",ans); 60 }
%%%mikufun为什么调代码那么快啊我调了半场考试加一个晚上才弄出来他半个晚上就过样例直接秒切了
我好菜啊QAQ