1. 程式人生 > >bzoj 4872 [Shoi2017]分手是祝願

bzoj 4872 [Shoi2017]分手是祝願

idt width char code lan int return stdin 是我

題面

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 }
95分的代碼 技術分享圖片
 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 }
100分的代碼

Review

動機?

到95分為止都是自己想到的 也不是很難想

然後差分... 這個怎麽想到的我也不是很清楚

(如果遞推式沒法推就差分一下?)

bzoj 4872 [Shoi2017]分手是祝願