裴蜀定理 + lowbit

Problem - D - Codeforces

题意

定义一个包含 \(m\) 个元素的数组 \(b\) 是好的,当且仅当满足以下两个条件

  1. 对于 \(b[i]\), 存在一个长度为 \(b[i]\) 的连续的段(如 \(b[i]=4\), [1,2,3,4], [-1,0,1,2]等就是符合条件的)
  2. 对于这 \(m\) 个段,\(sum_i\) 记为这一段的数字和,并满足 \(\sum sum_i=0\)]

给定一个长度为 \(n\;(1<=n<=2*10^5)\) 的数组 \(a[i]\),求 \(a\) 的 \(2^n-1\) 个非空子序列组成的数组中,有多少个是好的

思路

  1. 对于 \(a[i]\) 而言,设选取的一段的第一个数是 \(x_i\), 则 \(sum_i=a_i*x_i+\frac {a_i*(a_i-1)}2\)

  2. 若选了 \(a\) 数组的 \(k\) 个数,记为 \(c_1,c_2...c_k\)

    \(\sum sum_i=0\Lrarr \sum c_i*x_i=\sum \frac {c_i*(c_i-1)}2\)

​ 根据裴蜀定理,设 \(g=\gcd(c_1,c_2,...,c_k)\), 则要满足 \(g\mid \sum \frac {c_i*(c_i-1)}2\)

  1. 如果 \(c_i\) 中存在奇数,则 \(g\) 也一定是奇数,所以右边的除以2不影响整除的性质,又因为 \(g\mid c_i\), 因此 \(g\mid \sum \frac {c_i*(c_i-1)}2\) 恒成立

    所以奇数部分对方案数的贡献就是 \(2^{odd}\) (也可以感性考虑,如果存在一个奇数,那么它和其余所有的偶数共有奇数个数,把它们按关于 0 对称排列即可;其余的奇数也关于 0 对称排列)

  2. 现在只关心偶数部分,因为 \(g\mid c_i\), 问题是右边的除以 2 之后还能否满足 \(g\mid \sum \frac {c_i*(c_i-1)}2\),(即关心的是 \(c_i\) 的含 2 量) 由于 \(c_i-1\) 为奇数,对除以 2 而言没有意义,不用考虑;

  3. 现在转化为 \(g\mid \sum \frac {c_i}2\) 是否成立,记 \(lowb[x]\) 为能整除 \(x\) 的最高的 2 的幂次,例如 \(lowb[8]=3,lowb[16]=4\)

    \(lowb[g]<=lowb[c_i]\)

    1. \(lowb[c_i]>lowb[g]\), 那么 \(\frac {c_i}2\) 仍能被 \(g\) 整除
    2. \(lowb[c_i]==lowb[g]\), 需要偶数个相等的 \(c_i\) 才能使 \(g\mid \sum \frac {c_i}2\) (需要用到 \(\binom n0+\binom n2+\binom n4+...=2^{n-1}\) 来优化)

    代码

#include <bits/stdc++.h>
using namespace std;
#define endl "\n" typedef long long ll;
typedef pair<int, int> PII; const int N = 2e5 + 10;
const int mod = 1e9 + 7;
int n;
int a[N];
int lowb[40];
ll mi[N]; void add(ll &a, ll b)
{
a += b;
if (a >= mod)
a -= mod;
} void presolve()
{
mi[0] = 1;
for (int i = 1; i <= n; i++)
mi[i] = mi[i-1] * 2 % mod;
for (int i = 1; i <= n; i++)
{
int x = a[i], cnt = 0;
while(x % 2 == 0)
{
x /= 2;
cnt++;
}
lowb[cnt]++;
}
} ll solve()
{
ll ans = 0;
int even = 0;
for (int i = 1; i <= n; i++)
if (a[i] % 2 == 0) even++;
//至少一个奇数 + 任意个偶数
add(ans, mi[even] * (mi[n - even] - 1 + mod) % mod);
//只有偶数
for (int i = 1; i <= 30; i++)
{
if (!lowb[i])
continue;
even -= lowb[i];
//枚举拿的最小的lowbit,且要拿偶数个,C(n,0) + C(n,2) + C(n,4) + ... == 2^(n-1),且不能拿0个
add(ans, mi[even] * (mi[lowb[i] - 1] - 1 + mod) % mod);
}
return ans;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
presolve();
cout << solve() << endl;
return 0;
}

Codeforces Global Round 17 - D. Not Quite Lee的更多相关文章

  1. CodeForces Global Round 1

    CodeForces Global Round 1 CF新的比赛呢(虽然没啥区别)!这种报名的人多的比赛涨分是真的快.... 所以就写下题解吧. A. Parity 太简单了,随便模拟一下就完了. B ...

  2. Codeforces Global Round 1 - D. Jongmah(动态规划)

    Problem   Codeforces Global Round 1 - D. Jongmah Time Limit: 3000 mSec Problem Description Input Out ...

  3. Codeforces Global Round 2 题解

    Codeforces Global Round 2 题目链接:https://codeforces.com/contest/1119 A. Ilya and a Colorful Walk 题意: 给 ...

  4. Codeforces Global Round 1 (A-E题解)

    Codeforces Global Round 1 题目链接:https://codeforces.com/contest/1110 A. Parity 题意: 给出{ak},b,k,判断a1*b^( ...

  5. Codeforces Beta Round #17 D. Notepad (数论 + 广义欧拉定理降幂)

    Codeforces Beta Round #17 题目链接:点击我打开题目链接 大概题意: 给你 \(b\),\(n\),\(c\). 让你求:\((b)^{n-1}*(b-1)\%c\). \(2 ...

  6. Codeforces Global Round 3

    Codeforces Global Round 3 A. Another One Bites The Dust 有若干个a,有若干个b,有若干个ab.你现在要把这些串拼成一个串,使得任意两个相邻的位置 ...

  7. Codeforces Global Round 1 (CF1110) (未完结,只有 A-F)

    Codeforces Global Round 1 (CF1110) 继续补题.因为看见同学打了这场,而且涨分还不错,所以觉得这套题目可能会比较有意思. 因为下午要开学了,所以恐怕暂时不能把这套题目补 ...

  8. 【手抖康复训练1 】Codeforces Global Round 6

    [手抖康复训练1 ]Codeforces Global Round 6 总结:不想复习随意打的一场,比赛开始就是熟悉的N分钟进不去时间,2333,太久没写题的后果就是:A 题手抖过不了样例 B题秒出思 ...

  9. Codeforces Global Round 11 个人题解(B题)

    Codeforces Global Round 11 1427A. Avoiding Zero 题目链接:click here 待补 1427B. Chess Cheater 题目链接:click h ...

  10. Codeforces Beta Round #17 C. Balance DP

    C. Balance 题目链接 http://codeforces.com/contest/17/problem/C 题面 Nick likes strings very much, he likes ...

随机推荐

  1. CF生化全模式全装备单机版安装教程(基于CSOL)

    喜欢玩CF单机版的朋友平时应该接触过一些基于CS1.6的单机版,但是这种版本有些特性就是:改了分辨率就容易进不去游戏:变为幽灵时被枪射击时会出现视角乱晃的情况:游戏过程中场景宏大变数多时容易突然退出回 ...

  2. 新的学习历程-python4 input

    1 num = input("请输入数字:") # input用于录入键盘输入 2 print(num) 3 print(type(num)) #input获取到数据类型是字符类型 ...

  3. 如何将PDF文件中的部分信息隐藏或遮盖呢?

      由于工作需要,总是需要对PDF文件中的内容进行部分隐藏.之前,作为VIP,可以使用某软件对PDF中的信息进行部分遮盖,现在,VIP到期了,我也不想继续花钱了(哭穷,嘻嘻)   在信息时代,只要会百 ...

  4. 创建一个与a.txt文件同目录下的另一个文件b.txt

    File file1 = new("d:\\a\\a.txt"); File file2 = new(file1.getParent(),"b.txt"): F ...

  5. 【转】wamp如何添加多个站点

    1.打开wamp目录下的bin目录下的apache/conf/extra/httpd-vhosts.conf文件(虚拟目录配置文件),修改文件:在num01下创建index.php文件,输出01,:在 ...

  6. git+jenkins+ansible+gitlab部署网站

  7. Windows 与Docker

    https://docs.microsoft.com/zh-cn/windows/wsl/install-manual#step-4---download-the-linux-kernel-updat ...

  8. lua如何转化为exe

    在这里下载    https://wwn.lanzout.com/iIS9d07rpesh 然后用cmd到 下载的盘:\luapack\luapack\bin\Debug 然后glue.exe srl ...

  9. 【jquery easyUI 拓展

    jquery-easyui本身没有提供列锁定/解锁的接口,并且其原有的列隐藏/显示在符合表头的情况下会出现错位,我在项目中遇到了这两个问题,在参考了网上许多解决方案后,编写了一个拓展插件,基本上解决了 ...

  10. C++知识整理

    整理进度 1_ C++(31)中有很多没有整理的,找出来整理. 1.C++语言基础 C++中的头文件(.h) STL基本使用总结 C++里的花括号{},块:{}中的变量只在{}中有效 C++类型转换: ...