[考试反思]0201省选模拟15:分界

30+10+30+100=170 rk13

17岁的第一仗出师不利。

和外校联考,所以难度不高?后三道题非常简单基本上都是裸的。

但是我做的这是个啥啊。。。

T2广义后缀自动机板子写挂,如果儿子是nq就把儿子修改成nq。。。

T3想到正解然后算错复杂度结果觉得都可以写个简单的于是就把暴力交了上去。

T1猜到了第一个结论不会分块暴力也没想到数位dp。。。

考试前就感觉今天要炸,结果就真炸了。

又当了一次改题大神。半小时一道,中午没睡觉就直接改完了。

下午在uoj上乱跑找好题做ppt。效率挺低的。

这几天一直多灾多难。但愿它们在16岁终止吧。

T1:倒计时

大意:给定n,每次可以选择十进制下n的某一位,让n减去这个数。求最少几次能变成0。$n le 10^{18}$

首先,发现答案有单调性,随着n增加单调不减。所以最优决策是每次去掉最大的数字。可以归纳证明。

如果高位特别小,低位特别大,那么即使高位不一样那么最近的几次决策也都是一样的。

想到这里,设dp[i][j]表示前面的所有数位最大的是i,剩下的数位是j,此时想把较低的这些位操作到0或负数所需要的最少步数,以及在步数最少的前提下操作后低位上是几。

转移直接按照含义来。记忆化搜索。代码特别好写。但是思路想不到啊。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 map<ll,pair<ll,ll> >dp[10];
 5 pair<ll,ll>sch(ll x,ll n){//cout<<x<<' '<<n<<endl;
 6     if(n==0)return make_pair(0,0);
 7     if(n<=x)return make_pair(1,n-x);
 8     if(n<=9)return make_pair(1,0);
 9     if(dp[x].find(n)!=dp[x].end())return dp[x][n];
10     ll h=n,l=1,ans=0,ls;while(h>=10)h/=10,l*=10;ls=n-h*l-l;
11     while(h>=0){
12         pair<ll,ll>r=sch(max(x,h),l+ls);
13         ans+=r.first;ls=r.second;h--;
14         if(!ls&&h>=0)ans++,ls=-max(x,h+1);
15     }
16     return dp[x][n]=make_pair(ans,ls);
17 }
18 main(){ll n;cin>>n;cout<<sch(0,n).first;}
View Code

T2:旅行路线

大意:树,边定向,每个点都能到达1。一条路线可以用路径上每个点度数的序列表示。求本质不同路径数。$n le 10^5$

本质不同子串树。广义后缀自动机,可以说是模板题了。

写了一遍bfs建树。不怕被卡,心安了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 222222
 4 int fir[S],l[S],to[S],ec,f[S],lst=1,pc=1,deg[S],len[S],n,rt[S];long long ans;
 5 map<int,int>c[S];
 6 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;deg[a]++;}
 7 void extend(int C){
 8     int np,nq,q,p=lst;
 9     if(q=c[p][C]){
10         if(len[q]==len[p]+1){lst=q;return;}
11         nq=lst=++pc; c[nq]=c[q]; f[nq]=f[q]; len[nq]=len[p]+1;
12         f[q]=nq; for(;c[p][C]==q;p=f[p])c[p][C]=nq;
13     }else{
14         lst=np=++pc; len[np]=len[p]+1;
15         for(;p&&!c[p][C];p=f[p])c[p][C]=np;
16         if(!p){f[np]=1;return;} q=c[p][C];
17         if(len[q]==len[p]+1){f[np]=q;return;}
18         len[nq=++pc]=len[p]+1; c[nq]=c[q]; f[nq]=f[q]; f[np]=f[q]=nq;
19         for(;c[p][C]==q;p=f[p])c[p][C]=nq;
20     }
21 }
22 void dfs(int p){
23     for(int i=fir[p];i;i=l[i])lst=rt[p],extend(deg[to[i]]),rt[to[i]]=lst;
24     for(int i=fir[p];i;i=l[i])dfs(to[i]);
25 }
26 int main(){
27     scanf("%d",&n);
28     for(int i=1,a,b;i<n;++i)scanf("%d%d",&a,&b),link(b,a);
29     extend(deg[1]-1);rt[1]=lst;dfs(1);
30     for(int i=1;i<=pc;++i)ans+=len[i]-len[f[i]];
31     printf("%lld
",ans);
32 }
View Code

T3:流浪者

大意:一个人从(1,1)出发往右或下走,初始有个hp。有k个坏点。走到坏点时hp=hp+1>>1。求走到(n,m)时的期望hp。$n,m le 100000, k le 2000 , hp le 1000000$

每次除2,所以最多$log$次就变成1了。

容斥+拓扑dp。思路很简单,记录到每个点经过多少坏点的方案数就行,超过log次的特殊处理防止容斥出锅。

因为超出部分的缘故,所以容斥需要在转移过程中进行,这样dp的含义由至少变成了恰好。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define mod 1000000007
 4 int n,m,k,s,fac[222222],inv[222222],x[2222],y[2222],dp[2222][2222],ans;
 5 int q[2222],fir[2222],l[6666666],to[6666666],deg[2222],ec,ttpl;
 6 int C(int b,int t){return 1ll*fac[b]*inv[t]%mod*inv[b-t]%mod;}
 7 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;deg[b]++;}
 8 int main(){
 9     fac[0]=inv[0]=inv[1]=fac[1]=1;
10     for(int i=2;i<=200000;++i)fac[i]=fac[i-1]*1ll*i%mod,inv[i]=mod-1ll*mod/i*inv[mod%i]%mod;
11     for(int i=1;i<=200000;++i)inv[i]=inv[i-1]*1ll*inv[i]%mod;
12     scanf("%d%d%d%d",&n,&m,&k,&s);m--;n--;x[k+1]=n;y[k+1]=m;link(0,k+1);
13     for(int i=1;i<=k;++i)scanf("%d%d",&x[i],&y[i]),link(0,i),link(i,k+1),x[i]--,y[i]--;
14     for(int i=1;i<=k;++i)for(int j=1;j<=k;++j)if(i!=j)if(x[i]<=x[j]&&y[i]<=y[j])link(i,j);
15     dp[0][0]=1;
16     for(int h=1,t=1;h<=t;++h)for(int i=fir[q[h]];i;i=l[i]){
17         deg[to[i]]--;if(!deg[to[i]])q[++t]=to[i];long long rt=C(x[to[i]]+y[to[i]]-x[q[h]]-y[q[h]],x[to[i]]-x[q[h]]);
18         for(int j=0;j<=20;++j)dp[j+1][to[i]]=(dp[j+1][to[i]]+dp[j][q[h]]*rt)%mod,dp[j][to[i]]=(dp[j][to[i]]-(j?1:0)*dp[j][q[h]]*rt%mod+mod)%mod;
19     }
20     for(int i=1;i<=20;++i)ans=(ans+1ll*s*dp[i][k+1])%mod,s=s+1>>1;
21     ans=(ans+dp[21][k+1])%mod;
22     printf("%lld
",1ll*ans*inv[n+m]%mod*fac[n]%mod*fac[m]%mod);
23 }
View Code

T4:摆棋子

大意:同《土兵占领

当时的做法好诡异&弱智啊。

然而做了chip那道题之后,土兵占领连想带写也就17分钟。

直接考虑哪些位置放很麻烦,考虑哪些位置可以不放,最大化这个值。

左行右列边是士兵,每行每列不能删太多就是流量限制,每个兵流量为1如果流了就表示不放这个兵。

最大流,没了。1.1k

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,k,fir[222],l[22222],to[22222],v[22222],ec=1,T,X[111],Y[111],ans,d[22222],q[22222],gg[111][111];
 4 void link(int a,int b,int w){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=w;}
 5 void con(int a,int b,int w){link(a,b,w);link(b,a,0);}
 6 bool bfs(){
 7     for(int i=1;i<=T;++i)d[i]=0;d[0]=1;
 8     for(int h=1,t=1;h<=t;++h)for(int i=fir[q[h]];i;i=l[i])if(!d[to[i]]&&v[i])d[q[++t]=to[i]]=d[q[h]]+1;
 9     return d[T];
10 }
11 int dfs(int p,int f){int r=f;
12     if(p==T)return f;
13     for(int i=fir[p];i&&r;i=l[i])if(v[i]&&d[to[i]]==d[p]+1){
14         int x=dfs(to[i],min(r,v[i]));
15         if(!x)d[to[i]]=0;
16         v[i]-=x;v[i^1]+=x;r-=x;
17     }return f-r;
18 }
19 int main(){
20     scanf("%d%d%d",&n,&m,&k);T=n+m+1;
21     for(int i=1,w;i<=n;++i)scanf("%d",&X[i]);
22     for(int i=1,w;i<=m;++i)scanf("%d",&Y[i]);
23     for(int i=1,x,y;i<=k;++i)scanf("%d%d",&x,&y),gg[x][y]=1;
24     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(!gg[i][j])con(i,j+n,1),X[i]--,Y[j]--,ans++;
25     for(int i=1;i<=n;++i)if(X[i]>0)return puts("No Solution"),0;else con(0,i,-X[i]);
26     for(int i=1;i<=m;++i)if(Y[i]>0)return puts("No Solution"),0;else con(i+n,T,-Y[i]);
27     while(bfs())ans-=dfs(0,1234567);printf("%d
",ans);
28 }
View Code
原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12249889.html