[考试反思]1026csp-s模拟测试88:发展
不用你们说,我自己来:我颓闪存我没脸。
昨天的想法,
今天的回答。
生存,
发展。
总分榜应该稍有回升,但是和上面的差距肯定还是很大。
继续。
为昨天的谬误,承担代价。
T2和T3都值得张记性。
T2因为上次输出了"-0.00"在文本比较下与"0.0"不同导致WA,所以这次输出的时候把答案加了0.005
但是加的太多了,在四舍五入下恰好进位了导致WA。
为了防止输出"-0.0"要将答案加一个1e-9级别的数,不要太小也不要太大。
T3算错上限没打高精。
考虑极端情况。考试时不要用__int128(CSP-S不认可)
我不喜欢RP守恒。
我想稳在rank5以内。遥不可及。
T1:军训队列。
一个明显的斜率优化dp。但是考场上推了一会没有推出来。
然而这题用不到,因为身高最多有6001种,所以$O(6001*6001*k)$可过
但是要注意把所有人身高压起来后n可能小于k,判掉。
斜率优化的假单调栈可以当成是一个剪枝。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 double dp[100005][21],h[100005];int n,k,q[100005],qh,qt; 5 double fab2(double x){return x*x;} 6 double cal(int j,int k,int f){return (dp[j][f-1]-dp[k][f-1])/(h[j+1]-h[k+1])+h[j+1]+h[k+1];} 7 int main(){ 8 scanf("%d%d",&n,&k); 9 for(int i=1;i<=n;++i)scanf("%lf",&h[i]); 10 sort(h+1,h+1+n);n=unique(h+1,h+1+n)-h-1;h[n+1]=1e9; 11 for(int i=1;i<=n;++i)dp[i][1]=fab2(h[i]-h[1]); 12 for(int j=2;j<=k;++j){ 13 q[qt=qh=1]=0; 14 for(int i=1;i<=n;++i){ 15 dp[i][j]=1e18; 16 while(qt-qh>=1&&cal(q[qh+1],q[qh],j)<h[i]*2)qh++; 17 for(int p=qh;p<=qt;++p)dp[i][j]=min(dp[i][j],dp[q[p]][j-1]+fab2(h[i]-h[q[p]+1])); 18 q[++qt]=i; 19 } 20 }printf("%.2lf\n",dp[n][k]); 21 }
然而当然也可以打一个真正的斜率优化。
转移式是$dp[i][f]=min(dp[j][f-1]+(h[j+1])^2+(h[i])^2-2\times h[j+1] \times h[i])$
然后接下来与i有关的项都可以提出来,剩下的是常数。
然后就可以得到一个关于$h[i]$的一次函数(直线)。
因为在这道题里h是单调的,所以斜率是单调的,取值的横坐标也是单调的。
所以就是一堆直线,可以维护凸包了。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 double dp[100005][21],h[100005],k[100005],b[100005];int n,K,q[100005],qh,qt; 5 double fab2(double x){return x*x;} 6 double cal(int j,double x){return b[j]+k[j]*x;} 7 double jd(int j,int i){return (b[j]-b[i])/(k[i]-k[j]);} 8 int main(){ 9 scanf("%d%d",&n,&K); 10 for(int i=1;i<=n;++i)scanf("%lf",&h[i]); 11 sort(h+1,h+1+n);n=unique(h+1,h+1+n)-h-1;h[n+1]=1e9; 12 for(int i=1;i<=n;++i)dp[i][1]=fab2(h[i]-h[1]); 13 for(int j=2;j<=K;++j){ 14 q[qt=qh=1]=j-1;k[j-1]=-2*h[j];b[j-1]=dp[j-1][j-1]+fab2(h[j]); 15 for(int i=j;i<=n;++i){ 16 k[i]=-2*h[i+1];b[i]=dp[i][j-1]+fab2(h[i+1]); 17 while(qt-qh>=1&&cal(q[qh],h[i])>cal(q[qh+1],h[i]))qh++; 18 while(qt-qh>=1&&jd(q[qt-1],i)>jd(q[qt],i))qt--; 19 dp[i][j]=dp[q[qh]][j-1]+fab2(h[i]-h[q[qh]+1]); 20 q[++qt]=i; 21 } 22 }printf("%.2lf\n",dp[n][K]); 23 }
T2:山屋惊魂
规模不是很大的模拟。虽说也不小。
预处理一下dize[i][j]表示用i个骰子得到j的概率。(骰子的英语不是dize。。。打脸。。。但是我懒得改了)
然后。。我也不知道该讲什么。。。模拟好像真的没办法讲。。。
按照题目说的就是了。不要读错题
其实我不是很明白为什么会打的那么长,并没有感觉这个模拟比以前的模拟难很多。。。
1 #include<cstdio> 2 #include<string> 3 #include<iostream> 4 #include<map> 5 using namespace std; 6 map<string,int>M; 7 long double dize[9][17],pos[101][4098],fail,ans[4][8],lim[102][4][8]; 8 int n,st[4],s[102],c1[102],c2[102],num; 9 string bar[4],knd,opt; 10 int chg(int S,int p,int w){return (S^S&7<<p*3)|w<<p*3;} 11 int main(){//freopen("betrayal.in","r",stdin); 12 dize[0][0]=1; 13 for(int i=0;i<=7;++i)for(int j=0;j<=i<<1;++j) 14 dize[i+1][j]+=dize[i][j]/3,dize[i+1][j+1]+=dize[i][j]/3,dize[i+1][j+2]+=dize[i][j]/3; 15 for(int i=0;i<4;++i)cin>>bar[i]>>st[i],st[i]--; 16 cin>>n; 17 pos[0][st[0]|st[1]<<3|st[2]<<6|st[3]<<9]=1; 18 M["Might"]=0;M["Speed"]=1;M["Sanity"]=2;M["Knowledge"]=3; 19 for(int i=0;i<n;++i){ 20 cin>>knd>>opt; 21 if(opt=="<"){ 22 cin>>num; 23 for(int j=0;j<=7;++j)for(int k=0;k<=16;++k)lim[i][M[knd]][j]+=(dize[bar[M[knd]][j]-'0'][k]*(k>=num)); 24 cin>>knd>>opt; 25 }else if(opt=="<="){ 26 cin>>num; 27 for(int j=0;j<=7;++j)for(int k=0;k<=16;++k)lim[i][M[knd]][j]+=(dize[bar[M[knd]][j]-'0'][k]*(k> num)); 28 cin>>knd>>opt; 29 }else if(opt==">"){ 30 cin>>num; 31 for(int j=0;j<=7;++j)for(int k=0;k<=16;++k)lim[i][M[knd]][j]+=(dize[bar[M[knd]][j]-'0'][k]*(k<=num)); 32 cin>>knd>>opt; 33 }else if(opt==">="){ 34 cin>>num; 35 for(int j=0;j<=7;++j)for(int k=0;k<=16;++k)lim[i][M[knd]][j]+=(dize[bar[M[knd]][j]-'0'][k]*(k< num)); 36 cin>>knd>>opt; 37 } 38 s[i]=M[knd]; 39 if(opt[0]=='+')if(opt.length()==3)c2[i]+=opt[1]-'0'; 40 else c1[i]+=opt[1]-'0'; 41 if(opt[0]=='-')if(opt.length()==3)c2[i]-=opt[1]-'0'; 42 else c1[i]-=opt[1]-'0';//printf("%d %d %d\n",s[i],c1[i],c2[i]); 43 } 44 for(int i=0;i<n;++i)for(int S=0;S<1<<12;++S){ 45 int state[4]={S&7,S>>3&7,S>>6&7,S>>9&7}; 46 double rp=pos[i][S]; 47 for(int j=0;j<4;++j)rp*=(1-lim[i][j][state[j]]); 48 pos[i+1][S]+=pos[i][S]-rp; 49 if(c1[i]){ 50 state[s[i]]+=c1[i];state[s[i]]=min(state[s[i]],7); 51 if(state[s[i]]<0)fail+=rp; 52 else pos[i+1][chg(S,s[i],state[s[i]])]+=rp; 53 }else if(c2[i]>=0){ 54 for(int r=0;r<=16;++r){ 55 double P=rp*dize[c2[i]][r]; 56 int nw=state[s[i]]+r;nw=min(nw,7); 57 pos[i+1][chg(S,s[i],nw)]+=P; 58 } 59 }else{ 60 for(int r=0;r<=16;++r){ 61 double P=rp*dize[-c2[i]][r]; 62 int nw=state[s[i]]-r; 63 if(nw<0)fail+=P; 64 else pos[i+1][chg(S,s[i],nw)]+=P; 65 } 66 }ed:; 67 } 68 printf("%.2Lf\n",fail*100+0.0001); 69 for(int i=0;i<1<<12;++i)for(int k=0;k<4;++k)ans[k][bar[k][i>>k*3&7]-'1']+=pos[n][i]; 70 for(int k=0;k<4;++k,puts(""))for(int i=0;i<8;++i)printf("%.2Lf ",ans[k][i]*100+0.0001); 71 }
1 #include<cstdio> 2 #include<string> 3 #include<iostream> 4 #include<map> 5 using namespace std; 6 map<string,int>M; 7 double dize[9][17],pos[101][4098],fail,ans[4][8],lim[102][4][8]; 8 int n,st[4],s[102],c1[102],c2[102],num; 9 string bar[4],knd,opt; 10 int chg(int S,int p,int w){return (S^S&7<<p*3)|w<<p*3;} 11 int abs(int a){return a>0?a:-a;} 12 int nt(int a){return a>0?1:-1;} 13 int OPT(string s,int a,int b){return s=="<="?a>b:(s=="<"?a>=b:(s==">="?a<b:a<=b));} 14 int main(){ 15 dize[0][0]=1; 16 for(int i=0;i<8;++i)for(int j=0;j<=i*2;++j) 17 dize[i+1][j]+=dize[i][j]/3,dize[i+1][j+1]+=dize[i][j]/3,dize[i+1][j+2]+=dize[i][j]/3; 18 for(int i=0;i<4;++i)cin>>bar[i]>>st[i],st[i]--; 19 cin>>n; pos[0][st[0]|st[1]<<3|st[2]<<6|st[3]<<9]=1; 20 M["Speed"]=1;M["Sanity"]=2;M["Knowledge"]=3; 21 for(int i=0;i<n;++i){ 22 cin>>knd>>opt; 23 if(opt[0]!='+'&&opt[0]!='-'){ 24 cin>>num; 25 for(int j=0;j<8;++j)for(int k=0;k<=16;++k) 26 lim[i][M[knd]][j]+=(dize[bar[M[knd]][j]-'0'][k]*OPT(opt,k,num)); 27 cin>>knd>>opt; 28 } 29 s[i]=M[knd]; 30 if(opt.length()==3)c2[i]+=(opt[1]-'0')*(opt[0]=='+'?1:-1); 31 else c1[i]+=(opt[1]-'0')*(opt[0]=='+'?1:-1); 32 } 33 for(int i=0;i<n;++i)for(int S=0;S<1<<12;++S){ 34 int state[4]={S&7,S>>3&7,S>>6&7,S>>9&7}; double rp=pos[i][S]; 35 for(int j=0;j<4;++j)rp*=(1-lim[i][j][state[j]]); 36 pos[i+1][S]+=pos[i][S]-rp; 37 if(c1[i]){ 38 state[s[i]]+=c1[i];state[s[i]]=min(state[s[i]],7); 39 if(state[s[i]]<0)fail+=rp; 40 else pos[i+1][chg(S,s[i],state[s[i]])]+=rp; 41 }else for(int r=0;r<=16;++r){ 42 double P=rp*dize[abs(c2[i])][r]; 43 int nw=state[s[i]]+nt(c2[i])*r;nw=min(nw,7); 44 if(nw<0)fail+=P;else pos[i+1][chg(S,s[i],nw)]+=P; 45 } 46 } 47 printf("%.2lf\n",fail*100+1e-6); 48 for(int i=0;i<1<<12;++i)for(int k=0;k<4;++k)ans[k][bar[k][i>>k*3&7]-'1']+=pos[n][i]; 49 for(int k=0;k<4;++k,puts(""))for(int i=0;i<8;++i)printf("%.2lf ",ans[k][i]*100+1e-6); 50 }
压行后的代码不存在任何的复制粘贴了,可以简单扩展了。
T3:彩球问题
记忆化搜索/dp
状态4维,12/12/12/4,分别表示还有1/2/3个的球有几种颜色,且上一次用的球还剩下0/1/2个
然后又是模拟?
最后的答案貌似有$10^{33}$级别?
1 #include<cstdio> 2 #define dp re[c1][c2][c3][lst] 3 __int128 ans,re[13][13][13][3];int cnt[4],n,x; 4 __int128 sch(int c1,int c2,int c3,int lst){ 5 if(dp!=-1)return dp; 6 dp=0; 7 if(c1==0&&c2==0&&c3==0)return 1; 8 if(lst==0){ 9 if(c1)dp+=c1*sch(c1-1,c2,c3,0); 10 if(c2)dp+=c2*sch(c1+1,c2-1,c3,1); 11 if(c3)dp+=c3*sch(c1,c2+1,c3-1,2); 12 }else if(lst==1){ 13 if(c1>1)dp+=(c1-1)*sch(c1-1,c2,c3,0); 14 if(c2)dp+=c2*sch(c1+1,c2-1,c3,1); 15 if(c3)dp+=c3*sch(c1,c2+1,c3-1,2); 16 }else if(lst==2){ 17 if(c1)dp+=c1*sch(c1-1,c2,c3,0); 18 if(c2>1)dp+=(c2-1)*sch(c1+1,c2-1,c3,1); 19 if(c3)dp+=c3*sch(c1,c2+1,c3-1,2); 20 }return dp; 21 } 22 int main(){ 23 scanf("%d",&n); 24 while(n--)scanf("%d",&x),cnt[x]++; 25 for(int i=0;i<13;++i)for(int j=0;j<13;++j)for(int k=0;k<13;++k)for(int l=0;l<3;++l)re[i][j][k][l]=-1; 26 __int128 x=sch(cnt[1],cnt[2],cnt[3],0); 27 if(x/1000000000000000000ll)printf("%lld",(long long)(x/1000000000000000000ll)); 28 printf("%lld\n",(long long)(x%1000000000000000000ll)); 29 }
1 #include<cstdio> 2 #define dp re[c1][c2][c3][lst] 3 struct LL{ 4 long long x[5]; 5 #define mod 100000000 6 friend void operator+=(LL &a,LL b){ 7 for(int i=0;i<5;++i)a.x[i]+=b.x[i]; 8 for(int i=0;i<4;++i)a.x[i+1]+=a.x[i]/mod,a.x[i]%=mod; 9 } 10 void print(int i=4){ 11 for(;~i;--i)if(x[i]){printf("%lld",x[i]);break;} 12 for(--i;~i;--i)printf("%08lld",x[i]); 13 } 14 friend LL operator*(int x,LL a){ 15 for(int i=0;i<5;++i)a.x[i]*=x; 16 for(int i=0;i<4;++i)a.x[i+1]+=a.x[i]/mod,a.x[i]%=mod; 17 return a; 18 } 19 friend bool operator!=(LL a,int x){return a.x[0]!=-1;} 20 void operator=(int p){x[0]=p;} 21 }; 22 LL ans,re[13][13][13][3];int cnt[4],n,x; 23 LL sch(int c1,int c2,int c3,int lst){ 24 if(dp!=-1)return dp; 25 dp=0; 26 if(c1==0&&c2==0&&c3==0)return dp=1,dp; 27 if(lst==0){ 28 if(c1)dp+=c1*sch(c1-1,c2,c3,0); 29 if(c2)dp+=c2*sch(c1+1,c2-1,c3,1); 30 if(c3)dp+=c3*sch(c1,c2+1,c3-1,2); 31 }else if(lst==1){ 32 if(c1>1)dp+=(c1-1)*sch(c1-1,c2,c3,0); 33 if(c2)dp+=c2*sch(c1+1,c2-1,c3,1); 34 if(c3)dp+=c3*sch(c1,c2+1,c3-1,2); 35 }else if(lst==2){ 36 if(c1)dp+=c1*sch(c1-1,c2,c3,0); 37 if(c2>1)dp+=(c2-1)*sch(c1+1,c2-1,c3,1); 38 if(c3)dp+=c3*sch(c1,c2+1,c3-1,2); 39 }return dp; 40 } 41 int main(){ 42 scanf("%d",&n); 43 while(n--)scanf("%d",&x),cnt[x]++; 44 for(int i=0;i<13;++i)for(int j=0;j<13;++j)for(int k=0;k<13;++k)for(int l=0;l<3;++l)re[i][j][k][l]=-1; 45 sch(cnt[1],cnt[2],cnt[3],0).print(); 46 }
因为真正CSP-S上也不能用__int128,所以就算是模拟赛写高精也是很有必要的。
态度必须要有,天人不相欺。