這是個很是有趣的數學題啦...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)); } }