Codeforces Global Round 17 - D. Not Quite Lee
裴蜀定理 + lowbit
题意
定义一个包含 个元素的数组 是好的,当且仅当满足以下两个条件
- 对于 , 存在一个长度为 的连续的段(如 , [1,2,3,4], [-1,0,1,2]等就是符合条件的)
- 对于这 个段, 记为这一段的数字和,并满足 ]
给定一个长度为 的数组 ,求 的 个非空子序列组成的数组中,有多少个是好的
思路
-
对于 而言,设选取的一段的第一个数是 , 则
-
若选了 数组的 个数,记为
根据裴蜀定理,设 , 则要满足
-
如果 中存在奇数,则 也一定是奇数,所以右边的除以2不影响整除的性质,又因为 , 因此 恒成立
所以奇数部分对方案数的贡献就是 (也可以感性考虑,如果存在一个奇数,那么它和其余所有的偶数共有奇数个数,把它们按关于 0 对称排列即可;其余的奇数也关于 0 对称排列)
-
现在只关心偶数部分,因为 , 问题是右边的除以 2 之后还能否满足 ,(即关心的是 的含 2 量) 由于 为奇数,对除以 2 而言没有意义,不用考虑;
-
现在转化为 是否成立,记 为能整除 的最高的 2 的幂次,例如
- , 那么 仍能被 整除
- , 需要偶数个相等的 才能使 (需要用到 来优化)
代码
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!