[BZOJ4772]显而易见的数论(数论)

4772: 显而易见的数论

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 76  Solved: 32
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

input 1
1
3 3
0 1 2

input 2
2
5 4
4 1 5 2

input 3
3
7 5
12 11 45 6 2

Sample Output

output 1

4

output 2
31

output 3
7346

HINT


Source

[Submit][Status][Discuss]

预处理即$O(1)$求$F$显然不是瓶颈,关键是g和最终答案的求法。

比较自然的思路是枚举$p_i$,$p_j$,算出它们的出现次数和贡献,累计结果。

这个分情况讨论,整数划分DP一下就好了。

https://www.cnblogs.com/xiaoxubi/p/6927810.html

然后根据一波迷之推导得出$g$是一个积性函数,这样线性筛预处理即可。

https://blog.csdn.net/v5zsq/article/details/76714310

这样时间复杂度问题方面就解决了,然而这题卡时卡空间,任何一个取模运算较多的操作都有可能超时。

可以看出$p_i\neq p_j$的常数过大,所以用$cnt$数组先统计出$a[i]$一共被累计了几次,最后一起乘起来就好了。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=l; i<=r; i++)
 4 using namespace std;
 5 
 6 const int N=2010,M=10000010,mod=1000000007;
 7 int type,n,K,tot,ans,gcd[N][N],f[N][N],sum[N],mul[N][N];
 8 int tmp[M],cnt[M],g[M],pri[M],a[M];
 9 bool jud[M];
10 
11 void add(int &x,int y){ x+=y; if (x>=mod) x-=mod; }
12 
13 void pre1(){
14     sum[n]=1;
15     rep(i,1,n) rep(j,1,n){
16         if (i==1 || j==1) f[i][j]=1;
17         else if (j==i) f[i][j]=(f[i][j-1]+1)%mod;
18             else if (j<i) f[i][j]=(f[i-j][j]+f[i][j-1])%mod;
19                 else f[i][j]=f[i][j-1];
20         sum[n-i]=f[i][i];
21     }
22 }
23 
24 void pre2(){
25     g[0]=0; g[1]=1;
26     rep(i,2,10000000){
27         if (!jud[i]) pri[++tot]=tmp[i]=i,g[i]=(2*i-2)%mod;
28         for (int j=1; j<=tot && i*pri[j]<=M; j++){
29             jud[i*pri[j]]=1;
30             if (i%pri[j]) tmp[i*pri[j]]=pri[j],g[i*pri[j]]=g[i]*g[pri[j]]%mod;
31             else{
32                 tmp[i*pri[j]]=tmp[i]*pri[j];
33                 if (tmp[i]!=i) g[i*pri[j]]=1ll*g[i/tmp[i]]*g[tmp[i]*pri[j]]%mod;
34                     else g[i*pri[j]]=(1ll*g[i]*pri[j]+i*pri[j]-i)%mod;
35                 break;
36             }
37         }
38     }
39 }
40 
41 void pre3(){
42     rep(i,1,n) gcd[i][0]=gcd[0][i]=gcd[i][i]=i,gcd[1][i]=gcd[i][1]=1;
43     rep(i,2,n) rep(j,2,i){
44         if (!gcd[i][j]) gcd[i][j]=gcd[j][i-j];
45         gcd[j][i]=gcd[i][j];
46     }
47     rep(i,1,n){
48         mul[i][0]=1;
49         rep(j,1,n) mul[i][j]=1ll*mul[i][j-1]*i%K;
50     }
51 }
52 
53 int F(int pi,int pj){
54     if (type==1) return 1%K;
55     if (type==2) return gcd[pi][pj]%K;
56     if (type==3) return (mul[pi][pj]+mul[pj][pi]+(pi^pj))%K;
57     return 0;
58 }
59 
60 int main(){
61     freopen("bzoj4772.in","r",stdin);
62     freopen("bzoj4772.out","w",stdout);
63     scanf("%d%d%d",&type,&n,&K);
64     for (int i=0; i<K; i++) scanf("%d",&a[i]);
65     pre1(); pre2(); pre3();
66     /*
67     rep(i,1,n) rep(j,i+1,n-i)
68         for (int muli=1; i*muli<=n-j; muli++)
69             for (int mulj=1; i*muli+j*mulj<=n; mulj++){
70                 int t=(sum[muli*i+mulj*j]-sum[(muli+1)*i+mulj*j]-sum[muli*i+(mulj+1)*j]+sum[(muli+1)*i+(mulj+1)*j])%mod;
71                 add(cnt[F(i,j)],1ll*muli*mulj*(t+mod)%mod);
72             }
73     */
74     rep(i,1,n) rep(j,i+1,n-i)
75         for (int muli=1; i*muli<=n-j; muli++)
76             for (int mulj=1; i*muli+j*mulj<=n; mulj++) add(cnt[F(i,j)],sum[muli*i+mulj*j]);
77     for (int i=0; i<K; i++) add(ans,1ll*g[a[i]]*cnt[i]%mod);
78     rep(i,1,n) for (int muli=1; i*muli<=n; muli++)
79         add(ans,(1ll*g[a[F(i,i)]]*((muli*(muli-1)/2)%mod))%mod*(sum[muli*i]-sum[(muli+1)*i]+mod)%mod);
80     printf("%d\n",ans);
81     return 0;
82 }

 

posted @ 2018-04-24 17:25  HocRiser  阅读(371)  评论(0编辑  收藏  举报