[考试反思]0322省选模拟52:重现

又是$dy$讲的原题,我要疯了。

又成为了原题没$A$的人里的最高分(有个$P$用

只记得时间复杂度,但是忘了具体怎么做。。。

当时没听明白,后来也没时间回放研究,然后就挂了。

怎么这么多原题啊啊啊啊啊

幸亏$T2$送了不少分,最后没多少时间才打的$T1$,签到走人。

这样,最后才勉强有了个三位数的得分。

以后可能还是需要适度刚题。。。这暴力将近打满也没多少分。。。

应该还是得$A$一个。不然绝对没好名次

 

T1:图

大意:无向联通图。求方案使(四色染色后边两点不同色)或(去掉一个奇环的所有边后图联通)。$n,m \le 3 \times 10^5$

图不会做那就生成树呗。

生成树好啊,如果只考虑树边就能直接二色染色了。

然而四色染色没见过啊。好象是两个二色染色的结合。

对非树边能染出来就好了呀。染出来就行,染不出来就说明不是二分图,那就找个奇环。因为树边没被删所以一定联通。

 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 }
View Code

 

T2:数列

大意:交互。给定$a,b,n$。有$n$个$[0,10^a)$的数,称为数列$A$,你可以给出一个长为$n$的$[0,10^b)$数列$B$。

交互库会回答$\sum\limits_{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的处理比较麻烦。

 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 }
View Code

 

T3:走路

大意:数轴[1,n]每个整点有一家饭店,要从原点出发走回原点。每家饭店可选是否进去。只要进去就要吃$a_i$单位食物。

如果目前为止一共吃了$A$单位食物则移动一单位距离消耗$A+1$体力。给定初始体力$x$,求最多能吃多少。$n \le 10^5,x,a_i \le 10^6$

最优决策当然是回来的路上再吃。总代价是$2max(i)+\sum a_i \times i$

正着做不动,于是倒着来。设计$dp_{i,j}$表示$[i,n]$饭店一共吃$j$的最小代价。

每次可以拿上述总代价的式子更新$dp$表示从哪里出发。

或者$dp_{i,j+a[i]}=min(dp_{i+1,j}+a[i] \times i)$表示路上吃的。

后一种转移,因为大于$i$的饭店每单位食物消耗都$\geq i$所以第二维的枚举上届就是$\frac{x}{i}$

总时间复杂度是$O(x ln x)$

 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\n",i),0;
12 }
View Code

 

posted @ 2020-03-22 19:25  DeepinC  阅读(...)  评论(...编辑  收藏