$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 ",ans); 81 return 0; 82 }