2020ccpc长春D Meaningless Sequence(推规律 nlogn 解法)

本文介绍了一种针对特定二进制数求和问题的有效解决方法。通过观察规律,作者提出了一个递推公式,并将其复杂度优化至线性级别。该方法利用二进制位运算实现了高效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

赛场交了个 O(nlogn)O(nlogn)O(nlogn) 的代码,居然过了 第一次现场赛碾压标程(雾)
补一下想法:
一开始发现了一个规律,对于一个二进制位全为 111 的数 xxx∑i=0xai=(1+c)n\sum_{i=0}^xa_i=(1+c)^ni=0xai=(1+c)n 其中 nnnxxx 的二进制位数,而当 xxx 的二进制第一位是 111 其余都是 000 的数时有 ∑i=0xai=(1+c)n+c\sum_{i=0}^xa_i=(1+c)^n+ci=0xai=(1+c)n+c ,于是猜测有如下规律:
f(n,i)f(n,i)f(n,i) 为如下函数
f(n,i){i,if (n>>i)&1=10,otherwise f(n,i) \begin{cases} i, &if\ (n>>i)\&1=1\\ 0, &otherwise \end{cases} f(n,i){i,0,if (n>>i)&1=1otherwise
我们求解的答案就变成了下式:
∑i=0xai=((1+c)f(x,len)+c((1+c)f(x,len−1)+c(...((1+c)f(x,1)+c((1+c)f(x,0)+c)))))\sum_{i=0}^xa_i= ((1+c)^{f(x,len)}+c((1+c)^{f(x,len-1)}+c(...((1+c)^{f(x,1)}+c((1+c)^{f(x,0)}+c)))))i=0xai=((1+c)f(x,len)+c((1+c)f(x,len1)+c(...((1+c)f(x,1)+c((1+c)f(x,0)+c)))))
递推这个式子复杂度是 O(nlogn)O(nlogn)O(nlogn) 的,其实这个式子的复杂度可以优化到线性(边循环边处理 (1+c)(1+c)(1+c) 的幂次即可)

其实这个式子是我按照初始规律猜着猜着发现的,还不太会证(还是我太菜了)

具体细节见代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 3e3+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
char s[maxn];
ll c;
ll qpow(ll a,ll b)
{
	ll res = 1;
	while(b)
	{
		if(b&1) res = (res*a)%mod;
		a = a*a%mod;
		b >>= 1;
	}
	return res;
}
int main()
{
	ll ans = 1;
	scanf("%s%lld",s,&c);
	int len = strlen(s);
	for(int i = len-1;i >= 0;i--)
		if(s[i] == '1')
			ans = (qpow(1+c,len-i-1)+c*ans%mod)%mod;
	printf("%lld\n",ans);
	return 0;
}


评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值