【THUSC2017】杜老师

 题目描述

杜老师可是要打+∞年World Final的男人,虽然规则不允许,但是可以改啊!

但是今年WF跟THUSC的时间这么近,所以他造了一个idea就扔下不管了……

给定L,R,求从L到R的这R−L+1个数中能选出多少个不同的子集,满足子集中所有的数的乘积是一个完全平方数。特别地,空集也算一种选法,定义其乘积为1。

由于杜老师忙于跟陈老师和鏼老师一起打ACM竞赛,所以,你能帮帮杜老师写写标算吗?

输入格式

从标准输入读入数据。

每个测试点包含多组测试数据。

输入第一行包含一个正整数 T(1≤T≤100),表示测试数据组数。

接下来T行,第i+1行两个正整数Li,Ri表示第 i 组测试数据的 L,R ,保证1≤Li≤Ri≤107。

输出格式
输出到标准输出。

输出T​行,每行一个非负整数,表示一共可以选出多少个满足条件的子集,答案对998244353​取模。


 $R_{i} \le 1e7$ , $T \le 100$ , $\sum_{i=1}^{T}(R_{i}-L{i}+1) \le 6e7$

  • 题解

    • 唯一分解,把每个质数看成一个元,$mod2$意义下高斯消元设自由元个数为$d$
    • 答案就是线性相关的子集数$=2^d$;
    • 暴力$50$
    • 在$L,R$比较大的时候,直接消元会很浪费,考虑剪枝;
    • 如果$[L,R]$中出现了质因子$p$;
    • 一 ,若 $p > \sqrt R$则$p$对应位一定有基;  ->  $p^k>R  \  (k>1)$
    • 二 ,若$ p <= \lfloor \frac{R}{L} \rfloor $ 则$p$对应位一定有基;->  $( B(L) xor  B(L*p) == B(p) )$,说明$p$独立
    • 三, 若$R-L>=6e3$,则$p$对应位一定有基;  ->  ????  如果有人知道为什么的话求教
    • 大于根号的因子只有一个,特判一的;
    • 所以近距离暴力高斯消元,远距离直接计算;
    • $trick$ :线筛每个数的因子可$logR$分解因数 ,$bitset$优化,同时线性基满了就不再插入;
    • $O(R \ + \  \sum R_{i}-L_{i}  \ + \ T*(\frac{R}{64} + 6e3*log \ R) )$
    •  1 #include<bits/stdc++.h>
       2 #define ll long long
       3 using namespace std;
       4 const int N=60010,M=1e7+10,mod=998244353;
       5 int T,L[110],R[110],n,k,size,pos[N];
       6 int pt,pr[M],vis[M],v[M],visT[M];
       7 typedef bitset<500> BIT; 
       8 BIT B[500],now,pre;
       9 struct data{
      10     int x,y;
      11     bool operator <(const data&A)const{
      12         return y < A.y;
      13     }
      14 }A[N];
      15 int pw2(int y){
      16     int re=1,x=2;
      17     for(int i=y;i;i>>=1,x=(ll)x*x%mod){
      18         if(i&1)re=(ll)re*x%mod;
      19     }
      20     return re;
      21 }
      22 void get_fac(int x,BIT&y){
      23     y.reset(); 
      24     if(v[x]>k)x/=v[x];
      25     while(x!=1){
      26         int t=v[x],cnt=0;
      27         while(x%t==0&&(x/=t))cnt++;
      28         if(cnt&1)y[pos[t]]=1;
      29     }
      30 }
      31 bool ins(BIT&x){
      32     for(int i=0;i<size;i++)if(x[i]){
      33         if(B[i][i])x^=B[i];
      34         else return B[i]=x,true;
      35     }
      36     return false;
      37 }
      38 void solve1(int l,int r){
      39     int tot=0,cnt=0,tot2=0;
      40     for(int i=l;i<=r;i++)A[++cnt]=(data){i,v[i]};
      41     sort(A+1,A+cnt+1);
      42     for(int i=0;i<size;i++)B[i].reset();
      43     for(int i=1;i<=cnt;i++){
      44         get_fac(A[i].x,now); 
      45         if(A[i].y<=k){if(tot<size)tot+=ins(now);}
      46         else if(A[i].y!=A[i-1].y){tot2++;pre=now;}
      47         else {now^=pre;if(tot<size)tot+=ins(now);}
      48     } 
      49 //    printf("%d %d\n",tot,tot2);
      50     printf("%d\n",pw2(r-l+1-tot-tot2));
      51 }
      52 void solve2(int l,int r){
      53     int tot=0;
      54     for(int i=l;i<=r;i++)if(v[i]>k&&visT[v[i]]!=T){
      55         visT[v[i]]=T;
      56         tot++;
      57     }
      58     for(int i=1;i<=size;i++)if((l-1)/pr[i]<r/pr[i]&&visT[pr[i]]!=T){
      59         visT[pr[i]]=T;
      60         tot++;
      61     }
      62     printf("%d\n",pw2(r-l+1-tot));
      63 }
      64 int main(){
      65     freopen("T2.in","r",stdin);
      66     freopen("T2.out","w",stdout);
      67     scanf("%d",&T);
      68     for(int i=1;i<=T;i++)scanf("%d%d",&L[i],&R[i]),n=max(n,R[i]);
      69     k=sqrt(n); v[1]=1;
      70     for(int i=2;i<=n;i++){
      71         if(!vis[i]){
      72             v[pr[++pt]=i]=i;
      73             if(i<=k)size++,pos[i]=pt-1;
      74         }
      75         for(int j=1;j<=pt&&i*pr[j]<=n;j++){
      76             vis[i*pr[j]]=1;
      77             v[i*pr[j]]=v[i];
      78             if(i%pr[j]==0)break;
      79         }
      80     } 
      81     for(int i=1;T;i++,T--){
      82         if(R[i]-L[i]>=6000)solve2(L[i],R[i]);
      83         else solve1(L[i],R[i]);
      84     } 
      85     return 0;
      86 }
      THUSC2017D1T2

       

 

转载于:https://www.cnblogs.com/Paul-Guderian/p/10248782.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值