[40](CSP 集训)CSP 联训模拟 2
A.挤压
经典二进制拆位
好像也不是那么经典,CL-22 有提到
那么这个题因为维护的不是贡献和而是贡献平方和,所以考虑怎么计算
假设我们得到了一个异或后的答案
UPD: 码的谁问的,显然这里不是枚举
设
最后统计的时候直接从
提前预处理逆元和真实概率,否则跑的贼慢
跟 int_R 学到了炫酷写法
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int p=1e9+7;
int n;
int a[100001],p0[100001];
int f[2][33][33][2][2];
int power(int a,int t){
int base=a,ans=1;
while(t){
if(t&1){
ans=ans*base%p;
}
base=base*base%p;
t>>=1;
}
return ans;
}
const int inv=power(1000000000,p-2);
signed main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%lld",&n);
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;++i){
scanf("%lld",&p0[i]);
p0[i]=p0[i]*inv%p;
}
for(int i=0;i<=32;++i){
for(int j=0;j<=32;++j){
f[0][i][j][0][0]=1;
}
}
for(int i=1;i<=n;++i){
for(int j=0;j<=32;++j){
for(int k=0;k<=32;++k){
for(int l:{0,1}){
for(int m:{0,1}){
f[i&1][j][k][l][m]=(f[1-(i&1)][j][k][l][m]*(1-p0[i])+f[1-(i&1)][j][k][l^((a[i]>>j)&1)][m^((a[i]>>k)&1)]*p0[i])%p;
}
}
}
}
}
int ans=0;
for(int i=0;i<=32;++i){
for(int j=0;j<=32;++j){
ans+=(1ll<<(i+j))%p*f[n&1][i][j][1][1]%p;
ans%=p;
}
}
cout<<(ans%p+p)%p;
}
B.工地难题
C.星空遗迹
维护一个胜利者栈,在这个栈里保证前一个元素能赢后一个,只要维护出这个栈,则栈底元素即为胜利者
- 栈空,插入
- 栈顶元素输了或平局,弹出
- 栈顶元素赢了,插入新元素
这样做的依据:
- 两个可以胜中间元素的元素,将其中间元素清除后结果不变(弹掉失败者的依据)
- 一个相同元素的连通块,缩成一个后不影响结果(弹掉平局者的依据)
转化成式子大概就是
你无视这个对
感性理解
所以如果你无视掉这个对
然后上线段树
可以维护一个原数组的差分数组,这个差分数组只有
然后你做修改的时候(比如把差分数组
然后需要注意的就是,如果遇到两个都是最小值,那么应该取下标靠后的那个
#include<bits/stdc++.h>
using namespace std;
int n,q;
inline int ton(char c){
if(c=='R') return 0;
if(c=='P') return 2;
return 1;
}
inline char toc(int i){
if(i==0) return 'R';
if(i==2) return 'P';
return 'S';
}
inline bool win2(int x,int y){
if(x==0 and y==1) return true;
if(x==1 and y==2) return true;
if(x==2 and y==0) return true;
return false;
}
inline int win(int s,int x){
return win2(s,x);
// -1 front win
// if(s==x) return 0;
// if(s==1 and x==2) return 1;
// if(s==1 and x==3) return -1;
// if(s==2 and x==3) return 1;
// if(s==2 and x==1) return -1;
// if(s==3 and x==1) return 1;
// if(s==3 and x==2) return -1;
}
const int inf=0x3f3f3f3f;
int sum[200001];
namespace stree{
struct tree{
int l,r;
int val,pos;
int lazy;
}t[800001];
#define tol (id*2)
#define tor (id*2+1)
#define mid(l,r) mid=((l)+(r))/2
void pushup(int id){
if(t[tol].val<=t[tor].val){
t[id].val=t[tol].val;
t[id].pos=t[tol].pos;
}
else{
t[id].val=t[tor].val;
t[id].pos=t[tor].pos;
}
}
void build(int id,int l,int r){
t[id].l=l;t[id].r=r;
if(l==r){
t[id].val=sum[l];
t[id].pos=l;
return;
}
int mid(l,r);
build(tol,l,mid);
build(tor,mid+1,r);
pushup(id);
}
void pushdown(int id){
if(t[id].lazy){
t[tol].val+=t[id].lazy;
t[tol].lazy+=t[id].lazy;
t[tor].val+=t[id].lazy;
t[tor].lazy+=t[id].lazy;
t[id].lazy=0;
}
}
void change(int id,int l,int r,int val){
// cout<<"change "<<id<<" "<<l<<" "<<r<<" "<<val<<endl;
if(l<=t[id].l and t[id].r<=r){
t[id].val+=val;
t[id].lazy+=val;
return;
}
pushdown(id);
int mid(t[id].l,t[id].r);
if(mid>=l) change(tol,l,r,val);
if(mid<r) change(tor,l,r,val);
pushup(id);
}
tree ask(int id,int l,int r){
if(l<=t[id].l and t[id].r<=r) return t[id];
pushdown(id);
int mid(t[id].l,t[id].r);
tree res={0,0,inf,0,0};
if(mid>=l) res=ask(tol,l,r);
if(mid<r){
if(res.val>=inf) res=ask(tor,l,r);
else{
tree res2=ask(tor,l,r);
if(res2.val<res.val) res=res2;
}
}
return res;
}
}
int a[200001];
stack<int>st;
int solve(){
// for(int i=1;i<=n;++i){
// cout<<a[i]<<" ";
// }
// cout<<endl;
while(!st.empty()) st.pop();
int lastans=0;
for(int i=1;i<=n;++i){
while(!st.empty() and win2(st.top(),a[i])==false) st.pop();
st.push(a[i]);
if(st.size()==1) lastans=st.top();
}
return lastans;
}
int d[200001];
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d %d",&n,&q);getchar();
for(int i=1;i<=n;++i){
a[i]=ton(getchar());
}
d[1]=1;
for(int i=2;i<=n;++i){
if(win(a[i-1],a[i])) d[i]=1;
else if(win(a[i],a[i-1])) d[i]=-1;
else d[i]=0;
}
for(int i=1;i<=n;++i){
// cout<<d[i]<<" ";
sum[i]=sum[i-1]+d[i];
}
// cout<<endl;
stree::build(1,1,n);
while(q--){
int op;scanf("%d",&op);
int k,l,r;char x;
if(op==1){
scanf("%d %c",&k,&x);
a[k]=ton(x);
int bef,aft,now=ton(x);
if(k!=1){
bef=d[k];aft=0;
if(win(a[k-1],now)) aft=1;
if(win(now,a[k-1])) aft=-1;
d[k]=aft;
stree::change(1,k,n,aft-bef);
// cout<<aft<<" "<<bef<<" 1"<<aft-bef<<endl;
}
if(k!=n){
bef=d[k+1];aft=0;
if(win(now,a[k+1])) aft=1;
if(win(a[k+1],now)) aft=-1;
d[k+1]=aft;
stree::change(1,k+1,n,aft-bef);
// cout<<aft<<" "<<bef<<" 2"<<aft-bef<<endl;
}
a[k]=now;
}
else{
scanf("%d %d",&l,&r);
printf("%c\n",toc(a[stree::ask(1,l,r).pos]));
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!