據說LOJ傳了THUSC題趕忙上去看一波ios
隨便點了一題都不會作想了很久纔會寫暴力爆了一發過了...git
LOJ #2978spa
$ T$次詢問,每次詢問$ L,R$,問有多少種選取區間中數的方案使得選出的數的積爲徹底平方數code
$ T \leq 100,R \leq 10^7 \sum\limits R-L \leq 6·10^7$blog
時限$ 5s$排序
隨便寫個暴力發現答案都是$2$的若干次冪ip
首先對於每一個數,每一個質因子出現的次數顯然只有奇偶性是有用的get
用一個$ bitset$存儲每一個數中每一個質因數的出現次數的奇偶性string
則問題轉化成取若干個數使得異或和爲$ 0$it
用線性基維護這個問題
答案則爲$ 2^{自由基的數量}$
其中自由基就是能夠被其餘基所表示的基
直接這麼暴力複雜度太大
考慮若一個質因數的平方超過$ 10^7$那它不可能在一個數中出現兩次
所以咱們只統計前$ \sqrt{10^7}$個數中的質因數(446個)的$ bitset$
統計答案的時候咱們先將區間內數按其最大質因數排序(若一個數的最大質因數不超過 $\sqrt{10^7}$則認爲是0)
對於一段最大質因數相同的區間,咱們欽定第一個數爲非自由基
則這段區間的其餘擁有這個質因數的數能夠異或上這個欽定的非自由基
以起到消掉這個額外質因數的效果
這樣暴力作的複雜度是$ O(6·10^7·450·\frac{450}{64})$的
顯然過不了
若是加個剪枝:若當前線性基已滿則直接跳出判斷 就能過了...
雖然跑的超級慢...
這題有個科技:
若$ R-L+1$超過了一個定值(可定爲$ 2 \sqrt{10^7}$),則對每一個質數,咱們只要選一個數做爲這個數的基底
而後全部其餘非基底的區間中的數都能被這些基底表示
即答案爲$ 2^{R-L+1-出現過的質數數量}$
而後就跑的飛快了...
去掉Solve就是暴力
#include<ctime> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<vector> #include<bitset> #define p 998244353 #define file(x)freopen(x".in","r",stdin);freopen(x".out","w",stdout) #define rt register int #define l putchar('\n') #define ll long long #define r read() using namespace std; inline ll read(){ ll x=0;char zf=1;char ch=getchar(); while(ch!='-'&&!isdigit(ch))ch=getchar(); if(ch=='-')zf=-1,ch=getchar(); while(isdigit(ch))x=x*10+ch-'0',ch=getchar();return x*zf; } void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);} void writeln(const ll y){write(y);putchar('\n');} int k,m,n,x,y,z,cnt,ans,val=10000000; bool pri[10000010];int ss[4010],id[4010],lp[10000010],zs[1000010],tot; bitset<449>a[449]; int q[10000010],sl; bitset<449>make(int x){ bitset<449>A; if(lp[x])x/=lp[x]; for(rt i=1;ss[i]*ss[i]<=x&&i<=cnt;i++)while(x%ss[i]==0) A.flip(i),x/=ss[i]; if(x>1)A.flip(id[x]); return A; } vector<int>jw[5000010]; void solve(int L,int R){ int gs=R-L+1; for(rt i=1;i<=tot&&zs[i]<=R;i++)if(R/zs[i]!=(L-1)/zs[i])gs--; int ans=1; for(rt x=2,i=gs;i;i>>=1,x=1ll*x*x%p)if(i&1) ans=1ll*ans*x%p;writeln(ans); } int main(){ n=r;if(n<=10)val=1000000; const int v=sqrt(val); for(rt i=2;i<=val;i++)if(!pri[i]){ if(i<=v)ss[++cnt]=i,id[i]=cnt; zs[++tot]=i; if(i<=v)for(rt j=i*i;j<=val;j+=i)pri[j]=1; if(i>v)for(rt j=i;j<=val;j+=i)lp[j]=i; } bitset<449>now; while(n--){ memset(a,0,sizeof(a)); int L=r,R=r,ans=1;int len=0; if(R-L>7000){ solve(L,R); continue; } for(rt i=L;i<=R;i++)if(lp[i]<=5000000)jw[lp[i]].push_back(i); for(rt i=L;i<=R;i++)if(lp[i]<=5000000){ for(rt j=0;j<jw[lp[i]].size();j++)q[++len]=jw[lp[i]][j]; jw[lp[i]].clear(); } sl=0;now&=0; for(rt i=1;i<=len;i++){ const int v=q[i]; if(lp[v]!=lp[q[i-1]]&&i>1)now=make(v); else { if(sl==cnt){ans=1ll*ans*2%p;continue;} bitset<449>g=make(v)^now; if(g.count()==0){ans=1ll*ans*2%p;continue;} for(rt j=448;j>=0;j--)if(g[j]){ if(a[j][j]){ if(g==a[j]){ans=1ll*ans*2%p;break;} g^=a[j]; } else {a[j]=g;sl++;break;} } } } writeln(ans); } return 0; }