博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【THUSC2017】【LOJ2978】杜老师 高斯消元
阅读量:4354 次
发布时间:2019-06-07

本文共 2744 字,大约阅读时间需要 9 分钟。

题目大意

  给你 \(l,r\),求从 \(l\)\(r\)\(r-l+1\) 个数中能选出多少个不同的子集,满足子集中所有的数的乘积是一个完全平方数。

  对 \(998244353\) 取模。

  \(1\leq l,r\leq {10}^7\)

  有 \(100\) 组数据,\(\sum r-l+1\leq 6\times {10}^7\)

题解

  对于每个数,求出这个数中包含了哪些出现次数为奇数的质数。

  那么就可以直接高斯消元,记矩阵的秩为 \(r\),答案就是 \(2^{r-l+1-r}\)。可以用 bitset 优化。

  时间复杂度为 \(O(\frac{n\pi(n)^2}{w})\)

  可以发现,一个数最多有一个 \(>\sqrt r\) 的质因子。那么对于两个最大值因子相同的数,可以让第二个数的状态异或上第一个数的状态,这样第二个数的状态就只有 \(\leq \sqrt r\) 的质因子了。

  这样就可以让矩阵的列的数量降低到 \(\pi(\sqrt n)\)

  但是还是过不了这题。

  可以发现,当 \(r-l+1\) 足够大的时候就可以认为这个矩阵满秩了。在本题中,当 \(r-l+1>6000\) 的时候就可以不用高斯消元直接求出答案了。

  时间复杂度:\(O(\frac{T\times 6000\times \pi(\sqrt n)^2}{w})\)

  这个复杂度很松,实际跑起来非常快。

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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
pii;typedef std::pair
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;}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
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

转载于:https://www.cnblogs.com/ywwyww/p/10294451.html

你可能感兴趣的文章
STM32 keil printf的使用
查看>>
C++类相关
查看>>
Sql分隔字符串方法--split
查看>>
通过meta设置防止浏览器缓存
查看>>
angularJS 中的two-way data binding.
查看>>
MediaPlayer简易应用
查看>>
Ubuntu上完美视频播放软件XBMC
查看>>
idea创建maven项目的一点关键
查看>>
python函数:递归
查看>>
nodejs
查看>>
DIV+CSS 斜线效果
查看>>
虚拟机访问共享空间的身份验证问题
查看>>
ble低功耗蓝牙GATT应用协议
查看>>
ThinkPHP的url简化
查看>>
List<T> 类相关排序
查看>>
Win2012R2 AD主域控登录密码忘记
查看>>
php增加自动刷新当前页面
查看>>
[阿里]逆序打印整数,要求递归实现
查看>>
TCP小结
查看>>
转 java的JsonObject对象提取值
查看>>