又是$dy$讲的原题,我要疯了。
又成为了原题没$A$的人里的最高分(有个$P$用
只记得时间复杂度,但是忘了具体怎么做。。。
当时没听明白,后来也没时间回放研究,然后就挂了。
怎么这么多原题啊啊啊啊啊
幸亏$T2$送了不少分,最后没多少时间才打的$T1$,签到走人。
这样,最后才勉强有了个三位数的得分。
以后可能还是需要适度刚题。。。这暴力将近打满也没多少分。。。
应该还是得$A$一个。不然绝对没好名次
T1:图
大意:无向联通图。求方案使(四色染色后边两点不同色)或(去掉一个奇环的所有边后图联通)。$n,m le 3 imes 10^5$
图不会做那就生成树呗。
生成树好啊,如果只考虑树边就能直接二色染色了。
然而四色染色没见过啊。好象是两个二色染色的结合。
对非树边能染出来就好了呀。染出来就行,染不出来就说明不是二分图,那就找个奇环。因为树边没被删所以一定联通。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 6666666 4 int fir[S],l[S],to[S],FIR[S],L[S],TO[S],ec,EC,n,m,co[S],q[S],t,dep[S]; 5 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;} 6 void con(int a,int b){link(a,b);link(b,a);} 7 void Link(int a,int b){L[++EC]=FIR[a];FIR[a]=EC;TO[EC]=b;} 8 void dfs(int p,int c,int fa=0){ 9 co[p]|=c;c^=1; 10 for(int i=fir[p];i;i=l[i])if(!co[to[i]])dfs(to[i],c,p); 11 else if(to[i]!=fa)Link(p,to[i]); 12 } 13 void DFS(int p,int c){ 14 co[p]|=c; q[++t]=p; 15 for(int i=FIR[p];i;i=L[i])if(!(co[TO[i]]&8))DFS(TO[i],c^2); 16 else if((co[TO[i]]^c)&2^2){ 17 printf("B "); 18 int C=0; 19 for(;q[C]!=TO[i];++C); 20 printf("%d ",t-C+1); 21 for(int i=C;i<=t;++i)printf("%d ",q[i]); 22 exit(0); 23 } 24 t--; 25 } 26 int main(){ 27 cin>>n>>m; 28 for(int i=1,x,y;i<=m;++i)scanf("%d%d",&x,&y),con(x,y); 29 dfs(1,4); 30 for(int i=1;i<=n;++i)if(!(co[i]&8))DFS(i,10); 31 printf("A "); 32 for(int i=1;i<=n;++i)printf("%d ",co[i]-11); 33 }
T2:数列
大意:交互。给定$a,b,n$。有$n$个$[0,10^a)$的数,称为数列$A$,你可以给出一个长为$n$的$[0,10^b)$数列$B$。
交互库会回答$sumlimits_{i=1}^{n} A_i B_i$。最多调用$10$次询问后,输出$A$数列。
$Subtask1:n=10,a=b$
那么只需要每次让其中一个$B$为$1$其余均为$0$即可确定一个数。
$Subtask2,3:n=25,a=2,b geq 5$
那么只要手动哈希一下再哈希回来就行了。进制数$100$
$Subtask4:n=16,a=57,b=50$
还是哈希,但是因为位数不够,所以我们让最高的$8$位重叠,即两个数哈希一次,进制数$10^{49}$
于是其中一个数的较低$49$位就确定了。一共需要$8$次询问。
然后我们四对一组,以$10^8$为进制,把那些完全不确定的串再哈希一下。$2$次询问。
这样我们就能确定第一对的较低$8$位的值,结合上面的结果可以得到另一个数较高的$8$位,再减法得出这一对数。
然后在后面这个四对一组的哈希里删掉这一对继续做就行了。
要写高精减。前导0的处理比较麻烦。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #include"s.hpp" 3 using namespace std; 4 int X[233],Y[233],Z[233]; 5 void rev(string&s){reverse(s.begin(),s.end());} 6 void cpy(string s,int r,int b,int*a){ 7 for(int i=0;i<233;++i)a[i]=0; 8 for(int i=0;i<r;++i)a[b+i]=s[i]-'0'; 9 } 10 void dec(){ 11 for(int i=0;i<233;++i)Z[i]=0; 12 for(int i=0;i<233;++i){Z[i]+=X[i]-Y[i];if(Z[i]<0)Z[i]+=10,Z[i+1]--;} 13 } 14 vector<string>guess(int n,int a,int b,int t){ 15 if(t==1){ 16 string A="1",B="0"; 17 vector<string>v(10),ans(10); 18 for(int i=0;i<10;++i)v[i]=B; 19 for(int i=0;i<10;++i)v[i]=A,ans[i]=prod(v),v[i]=B; 20 return ans; 21 }else if(2<=t&&t<=3){ 22 string _10000="10000",_100="100",_1="1",_0="0",zz="000000"; 23 vector<string>v(25),ans(25); string B; 24 for(int i=0;i<n;++i)v[i]=_0; 25 for(int i=0;i<8;++i){ 26 v[i*3]=_1,v[i*3+1]=_100,v[i*3+2]=_10000; 27 string Q=prod(v); 28 for(int j=0;j<6;++j)zz[j]='0'; 29 for(int j=0;j<Q.size();++j)zz[j]=Q[Q.size()-j-1]; 30 if(zz[5]!='0')ans[i*3+2]=B+zz[5]+zz[4];else ans[i*3+2]=zz[4]; 31 if(zz[3]!='0')ans[i*3+1]=B+zz[3]+zz[2];else ans[i*3+1]=zz[2]; 32 if(zz[1]!='0')ans[i*3+0]=B+zz[1]+zz[0];else ans[i*3+0]=zz[0]; 33 v[i*3]=_0,v[i*3+1]=_0,v[i*3+2]=_0; 34 } 35 v[24]="1";ans[24]=prod(v); 36 for(int i=0;i<n;++i)cerr<<ans[i]<<endl; 37 return ans; 38 }else{ 39 string re[17],rt="10000000000000000000000000000000000000000000000000",b="1",_="00000000",T; 40 vector<string>v(16),ans(16); 41 for(int i=0;i<16;++i)v[i]="0"; 42 for(int i=0;i<16;i+=2){ 43 v[i]=rt;v[i|1]=b; 44 re[i]=prod(v);rev(re[i]); while(re[i].size()<114)re[i]+='0'; 45 int pt=48; while(re[i][pt]=='0'&&pt)pt--; 46 for(int j=0;j<=pt;++j)ans[i|1]+=re[i][j]; 47 v[i]=v[i|1]="0"; 48 } 49 for(int Q=0;Q<16;Q+=8){ 50 v[Q]=b;v[Q+2]=b+_;v[Q+4]=v[Q+2]+_;v[Q+6]=v[Q+4]+_; 51 T=prod(v); rev(T); 52 for(int I=Q;I<Q+8;I+=2){ 53 while(T.size()<66)T+='0'; 54 cpy(re[I],re[I].size(),0,X); cpy(T,8,49,Y); dec(); 55 int pt=56;while(!Z[pt]&&pt)pt--; 56 if(pt)for(int i=49;i<=pt;++i)ans[I|1]+='0'+Z[i]; 57 cpy(re[I],re[I].size(),0,X); cpy(ans[I|1],ans[I|1].size(),0,Y); dec(); 58 pt=232;while(!Z[pt]&&pt)pt--; 59 if(pt)for(int i=49;i<=pt;++i)ans[I]+='0'+Z[i]; else ans[I]="0"; 60 cpy(T,T.size(),0,X); cpy(ans[I],ans[I].size(),0,Y); dec(); 61 T.clear(); pt=232;while(!Z[pt]&&pt)pt--; 62 if(pt)for(int i=8;i<=pt;++i)T+='0'+Z[i]; else T="0"; 63 } 64 v[Q]=v[Q+2]=v[Q+4]=v[Q+6]="0"; 65 } 66 for(int i=0;i<16;++i)rev(ans[i]); 67 return ans; 68 } 69 }
T3:走路
大意:数轴[1,n]每个整点有一家饭店,要从原点出发走回原点。每家饭店可选是否进去。只要进去就要吃$a_i$单位食物。
如果目前为止一共吃了$A$单位食物则移动一单位距离消耗$A+1$体力。给定初始体力$x$,求最多能吃多少。$n le 10^5,x,a_i le 10^6$
最优决策当然是回来的路上再吃。总代价是$2max(i)+sum a_i imes i$
正着做不动,于是倒着来。设计$dp_{i,j}$表示$[i,n]$饭店一共吃$j$的最小代价。
每次可以拿上述总代价的式子更新$dp$表示从哪里出发。
或者$dp_{i,j+a[i]}=min(dp_{i+1,j}+a[i] imes i)$表示路上吃的。
后一种转移,因为大于$i$的饭店每单位食物消耗都$geq i$所以第二维的枚举上届就是$frac{x}{i}$
总时间复杂度是$O(x ln x)$
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,x,a[111111],dp[1111111]; 4 int main(){ 5 cin>>n>>x; 6 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 7 for(int i=0;i<=x;++i)dp[i]=x+1; 8 for(int i=n;i;--i){ 9 for(int j=x/i;j>=a[i];--j)dp[j]=min(dp[j-a[i]]+1ll*a[i]*i,1ll*dp[j]); 10 dp[a[i]]=min(dp[a[i]]*1ll,(a[i]+2ll)*i); 11 }for(int i=x;~i;--i)if(dp[i]<=x)return printf("%d ",i),0; 12 }