給你 \(l,r\),求從 \(l\) 到 \(r\) 這 \(r-l+1\) 個數中能選出多少個不一樣的子集,知足子集中全部的數的乘積是一個徹底平方數。dom
對 \(998244353\) 取模。優化
\(1\leq l,r\leq {10}^7\)spa
有 \(100\) 組數據,\(\sum r-l+1\leq 6\times {10}^7\)code
對於每一個數,求出這個數中包含了哪些出現次數爲奇數的質數。ip
那麼就能夠直接高斯消元,記矩陣的秩爲 \(r\),答案就是 \(2^{r-l+1-r}\)。能夠用 bitset 優化。get
時間複雜度爲 \(O(\frac{n\pi(n)^2}{w})\)。string
能夠發現,一個數最多有一個 \(>\sqrt r\) 的質因子。那麼對於兩個最大值因子相同的數,能夠讓第二個數的狀態異或上第一個數的狀態,這樣第二個數的狀態就只有 \(\leq \sqrt r\) 的質因子了。it
這樣就能夠讓矩陣的列的數量下降到 \(\pi(\sqrt n)\)。io
可是仍是過不了這題。function
能夠發現,當 \(r-l+1\) 足夠大的時候就能夠認爲這個矩陣滿秩了。在本題中,當 \(r-l+1>6000\) 的時候就能夠不用高斯消元直接求出答案了。
時間複雜度:\(O(\frac{T\times 6000\times \pi(\sqrt n)^2}{w})\)。
這個複雜度很鬆,實際跑起來很是快。
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<ctime> #include<functional> #include<cmath> #include<vector> #include<assert.h> #include<bitset> using namespace std; using std::min; using std::max; using std::swap; using std::sort; using std::reverse; using std::random_shuffle; using std::lower_bound; using std::upper_bound; using std::unique; using std::vector; typedef long long ll; typedef unsigned long long ull; typedef double db; typedef long double ldb; typedef std::pair<int,int> pii; typedef std::pair<ll,ll> pll; void open(const char *s){ #ifndef ONLINE_JUDGE char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout); #endif } void open2(const char *s){ #ifdef DEBUG char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout); #endif } int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;} void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');} int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;} int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;} const ll p=998244353; const int N=10000010; const int n=10000000; const int sqrtn=3162; const int size=446; typedef bitset<500> arr; ll fp(ll a,ll b) { ll s=1; for(;b;b>>=1,a=a*a%p) if(b&1) s=s*a%p; return s; } int c[N],d[N],b[N],pri[N],cnt; void sieve() { c[1]=1; for(int i=2;i<=n;i++) { if(!b[i]) { pri[++cnt]=i; d[i]=cnt; c[i]=i; } for(int j=1;j<=cnt&&i*pri[j]<=n;j++) { int v=i*pri[j]; b[v]=1; c[v]=c[i]; if(i%pri[j]==0) break; } } } void init() { sieve(); } arr get(int x) { while(c[x]>sqrtn) x/=c[x]; arr res; while(x>1) { res.flip(d[c[x]]-1); x/=c[x]; } return res; } int len,tot,tot2; void solve2(int l,int r) { tot=0; len=r-l+1; for(int i=1;i<=cnt;i++) if(r/pri[i]!=(l-1)/pri[i]) tot++; ll ans=fp(2,len-tot); printf("%lld\n",ans); } arr e[size]; int insert(arr v) { for(int i=0;i<size;i++) if(v[i]) { if(e[i][i]) v^=e[i]; else { e[i]=v; return 1; } } return 0; } pii a[10000]; arr pre; int cmp(pii a,pii b) { return a.second<b.second; } void solve() { int l,r; scanf("%d%d",&l,&r); if(r-l>6000) { solve2(l,r); return; } tot=0; tot2=0; len=r-l+1; if(l==1) l++; int m=0; for(int i=0;i<size;i++) e[i].reset(); for(int i=l;i<=r;i++) a[++m]=pii(i,c[i]); sort(a+1,a+m+1,cmp); for(int i=1;i<=m;i++) if(a[i].second<=sqrtn) { if(tot<size) if(insert(get(a[i].first))) tot++; } else if(i==1||a[i].second!=a[i-1].second) { tot2++; if(tot<size) pre=get(a[i].first); } else { if(tot<size) if(insert(get(a[i].first)^pre)) tot++; } ll ans=fp(2,len-tot-tot2); printf("%lld\n",ans); } int main() { open("dls"); init(); int t; scanf("%d",&t); while(t--) solve(); return 0; }