题目
问题描述
错误点
应当为:
(
a
[
i
]
+
=
a
[
i
−
1
]
)
%
=
m
o
d
(a[i]+=a[i-1])\%=mod
(a[i]+=a[i−1])%=mod
误写为:
(
a
[
i
]
+
=
a
[
i
−
1
]
)
%
m
o
d
(a[i]+=a[i-1])\%mod
(a[i]+=a[i−1])%mod
意义不同,后者其实相当于没有进行取模。
1.二次前缀和(向后顾)
对于序列
[
1
,
0
,
0
,
1
,
0
,
0
,
0
,
0
,
1
]
[1,0,0,1,0,0,0,0,1]
[1,0,0,1,0,0,0,0,1]中出现的第一个
1
1
1,考虑其对后续出现的
1
1
1
的影响为
[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
]
[0,1,2,3,4,5,6,7,8]
[0,1,2,3,4,5,6,7,8],第二个出现的
1
1
1,对后续
的影响为
[
0
,
0
,
0
,
0
,
1
,
2
,
3
,
4
,
5
]
[0,0,0,0,1,2,3,4,5]
[0,0,0,0,1,2,3,4,5]。而最后一个
1
1
1没有后续的
1
1
1了,可以不考虑。
求和可得
[
0
,
1
,
2
,
3
,
5
,
6
,
9
,
11
,
13
]
[0,1,2,3,5,6,9,11,13]
[0,1,2,3,5,6,9,11,13],取对应位置求和即答案。
要点:通过分析影响,可以看出 ‘ 1 ’ ‘1’ ‘1’的影响其实就是二次前缀和的结果。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod =1e9+7;
const int N =1e5+7;
ll n,a[N],ans;
string s;
int main(){
cin>>n;
cin>>s;
for(ll i=0;i<n;i++){
if(s[i]=='1')a[i+1]=1;
}
for(int i=1;i<=n;i++)(a[i]+=a[i-1])%=mod;
for(int i=1;i<=n;i++)(a[i]+=a[i-1])%=mod;
for(int i=1;i<n;i++){
if(s[i]=='1')(ans+=a[i])%=mod;
}
cout<<ans<<endl;
return 0;
}
2.直接求解(往前盼)
对于一个
1
1
1,考虑其前方所有的
1
1
1与这个
1
1
1可以产生的能量,类似DP,满足递推关系:
p
[
i
]
.
a
n
s
=
(
(
p
[
i
]
.
v
a
l
−
p
[
i
−
1
]
.
v
a
l
)
∗
i
+
p
[
i
−
1
]
.
a
n
s
)
%
m
o
d
p[i].ans=((p[i].val-p[i-1].val)*i+p[i-1].ans)\%mod
p[i].ans=((p[i].val−p[i−1].val)∗i+p[i−1].ans)%mod
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+5;
const int mod = 1e9+7;
#define fir(i, a, b) for (int i = (a); i <= (b); i++)
ll n,sz,ans;
char a[N];
struct node{
ll ans,val;
node(){
ans=val=0;
}
node(ll x){
val=x;
}
};
vector<node>p;
int main(){
cin>>n>>a+1;
fir(i,1,n){
if(a[i]=='1'){
p.push_back(i);
}
}
sz=p.size();
fir(i,1,sz-1){
p[i].ans=((p[i].val-p[i-1].val)*i+p[i-1].ans)%mod;
(ans+=p[i].ans)%=mod;
}
cout<<ans<<endl;
}