bzoj3434 [Wc2014]时空穿梭

式子的推导网上有很多dalao写的都很好,就不再赘述了。

有两点是我没有想到的,再次写一下。

首先就是初始的式子。不知道直角三角形斜边上整数点个数=gcd(a,b)+1,更没有拓展到多维。

第二就是划出来60分的式子之后的优化,把后边的关于T的多项式的系数通过O(n2)时间算了出来$O(n^2*m)->O(n^3*\sqrt{m})$

十分巧妙。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define N 100500
 7 #define mod 10007
 8 using namespace std;
 9 int C[N][25],mu[N],h[N],nn,prime[N],tot,vis[N],g[25][N],pw[N][25],sum[25][25][N];
10 void init(){
11     C[0][0]=1;
12     for(int i=1;i<=100000;i++){
13         C[i][0]=1;
14         for(int j=1;j<=20&&j<=i;j++)
15             C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
16     }
17     mu[1]=1;h[++nn]=1;
18     for(int i=2;i<=100000;i++){
19         if(!vis[i]){
20             prime[++tot]=i;
21             mu[i]=-1;
22         }
23         for(int j=1;j<=tot&&i*prime[j]<=100000;j++){
24             vis[i*prime[j]]=1;
25             if(i%prime[j]==0){
26                 mu[i*prime[j]]=0;
27                 break;
28             }
29             mu[i*prime[j]]=-mu[i];
30         }
31         if(mu[i])h[++nn]=i;
32     }
33     for(int k=2;k<=20;k++){
34         for(int i=1;i<=100000;i++)
35             for(int j=1;j<=nn&&h[j]*i<=100000;j++)
36                 (g[k][i*h[j]]+=mu[h[j]]*C[i-1][k-2]+mod)%=mod;
37     }
38     for(int i=1;i<=100000;i++){
39         pw[i][0]=1;
40         for(int j=1;j<=11;j++)pw[i][j]=pw[i][j-1]*i%mod;
41     }
42     for(int k=1;k<=20;k++)
43         for(int j=0;j<=11;j++)
44             for(int i=1;i<=100000;i++)
45                 sum[k][j][i]=(sum[k][j][i-1]+g[k][i]*pw[i][j]%mod)%mod;
46 }
47 int T,n,c,m[25],ans,f[25];
48 void work(int x){
49     memset(f,0,sizeof f);f[0]=1;
50     for(int i=1;i<=n;i++){
51         for(int j=i;j>0;j--)
52             f[j]=(f[j]*2%mod*m[i]%mod-f[j-1]*(m[i]/x+1)%mod+mod)%mod;
53         f[0]=f[0]*2*m[i]%mod;
54     }
55 }
56 int main(){
57     init();
58     scanf("%d",&T);
59     while(T--){
60         scanf("%d%d",&n,&c);ans=0;
61         for(int i=1;i<=n;i++)scanf("%d",&m[i]);
62         sort(m+1,m+n+1);
63         for(int i=1,pos;i<=m[1];i=pos+1){
64             pos=N;
65             for(int j=1;j<=n;j++)pos=min(pos,m[j]/(m[j]/i));
66             int now=1;
67             for(int j=1;j<=n;j++)
68                 now=(now*(m[j]/i)%mod*5004%mod);
69             work(i);
70             for(int j=0;j<=n;j++)
71                 (ans+=now*f[j]%mod*(sum[c][j][pos]-sum[c][j][i-1]+mod)%mod)%=mod;
72         }
73         printf("%d\n",ans);
74     }
75     return 0;
76 }
View Code

 

posted @ 2018-01-06 10:46  Ren_Ivan  阅读(164)  评论(0编辑  收藏  举报