• [loj2978]杜老师


    假设所有素数从小到大依次为$p_{1},p_{2},...,p_{k}$,我们将$x$转换为一个$k$位的二进制数,其中从低到高第$i$位为1当且仅当其$p_{i}$的幂次为奇数

    不难发现以下两个性质:

    1.假设$x$和$y$转换得到的二进制数分别为$x'$和$y'$,则$xy$转换后二进制数为$x'oplus y'$

    2.$x$为完全平方数当且仅当$x$转换得到的二进制为0

    由此,实际上也就是统计$[l,r]$这些数所转换的二进制数有多少个子集结果为0

    考虑线性基,当构造得到线性基后,根据线性基有以下性质:对于线性基外任取若干个数,线性基内恰存在一种取法使得最终异或结果为0

    首先,由于线性基外的每一个数都能与线性基内的若干个数异或为0,将所有数异或起来也就得到了一种方案,同时若有两种方案,即线性基内存在若干个数异或为0,也矛盾

    由此,我们得到了方案数就是$2^{r-l+1-线性基内数的个数}$

    暴力求线性基复杂度是$o(frac{r-l+1}{omega}pi(r)^{2})$(其中$pi(r)$表示小于等于$r$的素数个数),需要优化:

    由于大于$sqrt{r}$的素因子至多只有1个,因此可以手动模拟这一次操作,具体来说遍历时在第一次出现某个大素数(大于$sqrt{r}$的素数)时记录该数,并令之后出现含有此因子的都异或该数

    这样做的复杂度降为$o(frac{r-l+1}{omega}pi(sqrt{r})^{2})$,但还是无法通过

    进一步的,暴力验证可以发现在$r-lge 6661$时,线性基一定会满,即线性基内数的个数即$[l,r]$中所有出现的素因子个数,这个可以枚举素数来计算

    最终,复杂度即$o(t(pi(r)+frac{6661pi(sqrt{r})^{2}}{omega}))$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 10000005
     4 #define mod 998244353
     5 #define L 6661
     6 #define P 446
     7 bitset<P>g,bt[L],f[P];
     8 int t,l,r,mi[N],vis[N],p[N],lst[N];
     9 int main(){
    10     mi[0]=1;
    11     for(int i=1;i<N;i++)mi[i]=2*mi[i-1]%mod;
    12     vis[1]=1;
    13     for(int i=2;i<N;i++){
    14         if (!vis[i])p[++p[0]]=i;
    15         for(int j=1;(j<=p[0])&&(i*p[j]<N);j++){
    16             vis[i*p[j]]=1;
    17             if (i%p[j]==0)break;
    18         }
    19     }
    20     scanf("%d",&t);
    21     while (t--){
    22         scanf("%d%d",&l,&r);
    23         int ans=r-l+1;
    24         if (r-l>=L){
    25             for(int i=1;p[i]<=r;i++)
    26                 if (r/p[i]>(l-1)/p[i])ans--;
    27         }
    28         else{
    29             for(int i=0;i<P;i++)f[i].reset();
    30             for(int i=l;i<=r;i++){
    31                 int k=i;
    32                 for(int j=1;j<=P;j++){
    33                     int tot=0;
    34                     while (k%p[j]==0){
    35                         tot^=1;
    36                         k/=p[j];
    37                     }
    38                     bt[i-l][j-1]=tot;
    39                 }
    40                 g=bt[i-l];
    41                 if (k>1){
    42                     if ((lst[k]<l)||(lst[k]>=i))lst[k]=0;
    43                     if (!lst[k]){
    44                         lst[k]=i;
    45                         ans--;
    46                     }
    47                     g^=bt[lst[k]-l];
    48                 }
    49                 for(int j=0;j<P;j++){
    50                     if (!g.any())break;
    51                     if (g[j]){
    52                         if (!f[j].any()){
    53                             f[j]=g;
    54                             ans--;
    55                         }
    56                         g^=f[j];
    57                     }
    58                 }
    59             } 
    60         }
    61         printf("%d
    ",mi[ans]);
    62     }
    63     return 0;
    64 } 
    View Code
  • 相关阅读:
    [国家集训队]墨墨的等式(同余最短路)
    [洛谷P2575]高手过招
    [CSP校内集训]rank
    杀人游戏(tarjan思维好题)
    骑士游戏(spfa好题)
    机房模拟测试4:计数类dp+水题+树上计数
    机房测试模拟2:模拟+数学+数位dp
    机房测试11:最小生成树(最小生成树+二分)
    机房测试模拟1(day2):矩阵+树上贪心+bfs+状压
    机房测试16:字符串专题(AC自动机+dp+kmp)
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14588594.html
Copyright © 2020-2023  润新知