bzoj 4872 [Shoi2017]分手是祝愿
题面
https://www.lydsy.com/JudgeOnline/problem.php?id=4872
题解
首先解法是唯一的
所以我们算出最少要按几次 然后如果<=k那么就这么按 获得80分(真多啊...)
然后我们令f[i]表示当前离结果还有i步,我们要得到结果的期望步数
又因为f[k]=k 所以我们可以解出所有的f
f[最少要按几次]*n!就是答案
我们可以递推 设f[i]=Af[i+1]+B 这样我们从k+1跑到n 每一个i的A,B都可以求出来 这样我们就解出了f[n]
然后记录下每一个i对应的A,B 逆着推回去 就能解出f[最少要按几次]
但是由于不知名问题 我的这个写法只获得95分 可能在取模和求逆元的过程中出现了问题
于是我因为这种方法不是正解(失去调试的耐心)而放弃了这种做法
然后百度一下
差分!!!
考虑差分f,或者说g[i]表示i到i-1步的期望步数
这样得到
g[i]=((n-i)(g[i]+1)+n)/i
然后答案就是(g[m]+...+g[k+1]+k)*n!
Code
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 ll read(){ 6 ll x=0,f=1;char c=getchar(); 7 while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();} 8 while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();} 9 return x*f; 10 } 11 12 const int mod=100003; 13 int n,k; 14 int a[100100]; 15 16 int ksm(int x,int p){ 17 int ret=1; 18 while(p){ 19 if(p&1) ret=ret*1ll*x%mod; 20 x=x*1ll*x%mod; 21 p=p>>1; 22 } 23 return ret; 24 } 25 26 int p[100100]; 27 int recA[100100],recB[100100]; 28 int main(){ 29 #ifdef LZT 30 freopen("in","r",stdin); 31 #endif 32 n=read(),k=read(); 33 for(int i=1;i<=n;i++) 34 a[i]=read(); 35 int m=0; 36 for(int i=n;i>=1;i--){ 37 if(a[i]){ 38 m++; 39 for(int j=1;j*j<=i;j++){ 40 if(i%j!=0) continue; 41 a[j]^=1; 42 if(j*j!=i) a[i/j]^=1; 43 } 44 } 45 } 46 if(k>=m){ 47 for(int i=1;i<=n;i++) 48 m=m*1ll*i%mod; 49 printf("%d\n",m); 50 return 0; 51 } 52 int t=ksm(n,mod-2); 53 //cout<<t<<endl; 54 p[k]=k; 55 int A=0,B=0; 56 for(int x=k+1;x<=n;x++){ 57 if(x==k+1){ 58 A=t*1ll*(n-x)%mod; 59 B=(t*1ll*x%mod*p[x-1]%mod+1)%mod; 60 recA[x]=A; 61 recB[x]=B; 62 //cout<<A<<' '<<B<<endl; 63 continue; 64 } 65 int nw=t*1ll*x%mod*A%mod; 66 nw=(1-nw+mod)%mod; 67 nw=ksm(nw,mod-2); 68 A=nw*1ll*t%mod*(n-x)%mod; 69 B=nw*1ll*(t*1ll*x%mod*B%mod+1)%mod; 70 recA[x]=A; 71 recB[x]=B; 72 //cout<<A<<' '<<B<<endl; 73 } 74 int val=B; 75 for(int i=n-1;i>=m;i--) 76 val=(recA[i]*1ll*val%mod+recB[i]%mod)%mod; 77 for(int i=1;i<=n;i++) 78 val=val*1ll*i%mod; 79 printf("%d\n",val); 80 return 0; 81 }
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 ll read(){ 6 ll x=0,f=1;char c=getchar(); 7 while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();} 8 while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();} 9 return x*f; 10 } 11 12 const int mod=100003; 13 int n,k; 14 int a[100100]; 15 16 int ksm(int x,int p){ 17 int ret=1; 18 while(p){ 19 if(p&1) ret=ret*1ll*x%mod; 20 x=x*1ll*x%mod; 21 p=p>>1; 22 } 23 return ret; 24 } 25 26 int p[100100]; 27 //int recA[100100],recB[100100]; 28 int main(){ 29 #ifdef LZT 30 freopen("in","r",stdin); 31 #endif 32 n=read(),k=read(); 33 for(int i=1;i<=n;i++) 34 a[i]=read(); 35 int m=0; 36 for(int i=n;i>=1;i--){ 37 if(a[i]){ 38 m++; 39 for(int j=1;j*j<=i;j++){ 40 if(i%j!=0) continue; 41 a[j]^=1; 42 if(j*j!=i) a[i/j]^=1; 43 } 44 } 45 } 46 if(k>=m){ 47 for(int i=1;i<=n;i++) 48 m=m*1ll*i%mod; 49 printf("%d\n",m); 50 return 0; 51 } 52 int t=ksm(n,mod-2); 53 /* 54 //cout<<t<<endl; 55 p[k]=k; 56 int A=0,B=0; 57 for(int x=k+1;x<=n;x++){ 58 if(x==k+1){ 59 A=t*1ll*(n-x)%mod; 60 B=(t*1ll*x%mod*p[x-1]%mod+1)%mod; 61 recA[x]=A; 62 recB[x]=B; 63 //cout<<A<<' '<<B<<endl; 64 continue; 65 } 66 int nw=t*1ll*x%mod*A%mod; 67 nw=(1-nw+mod)%mod; 68 nw=ksm(nw,mod-2); 69 A=nw*1ll*t%mod*(n-x)%mod; 70 B=nw*1ll*(t*1ll*x%mod*B%mod+1)%mod; 71 recA[x]=A; 72 recB[x]=B; 73 //cout<<A<<' '<<B<<endl; 74 } 75 int val=B; 76 for(int i=n-1;i>=m;i--) 77 val=(recA[i]*1ll*val%mod+recB[i]%mod)%mod; 78 for(int i=1;i<=n;i++) 79 val=val*1ll*i%mod; 80 printf("%d\n",val);*/ 81 p[n]=1; 82 for(int i=n-1;i>k;i--) 83 p[i]=((n-i)*1ll*p[i+1]%mod+n)%mod*1ll*ksm(i,mod-2)%mod; 84 int val=0; 85 for(int i=m;i>k;i--) 86 val=(val+p[i])%mod; 87 val=val+k; 88 for(int i=1;i<=n;i++) 89 val=val*1ll*i%mod; 90 printf("%d\n",val); 91 return 0; 92 }
Review
动机?
到95分为止都是自己想到的 也不是很难想
然后差分... 这个怎么想到的我也不是很清楚
(如果递推式没法推就差分一下?)