CF895C: Square Subsets && 【BZOJ2844】albus就是要第一个出场

这两道题很类似,都是线性基的计数问题,解题的核心思想也一样。

CF895C Square Subsets

题目链接

题意

给定\(n\)个数,求多少种选数方案使得选出来的数乘积为完全平方数。\(n\leq 100000,a_i\leq70\)。

完全平方数的本质就是每个质因子的次数为偶数。

所以我们将每一个数唯一分解,然后记录每个质因子的奇偶状态,就得到了一个个01串。问题就变成了有多少个集合中的数异或为0。

我们建好线性基,设线性基的秩为\(m\),则答案就是\(2^{n-m}-1\)。再判线性基能否组成0,如果能,答案再\(+1\)

因为线性基中的\(m\)个元素是线性无关的,并且可以表达出其他数的所有线性组合,所以其他\(2^{n-m}-1\)(减掉都不选的一种情况)的所有数都能在线性基中找到唯一的一个组合与之异或起来为0。

代码:

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. using namespace std;
  4. int n;
  5. ll p[50],cnt;
  6. bool Insert(ll x) {
  7. for(int i=20;i>=0;i--) {
  8. if(!(x>>i)&1) continue ;
  9. if(!p[i]) return p[i]=x,1;
  10. x^=p[i];
  11. }
  12. return 0;
  13. }
  14. ll pri[100];
  15. bool vis[100];
  16. void pre() {
  17. for(int i=2;i<=70;i++) {
  18. if(!vis[i]) pri[++pri[0]]=i;
  19. for(int j=1;j<=pri[0]&&i*pri[j]<=70;j++) {
  20. vis[i*pri[j]]=1;
  21. if(i%pri[j]==0) break;
  22. }
  23. }
  24. }
  25. void break_down(ll v) {
  26. ll x=0;
  27. for(int i=1;i<=pri[0];i++) {
  28. while(v%pri[i]==0) {
  29. x^=1<<i;
  30. v/=pri[i];
  31. }
  32. }
  33. if(!Insert(x)) cnt++;
  34. }
  35. int main() {
  36. pre();
  37. scanf("%d",&n);
  38. ll a;
  39. for(int i=1;i<=n;i++) {
  40. scanf("%lld",&a);
  41. break_down(a);
  42. }
  43. ll t=2,ans=1;
  44. for(;cnt;cnt>>=1,t=t*t%1000000007) {
  45. if(cnt&1)ans=ans*t%1000000007;
  46. }
  47. cout<<(ans-1+1000000007)%1000000007;
  48. return 0;
  49. }

【BZOJ2844】albus就是要第一个出场

题目链接

我们就是要求比\(Q\)小的集合有多少个。

和上一道题一样,我们就是要求比\(Q\)小,且能被线性基表示出来的数有多少个,我们设为\(lower\),则答案为\(lower\cdot 2^{n-m}+1\)。

问题其实就是求\(\leq Q-1\)的的最大的数的\(Rank\)。

我的实现方式不太一样。我们就找\(\leq Q-1\)的数的数量。\(\leq Q-1\)一定是从高到低的前\(i-1\)位相同,第\(i\)位小一些,后面的几位随便。于是我们就考虑\(Q\)的前\(i\)位,我们设为\(Q'\),然后将所有数的前\(i\)位建线性基。问题就变成求有多少种方法能组合出\(Q'\)。

这样做复杂度要比网上的一般写法多一个\(log\),不过个人感觉好理解些。

代码:

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. #define N 100005
  4. #define mod 10086
  5. using namespace std;
  6. inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
  7. int n;
  8. int p[35],a[N];
  9. int Q;
  10. bool Insert(int a) {
  11. for(int i=30;i>=0;i--) {
  12. if(a&(1<<i)) {
  13. if(!p[i]) return p[i]=a,1;
  14. else a^=p[i];
  15. }
  16. }
  17. return 0;
  18. }
  19. int cnt;
  20. void build(int k) {
  21. cnt=0;
  22. memset(p,0,sizeof(p));
  23. for(int i=1;i<=n;i++) {
  24. cnt+=Insert(a[i]>>k);
  25. }
  26. }
  27. ll ans;
  28. ll pw[N];
  29. int main() {
  30. n=Get();
  31. pw[0]=1;
  32. for(int i=1;i<=n;i++) pw[i]=(pw[i-1]<<1)%mod;
  33. for(int i=1;i<=n;i++) a[i]=Get();
  34. Q=Get();
  35. for(int i=30;i>=0;i--) {
  36. if(Q&(1<<i)) {
  37. build(i);
  38. if(!Insert((Q>>i)^1)) {
  39. (ans+=pw[n-cnt])%=mod;
  40. }
  41. }
  42. }
  43. cout<<(ans+1)%mod;
  44. return 0;
  45. }

CF895C: Square Subsets && 【BZOJ2844】albus就是要第一个出场的更多相关文章

  1. BZOJ2844: albus就是要第一个出场

    Description 已知一个长度为n的正整数序列A(下标从1开始), 令 S = { x | 1 <= x <= n }, S 的幂集2^S定义为S 所有子集构成的集合. 定义映射 f ...

  2. BZOJ2844: albus就是要第一个出场(线性基)

    Time Limit: 6 Sec  Memory Limit: 128 MBSubmit: 2054  Solved: 850[Submit][Status][Discuss] Descriptio ...

  3. bzoj千题计划195:bzoj2844: albus就是要第一个出场

    http://www.lydsy.com/JudgeOnline/problem.php?id=2844 题意:给定 n个数,把它的所有子集(可以为空)的异或值从小到大排序得到序列 B,请问 Q 在  ...

  4. 【贪心】【线性基】bzoj2844 albus就是要第一个出场

    引用题解:http://blog.csdn.net/PoPoQQQ/article/details/39829237 注意评论区. #include<cstdio> using names ...

  5. 【线性基】bzoj2844: albus就是要第一个出场

    线性基求可重rank 题目描述 给定 n 个数 $\{ a_i \}$ ,以及数 $x$. 将 $\{ a_i \}$​ 的所有子集(包括空集)的异或值从小到大排序,得到 $\{ b_i \} $. ...

  6. 【BZOJ2844】albus就是要第一个出场 高斯消元求线性基

    [BZOJ2844]albus就是要第一个出场 Description 已知一个长度为n的正整数序列A(下标从1开始), 令 S = { x | 1 <= x <= n }, S 的幂集2 ...

  7. BZOJ 2844: albus就是要第一个出场 [高斯消元XOR 线性基]

    2844: albus就是要第一个出场 题意:给定一个n个数的集合S和一个数x,求x在S的$2^n$个子集从小到大的异或和序列中最早出现的位置 一开始看错题了...人家要求的是x第一次出现位置不是第x ...

  8. BZOJ 2844: albus就是要第一个出场

    2844: albus就是要第一个出场 Time Limit: 6 Sec  Memory Limit: 128 MBSubmit: 1134  Solved: 481[Submit][Status] ...

  9. 2844: albus就是要第一个出场

    2844: albus就是要第一个出场 链接 分析: 和HDU3949差不多互逆,这里需要加上相同的数. 结论:所有数任意异或,构成的数出现一样的次数,次数为$2^{n-cnt}$,cnt为线性基的大 ...

随机推荐

  1. wepack---预打包dll

    一.前言 今天被问到,怎么实现webpack快速打包?话说距离上次手动配置webpack已经过去很长时间了,现在webpack都出到4.0版本了,号称零配置,还没来得及好好感受一下. ‘不就是公共模块 ...

  2. JavaWeb学习(二十九)———— 事务

    一.事务的概念 事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功. 例如:A——B转帐,对应于如下两条sql语句  update from account set mone ...

  3. C# GDI+编程之剖析startAngle和sweepAngle

    以DrawArc为例,它有一种形式如下的构造函数 public void DrawArc(Pen pen, Rectangle rect, float startAngle, float sweepA ...

  4. Linux tar 命令用法

    tar 命令可以为linux的文件和目录创建档案.利用 tar,可以为某一特定文件创建档案(备份文件),也可以在档案中改变文件,或者向档案中加入新的文件.tar 最初被用来在磁带上创建档案,现在,用户 ...

  5. net4log 日志管理

    使用log4net可以很方便地为应用添加日志功能.应用Log4net,开发者可以很精确地控制日志信息的输出,减少了多余信息,提高了日志记录性能.同时,通过外部配置文件,用户可以不用重新编译程序就能改变 ...

  6. Java中构造方法与setter方法

      今天在重温Java的同时,一个不是问题的问题,突然地冒出来,不知道大家是不是和我一样,也有过这个比较尴尬的问题 不啰嗦了,那咱就直接说问题吧~~~ 那么首先我们在Java中都会写构造函数,目的是在 ...

  7. How do I close a single buffer (out of many) in Vim?

    I open several files in Vim by, for example, running vim a/*.php which opens 23 files. I then make m ...

  8. 站在DevOps肩膀上的TestOps(二)

    一十一 发表于 2018-03-14 16:40:22 TestOps   摘要: TestOps模型旨在将整个团队的注意力集中在质量上,因此TestOps确实需要无缝且可靠. 一个简单的例子是任何测 ...

  9. mysql中数据类型后面的数字到底是什么?

    1.在mysql新建数据表的时候我们在数据类型后面经常会见到,或者添加数据,那么数据类型后面的数字到底是什么呢?之前以为int(3) 就代表最长数据就是3个字节,其实不是!! 我向num字段中插入: ...

  10. 2017-12-22 日语编程语言"抚子"-第三版实现初探

    前文日语编程语言"抚子" - 第三版特色初探仅对语言的语法进行了初步了解. 之前的语言原型实现尝试(如编程语言试验之Antlr4+JavaScript实现"圈4" ...