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

在这里插入图片描述

赛场交了个 O ( n l o g n ) O(nlogn) O(nlogn) 的代码,居然过了 第一次现场赛碾压标程(雾)
补一下想法:
一开始发现了一个规律,对于一个二进制位全为 1 1 1 的数 x x x ∑ i = 0 x a i = ( 1 + c ) n \sum_{i=0}^xa_i=(1+c)^n i=0xai=(1+c)n 其中 n n n x x x 的二进制位数,而当 x x x 的二进制第一位是 1 1 1 其余都是 0 0 0 的数时有 ∑ i = 0 x a i = ( 1 + c ) n + c \sum_{i=0}^xa_i=(1+c)^n+c i=0xai=(1+c)n+c ,于是猜测有如下规律:
f ( n , i ) f(n,i) f(n,i) 为如下函数
f ( n , i ) { i , i f   ( n > > i ) & 1 = 1 0 , o t h e r w i s e 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 = 0 x a i = ( ( 1 + c ) f ( x , l e n ) + c ( ( 1 + c ) f ( x , l e n − 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 ( n l o g n ) 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、付费专栏及课程。

余额充值