HDU6327 Problem I. Random Sequence
阿新 • • 發佈:2019-02-18
補題的時候一開始想了個假演算法,我預處理出有4個數字都是空的對答案的貢獻anum4,bnum4,3個數字為空,一個數字為i,anum3[i],bnum4[i],然後很膨脹地寫到一半發現數字是要連續的,上一個空位確定後會對當前空位確定有可能產生影響。然後就不知道怎麼辦了,看了claris題解,儲存的是f[i][x][y][z]表示到了第i位,z=a[i-1],y=gcd(a[i-1],a[i-2]),x=gcd(y,a[i-3])的情況對A有多少貢獻。看似簡單然而很不好寫,於是對著claris究極壓行的程式碼思考人生,claris機制得給所有x,y,z情況標了號,經過他的計算只有1500中情況,然後用g[s][y]表示x,y,z的情況編號後面一位是y時,轉移到的編號,w[s][y]表示要乘的數字。然後進行轉移計算出A,最後統計一遍B,有0的位置就乘以m。
#include<cstdio> #include<cstring> const int mod=1e9+7; #define maxl 110 #define maxs 1500 int n,m,cnt,ans,numa,numb; int a[maxl],v[maxl]; int gcd[maxs][maxl],g[maxs][maxl],w[maxs][maxl]; int f[maxl][maxs]; int id[maxl][maxl][maxl]; inline int cgcd(int a,int b) { if(b==0) return a; else return cgcd(b,a%b); } inline int qp(int a,int b) { int ans=1,cnt=a; while(b) { if(b&1) ans=(1ll*ans*cnt)%mod; cnt=(1ll*cnt*cnt)%mod; b>>=1; } return ans; } inline void prework() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++) scanf("%d",&v[i]); for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) gcd[i][j]=cgcd(i,j); cnt=0; for(int i=1;i<=m;i++) for(int j=i;j<=m;j+=i) for(int k=j;k<=m;k+=j) id[i][j][k]=++cnt; int x,y; for(int i=1;i<=m;i++) for(int j=i;j<=m;j+=i) for(int k=j;k<=m;k+=j) { x=id[i][j][k]; for(y=1;y<=m;y++) { g[x][y]=id[gcd[j][y]][gcd[k][y]][y]; w[x][y]=v[gcd[i][y]]; } } } inline void mainwork() { for(int i=1;i<=n;i++) for(int j=1;j<=cnt;j++) f[i][j]=0; int x,y,z,s; for(int i=1;i<=m;i++) { if(a[1] && a[1]!=i) continue; for(int j=1;j<=m;j++) { if(a[2] && a[2]!=j) continue; for(int k=1;k<=m;k++) { if(a[3] && a[3]!=k) continue; x=gcd[gcd[i][j]][k];y=gcd[j][k];z=k; s=id[x][y][z]; f[3][s]=(f[3][s]+1)%mod; } } } for(int i=3;i<n;i++) for(int j=1;j<=cnt;j++) if(f[i][j]) for(int k=1;k<=m;k++) { if(a[i+1]&&k!=a[i+1])continue; f[i+1][g[j][k]]=(f[i+1][g[j][k]]+1ll*f[i][j]*w[j][k]%mod)%mod; } numa=0;numb=1; for(int j=1;j<=cnt;j++) numa=(numa+f[n][j])%mod; for(int i=1;i<=n;i++) if(!a[i]) numb=1ll*numb*m%mod; ans=(1ll*numa*qp(numb,mod-2))%mod; } inline void print() { printf("%d\n",ans); } int main() { int t; scanf("%d",&t); for(int i=1;i<=t;i++) { prework(); mainwork(); print(); } return 0; }