CF Round 1008 题解合集
2D
抖音小游戏。
考虑从后往前 DP,设 \(f_{i,0/1}\) 表示在第 \(i\) 个位置放一个人,会给结果贡献几个人。
转移枚举当前位置是否是乘法:
-
\(f_{i,j}=f_{i+1,j}\),当前位置是加法;
-
\(f_{i,j}=a_{i}\max(f_{i+1,0},f_{i+1,1})\),当前位置是乘法。
然后从前往后贪心,每次把人放到贡献大的位置上。
复杂度 \(O(n)\)。
2E & 1B
考虑我们需要知道每个二进制位,是 \((0,0)\),\((0,1)\),还是 \((1,1)\)。
又发现困扰我们的实际是加法的进位。
于是我们可以分别考虑奇数位和偶数位,询问奇数位时,把 \(n\) 的偶数位全变成 \(1\),询问偶数位时,把 \(n\) 的奇数位全变成 \(1\),在最后计算答案时减去 \(2n\)。这样就能避免进位对下一位带来的干扰。
2F & 1C
这个真的只有 2300 吗。
设 \(cnt_0\) 表示序列中 \(0\) 的个数,\(cnt_1\) 表示序列中 \(1\) 的个数,\(S=cnt_1-cnt_0\),那么贪心地考虑,最后分数一定是 \(\lfloor\frac{S}{2}\rfloor\lceil\frac{S}{2}\rceil\),也就是:
所以我们要对所有的子序列 \(T\) 计算上面的式子之和,也就是:
考虑后一项,实际上是 \(2^{n-1}\),因为 \(S_T\) 的变化是连续的,所以这一项的值只有在 \(|T| \bmod 2=1\) 时才是 \(1\)。
现在的问题是前一项。我们还是希望合并处理系数,所以我们想要求的系数,实际上是:
如果我们能求出这个式子,那么相当于把枚举子集求答案转化成了只对全集求答案。
所以说,对于集合内的一个为 \(1\) 的系数,实际上就是全集一个 \(2^{n-1}\) 的系数。意会即可。
当 \(a_i=0\) 时,\(val_i=-1\);当 \(a_i=1\) 时,\(val_i=1\)。这样我们的答案变成:
用 脚 维护即可。
复杂度 \(O(n)\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
char ch;
int t,n,m,sum,pos,a[200005];
int binpow(int a,int b){
if(!b) return 1;
int res=binpow(a,b/2);
if(b&1) return res*res%mod*a%mod;
else return res*res%mod;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
cin>>n>>m;
sum=0;
for(int i=1;i<=n;i++){
cin>>ch;
if(ch=='0') a[i]=-1;
else a[i]=1;
sum+=a[i];
}
for(int i=1;i<=m;i++){
cin>>pos;
sum-=a[pos];
a[pos]*=-1;
sum+=a[pos];
cout<<(binpow(4,mod-2)*((sum*sum%mod+n)%mod*(n!=1?binpow(2,n-2):binpow(2,mod-2))%mod-binpow(2,n-1))%mod+mod)%mod<<'\n';
}
}
return 0;
}
2G & 1F
转化题意后,相当于每次选择若干位置 \(p_i\),满足相邻两个位置奇偶性不同,然后将这些位置减去 \(1\)。
令 \(b_i=\sum_{j=1}^ia_j[a_j \bmod 2=1]-\sum_{j=1}^ia_j[a_j \bmod 2=0]\),我们猜测答案为:
不难发现,这是答案的一个下界,但是这个下界好像能过样例的样子。
于是写一发扫描线,发现过了。
证明咕了。
复杂度 \(O(n \log n)\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
int t,n,ans,a[200005],b[200005],s1[200005],s2[200005],top1,top2;
int val[400005],ls[400005],rs[400005],tag[400005],dcnt,rt;
void pushup(int x){
val[x]=(val[ls[x]]+val[rs[x]])%mod;
}
void pushdown(int l,int r,int x){
if(!tag[x]) return;
int mid=(l+r)>>1;
val[ls[x]]=(val[ls[x]]+(mid-l+1)*tag[x]%mod)%mod;
val[rs[x]]=(val[rs[x]]+(r-mid)*tag[x]%mod)%mod;
tag[ls[x]]=(tag[ls[x]]+tag[x])%mod;
tag[rs[x]]=(tag[rs[x]]+tag[x])%mod;
tag[x]=0;
}
void build(int l,int r,int &x){
x=++dcnt;
val[x]=tag[x]=0;
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,ls[x]);
build(mid+1,r,rs[x]);
pushup(x);
}
void modify(int l,int r,int ql,int qr,int k,int x){
if(ql<=l && r<=qr){
val[x]=(val[x]+(r-l+1)*k%mod)%mod;
tag[x]=(tag[x]+k)%mod;
return;
}
pushdown(l,r,x);
int mid=(l+r)>>1;
if(ql<=mid) modify(l,mid,ql,qr,k,ls[x]);
if(qr>=mid+1) modify(mid+1,r,ql,qr,k,rs[x]);
pushup(x);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=b[i-1];
if(i&1) b[i]=b[i]+a[i];
else b[i]=b[i]-a[i];
}
memcpy(a,b,sizeof(a));
top1=top2=0;
s1[0]=s2[0]=-1;
build(0,n,rt);
for(int i=0;i<=n;i++){
while(top1 && a[s1[top1]]>a[i]){
modify(0,n,s1[top1-1]+1,s1[top1],a[s1[top1]]-a[i],rt);
top1--;
}
while(top2 && a[s2[top2]]<a[i]){
modify(0,n,s2[top2-1]+1,s2[top2],a[i]-a[s2[top2]],rt);
top2--;
}
s1[++top1]=i;
s2[++top2]=i;
ans=((ans+val[1])%mod+mod)%mod;
}
cout<<ans<<'\n';
ans=dcnt=rt=0;
}
return 0;
}