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 }
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分为止都是自己想到的 也不是很难想

然后差分... 这个怎么想到的我也不是很清楚

(如果递推式没法推就差分一下?)

posted @ 2018-07-27 17:44  wawawa8  阅读(198)  评论(0编辑  收藏  举报