赛场交了个
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=0∑xai=((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)))))
递推这个式子复杂度是
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;
}