这是个很是有趣的数学题啦...node
其实大概推一推式子就能获得一个信息,就是答案必定是$2$的整数次幂,而且其实答案就是$2^{R-L+1-sum}$,其中$sum$表示有多少个数不能用$L-i-1$的数表达出来。ios
另外,根据寿司晚宴那道题给予的启发,咱们只须要统计质数小于$\sqrt {10^7}$的就能够了,而后打一个表就能够知道,一共大概有$450$个左右。测试
那么$70$分的部分分就很容易到手了。优化
咱们能够经过$O(n)$的时间复杂度,预处理出$10^7$之内的全部数的最大质因子,显然,每一个数大于$\sqrt{10^7}$的质因子最多只有一个。spa
那么能够分开考虑,若是没有大于$\sqrt{10^7}$的质因子,那么就能够用$bitset$维护一下每一个质因子在选取的同时须要选择哪些其余比他大的质因子,以及如今须要选择什么质因子。code
而后还有就是须要把全部的在$[L,R]$以内的数,按照最大质因子的大小排序,这样是为了保证在更新到$x$的时候,比$x$小的质因子都已经出现过了,或者不会再出现了,或者出现的时候再来更新答案。blog
而后每次$O(\frac{450\times 450}{32})$的时间(跑不满,大概均摊下来每次询问的总时间是$O(\frac{450^3}{32})$上下的),来验证可否更新答案,也就是可否被选出了更新答案,具体实现相似高斯消元。排序
而后若是存在比$\sqrt{10^7}$大的质因子,那么就把这个质因子去掉。get
若是没存在过这个质因子,那么把这个数能分解出来的小于$\sqrt{10^7}$的质因子所有记录下来,而且这个数不能用来更新答案。数学
若是存在过这个质因子,那么上面必定处理过了上一个包含这个质因子的数的小于$\sqrt{10^7}$的质因子,而后用两个$bitset$抑或一下,也就是说这个质因子必须被消掉,而后再重复进行最上面没有大于$\sqrt{10^7}$的质因子的操做便可。
而后这个东西的正确性显然,由于其实全部包含数$x$的能成为彻底平方数的方案都是同构的,也就是从某个方案加上一个乘积是彻底平方数的方案转移过来的,全部只须要验证一个方案可否知足便可,也就是说能不能经过前面某些不一样的质因子把相同的东西彻底消去。
这个是$70$分的东西,由于算上排序等操做,一次询问的总时间复杂度是$O(\frac{450^3}{32}+(R-L+1)\log {(R-L+1)}+(R-L+1)\times \frac{500}{32})$的。
这个东西彻底没有办法优化了...
而后能够经过一些奇思妙想拿到满分。(其实只须要加上$11,12$测试点的特判就能够了...)
也就是说,若是$R-L+1$的区间大于$2\times \sqrt{10^7}$的话,就会在这段区间内包含所有的$1\sim \sqrt{10^7}$之内的全部质因子,经过消元的话,必定能够获得所有的数字,除非这个数的是质数,而且只在这点区间内只出现一次。
具体证实的话,我也不会很会啊...(由于我复现的时候才写了$70$分啊)
而后就没了...
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <cstdlib> #include <queue> #include <iostream> #include <bitset> using namespace std; #define N 10000005 #define ll long long #define mod 998244353 struct node { int x,y; node(){} node(int a,int b){x=a,y=b;} inline bool operator < (const node &a) const {return y==a.y?x<a.x:y<a.y;} }a[N]; bitset<455>b[455],now,tmp; int ans,L,R,pri[N],t[N],vis[N],idx[N],cnt,tot,block,size;bool f[N]; void init() { t[1]=1; for(int i=2;i<=10000000;i++) { if(!vis[i])pri[++cnt]=i,t[i]=i,idx[i]=cnt,size+=(i<=block); for(int j=1;j<=cnt&&pri[j]*i<=10000000;j++) { vis[pri[j]*i]=1;t[pri[j]*i]=max(pri[j],t[i]); if(i%pri[j]==0)break; } } } int get_fac(int x,bitset<455> &now) { bool flag=0;now.reset(); if(t[x]>block)x/=t[x]; while(x!=1) { int j=t[x],cnt=0; while(x%j==0)x/=j,cnt++; if(cnt&1) { now[idx[j]]=1; flag=1; } }return flag; } int get_now() { for(int i=1;i<=size;i++) if(now[i]) if(b[i][i])now^=b[i]; else return b[i]=now,1; return 0; } int q_pow(int x,int n){int ret=1;for(;n;n>>=1,x=(ll)x*x%mod)if(n&1)ret=(ll)ret*x%mod;return ret;} int solve(int L,int R) { int ret1=0,ret2=0;tot=0; for(int i=max(2,L);i<=R;i++)a[++tot]=node(i,t[i]); sort(a+1,a+tot+1); for(int i=1;i<=size;i++)b[i].reset(); for(int i=1;i<=tot;i++) { if(a[i].y<=block) { if(ret1<=size) if(get_fac(a[i].x,now)) ret1+=get_now(); }else if(a[i].y!=a[i-1].y) { ret2++; if(ret1<=size)get_fac(a[i].x,tmp); }else if(ret1<=size) { get_fac(a[i].x,now); now^=tmp;ret1+=get_now(); } } return q_pow(2,R-L+1-ret1-ret2); } int solve2(int L,int R) { int ret=0; for(int i=2;i<=R;i++) if(!vis[i]&&(R/i)>((L-1)/i))ret++; return q_pow(2,R-L+1-ret); } int main() { block=sqrt(10000000)+1; int T;scanf("%d",&T);init(); while(T--) { scanf("%d%d",&L,&R); if(R-L<=100000)printf("%d\n",solve(L,R)); else printf("%d\n",solve2(L,R)); } }