9.29模考
阿新 • • 發佈:2021-09-29
T1 打表(table)
Sol
所謂最優不最優都是假的。因為顯然當一個取法最優的時候,其對立面就是最不優的,而每次選擇優和不優是等概率的,所以實際上每個數都是等概選取,答案就是所有數與原數的差的絕對值之和除\(2^k\)。
Code
#include<bits/stdc++.h> using namespace std; #define int long long const int p=1000000007,maxn=1000010; inline int read() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();} while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar(); return f?x:-x; } inline int ksm(int x,int mi) { int ans=1; while(mi) { if(mi&1)ans=ans*x%p; x=x*x%p;mi>>=1; } return ans; } int n,k,a[maxn]; signed main() { freopen("table.in","r",stdin); freopen("table.out","w",stdout); k=read();n=read(); int m=1<<k; for(int i=0;i<m;i++)a[i]=read(); int sum=0; for(int i=0;i<m;i++) { sum+=abs(a[i]-a[n]); } sum%=p; printf("%lld\n",sum*ksm(m,p-2)%p); return 0; }
T2 蛇(snake)
Sol
因為只有兩行,所以蛇的軌跡一定可以拆分成三部分:向前然後調頭、s形扭曲前進、向後然後調頭。
向前調頭和向後調頭的部分可以雜湊解決,而中間的s形部分考慮DP。
設\(dp[i][j][k][0]、dp[i][j][k][1]\)分別表示到\(i,j\)的位置蛇到\(k\)位置時,有/沒有變道的方案數。
那麼顯然有
前後的雜湊部分要注意方向即可。
由於蛇的方向不固定,所以要反向在跑一遍。但是上下沒有方向,所以當蛇長為\(1\)
不知道為什麼掛了的code
#include<bits/stdc++.h> #define int long long using namespace std; typedef unsigned long long ull; const int maxn=2010,p=1000000007; int dp[2][maxn][maxn<<1][2];//行、列、路徑長、是否換行 ull hash1[2][2][maxn],hash2[maxn]; ull bw[maxn]; ull gethash1(int x,bool flag,int st,int t) { if(flag)return hash1[x][flag][t]-hash1[x][flag][st+1]*bw[st-t+1]; return hash1[x][flag][t]-hash1[x][flag][st-1]*bw[t-st+1]; } ull gethash2(int st,int t) { return hash2[t]-hash2[st-1]*bw[t-st+1]; }//雜湊 int n,l,ans; char s[maxn]; int a[2][maxn],snk[maxn]; inline void pre() { for(int i=0;i<2;i++) { for(int j=1;j<=n;j++) { hash1[i][0][j]=hash1[i][0][j-1]*107+a[i][j]; } } for(int i=0;i<2;i++) { for(int j=n;j>=1;j--) { hash1[i][1][j]=hash1[i][1][j+1]*107+a[i][j]; } } return; } inline void work() { pre();//預處理雜湊 for(int i=0;i<2;i++) { for(int j=1;j<=n;j++) { if(a[i][j]==snk[1])dp[i][j][1][0]=1;//第一段預處理 for(int k=2;k<=j;k++) { if(k<<1>l)break; if(gethash1(i,0,j-k+1,j)==gethash2(1,k)&&gethash1(i^1,1,j,j-k+1)==gethash2(k+1,k<<1))dp[i][j][k<<1][1]=1; } } } for(int k=1;k<=l;k++) { for(int i=0;i<2;i++) { for(int j=1;j<=n;j++) { if(a[i][j]!=snk[k])continue; dp[i][j][k][0]=(dp[i][j][k][0]+dp[i][j-1][k-1][0]+dp[i][j-1][k-1][1])%p;//直走 dp[i][j][k][1]=(dp[i^1][j][k-1][0]+dp[i][j][k][1])%p;//蛇形轉向 } } } for(int i=0;i<2;i++) { for(int j=1;j<=n;j++) { for(int k=0;k<=l;k++) { if((l-k)%2!=0)continue; int le=(l-k)>>1; if(le==1)continue; if(j+le>n)continue; if(k==l||gethash1(i,0,j+1,j+le)==gethash2(k+1,k+le)&&gethash1(i^1,1,j+le,j+1)==gethash2(k+le+1,l)) { ans=(ans+dp[i][j][k][0]+dp[i][j][k][1])%p; } } } } return; } signed main() { freopen("snake.in","r",stdin); freopen("snake.out","w",stdout); scanf("%s",s+1);n=strlen(s+1); for(int i=1;i<=n;i++)a[0][i]=s[i]-'a'; scanf("%s",s+1); for(int i=1;i<=n;i++)a[1][i]=s[i]-'a'; scanf("%s",s+1);l=strlen(s+1); bw[0]=1; for(int i=1;i<=l;i++) { snk[i]=s[i]-'a'; hash2[i]=hash2[i-1]*107+snk[i]; bw[i]=bw[i-1]*107; } work(); reverse(a[0]+1,a[0]+n+1); reverse(a[1]+1,a[1]+n+1); memset(dp,0,sizeof(dp)); work(); if(l==1) { for(int i=0;i<2;i++) { for(int j=1;j<=n;j++) { if(a[i][j]==snk[1])ans--; } } } if(l==2) { for(int i=0;i<2;i++) { for(int j=1;j<=n;j++) { if(a[i][j]==snk[1]&&a[i^1][j]==snk[2])ans--; } } } printf("%lld\n",ans); return 0; }