首页 > 代码库 > 3.5~3.6联考题解

3.5~3.6联考题解

本来想加个密码的,后来一想全HE就咱们这几个人,外省的dalao愿看也没事儿,就公开算了,省得加密码各种麻烦。

先补这两天的题解吧……如果有空的话我可能会把上次联考的题解补上= =(中午没睡觉,现在困得很,根本没法写题……

算算算number

感觉出题人出题的时候zz了吧,费了半天搞出来一个极其麻烦还跑得慢的做法是要闹哪样啊……

算了,写一写$O(nk)$做法的推导过程吧,虽然其实非常好推……

首先定义$S_i$表示到$1~i$位置的前缀和,并且规定$S_0=0$,那么

\begin{align}Ans_i=&\sum_{j=0}^{i-1}\left(S_i-S_j\right)^k\\=&\sum_{j=0}^{i-1}\sum_{x=0}^k C_k^xS_i^x\left(-S_j\right)^{k-x}\left(二项式定理\right)\\=&\sum_{x=0}^k C_k^x S_i^x\sum_{j=0}^{i-1}\left(-S_j\right)^{k-x}\end{align}

然后就很好搞了,首先枚举$x$,然后维护$\left(-S_j\right)^{k-x}$的前缀和即可。组合数是可以直接一边算一边递推的,不需要再预处理了。

直接算是$O(nk\log k)$的,加上一些线性预处理逆元之类的技巧就可以降到$O(nk+n\log p)$了,实测极限数据只需要不到1.3s就可以出解,并且不需要利用数据随机这个性质。

技术分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn=50010,p=1000000007;
 6 int qpow(int,int);
 7 int fac[maxn],fac_inv[maxn],inv[maxn];
 8 int T,n,k,s[maxn],s_k[maxn],s_inv[maxn],t[maxn],a[maxn],ans[maxn];
 9 int main(){
10     fac[0]=fac_inv[0]=1;
11     for(int i=1;i<=50001;i++)fac[i]=(long long)fac[i-1]*i%p;
12     fac_inv[50001]=qpow(fac[50001],p-2);
13     for(int i=50001-1;i;i--)fac_inv[i]=(long long)fac_inv[i+1]*(i+1)%p;
14     for(int i=1;i<=50001;i++)inv[i]=(long long)fac[i-1]*fac_inv[i]%p;
15     scanf("%d",&T);
16     while(T--){
17         memset(s,0,sizeof(s));
18         memset(ans,0,sizeof(ans));
19         scanf("%d%d",&n,&k);
20         for(int i=1;i<=n;i++){
21             scanf("%1d",&s[i]);
22             s[i]+=s[i-1];
23             s_k[i]=qpow(s[i],k);
24             s_inv[i]=qpow(s[i],p-2);
25         }
26         fill(t,t+n+1,1);
27         for(int x=0,C=1;x<=k;x++){
28             copy(t,t+n+1,a);
29             for(int i=1;i<=n;i++){
30                 a[i]=(a[i]+a[i-1])%p;
31                 ans[i]=(ans[i]+(long long)C*s_k[i]%p*a[i-1]%p)%p;
32             }
33             for(int i=0;i<=n;i++){
34                 t[i]=(long long)t[i]*((p-s[i])%p)%p;
35                 s_k[i]=(long long)s_k[i]*s_inv[i]%p;
36             }
37             C=(long long)C*(k-x)%p*inv[x+1]%p;
38         }
39         for(int i=1;i<=n;i++)printf("%d ",ans[i]);
40         printf("\n");
41     }
42     return 0;
43 }
44 int qpow(int a,int b){
45     int ans=1;
46     for(;b;b>>=1,a=(long long)a*a%p)if(b&1)ans=(long long)ans*a%p;
47     return ans;
48 }
49 /*
50 2
51 10 2
52 3672415495
53 10 2
54 9040607879
55 Answer:
56 9 117 474 634 1066 1200 2075 3043 6238 8668
57 81 81 201 201 633 633 1690 3802 6539 11435
58 */
View Code

所以你们看,这题就是个基本的二项式定理,换句话说就是比较水的高考题……

买买买buy

T(o)B(e)C(ompleted)……

树树树mst

还没有去学Boruvka算法……TBC……

 

Day2的三道题期待中……

3.5~3.6联考题解