51nod1026 矩阵中不重复的元素 V2

$n \leq 500000,m \leq 500000$的矩阵,第一行第一列是$a^b,2 \leq a,b \leq 500000$,如果一个数是$i^j$那他右边是$i^{j+1}$,下面是${i+1}^{j}$,问这个矩阵里有多少不同的数字。

把数字化成“基”来统筹统计一些重复情况。意思就是:$a=\prod_{i=1}^{k}p_i^{b_i}$,其中$gcd(b_1,b_2,...,b_k)=1$,那么这些$a$就可以当基,他的若干次幂在比他小的行中一定不会出现,而他的平方,三次方,这些行可能会跟他有部分重复。因此这些行单独拿出来考虑。可以看一下次数:

$a^{1*1} \ \ a^{1*2} \ \ a^{1*3}...$

$a^{2*1} \ \ a^{2*2} \ \ a^{2*3}...$

$a^{3*1} \ \ a^{3*2} \ \ a^{3*3}...$

如此,只需要在这样的矩形里的一段连续行中去重就可以了。一次考虑一个记,元素总数是$log_an*m$的,但总的元素总数仍是$n*m$的。

可以观察到,随着基变大,这个抽象出来的矩形的连续行(叫$[L,R]$)的$L$和$R$都会变小。而这个矩形的数字范围只有$mlogn$,可以开个桶来算每次多出或损失的行。总复杂度变成这个矩形的元素总数$mlogn$。

V3暂时不会QAQ是用容斥的观点进行搜索+剪枝的,希望能回来填坑。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 //#include<time.h>
 5 //#include<complex>
 6 //#include<set>
 7 #include<queue>
 8 //#include<vector>
 9 #include<algorithm>
10 #include<stdlib.h>
11 using namespace std;
12 
13 #define LL long long
14 int qread()
15 {
16     char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
17     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
18 }
19 
20 //Pay attention to '-' , LL and double of qread!!!!
21 
22 int n,m,a,b;
23 #define maxn 1000011
24 #define maxm 10000011
25 
26 //int prime[maxn],lp,xx[maxn]; bool notprime[maxn];
27 //void makeprime(int n)
28 //{
29 //    lp=0;
30 //    for (int i=2;i<=n;i++)
31 //    {
32 //        if (!notprime[i]) {prime[++lp]=i; xx[i]=i;}
33 //        for (int tmp,j=1;j<=lp && 1ll*i*prime[j]<=n;j++)
34 //        {
35 //            notprime[tmp=i*prime[j]]=1; xx[tmp]=prime[j];
36 //            if (!(i%prime[j])) break;
37 //        }
38 //    }
39 //}
40 
41 int cnt[maxm]; bool vis[maxn];
42 int main()
43 {
44     m=qread(); n=qread(); a=qread(); b=qread(); int N=a+n-1,M=b+m-1;
45 //    makeprime(a+n);
46     
47     int L=0,R=20; while ((1<<L)<a) vis[1<<L]=1,L++; while ((1<<R)>N) R--;
48 //    cout<<L<<' '<<R<<endl;
49     for (int i=L;i<=R;i++) vis[1<<i]=1;
50     LL ans=0; int now=0;
51     for (int j=L,tmp;j<=R;j++)
52         for (int k=b;k<=M;k++)
53         {
54             if (cnt[tmp=j*k]==0) now++;
55             cnt[tmp]++;
56         }
57     ans+=now;
58     for (int i=3;i<=N;i++) if (!vis[i])
59     {
60         int nl=0,nr=0; LL tmp=1;
61         for (;tmp<a;tmp*=i,nl++) vis[tmp]=1;
62         nr=nl; for (;tmp<=N;tmp*=i,nr++) vis[tmp]=1; nr--;
63 //        cout<<nl<<' '<<nr<<endl;
64         for (int j=L-1;j>=nl;j--)
65             for (int k=b;k<=M;k++)
66             {
67                 if (cnt[tmp=j*k]==0) now++;
68                 cnt[tmp]++;
69             }
70         L=nl;
71         for (int j=R;j>nr;j--)
72             for (int k=b;k<=M;k++)
73             {
74                 cnt[tmp=j*k]--;
75                 if (cnt[tmp]==0) now--;
76             }
77         R=nr;
78         ans+=now;
79     }
80     printf("%lld\n",ans);
81     return 0;
82 }
View Code

 

posted @ 2018-06-10 21:00  Blue233333  阅读(349)  评论(0编辑  收藏  举报