冲刺CSP联训模拟2
A. 挤压
拆位算贡献,一个数二进制表示平方为 \(\sum_{i,j}s_i*s_j*2^{i+j}\) ,单独算每一项的贡献,枚举 \(i,j\),只有当这两位都为1时
结果才是1,所以我们要找异或后这两位都是1的方案数,这里需要 \(dp\) 用 \(f_{i,j,k}\) 表示前 \(i\) 个数异或出来的 \(j,k\) 两位
是1/0的方案数,对于每个数考虑是否选即可。
点击查看代码
#include<bits/stdc++.h>
#define int long long
const int mod=1e9+7;
const int maxn=2e5+10;
using namespace std;
int n,a[maxn],p[maxn],ans,f[maxn][2][2];
inline int qpow(int x,int y)
{
int ans=1;
while(y)
{
if(y&1)ans=ans*x%mod;
x=x*x%mod;
y>>=1;
}
return ans;
}
signed main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>p[i],p[i]=p[i]*qpow(1000000000,mod-2)%mod;
for(int i=0;i<=29;i++)
{
for(int j=0;j<=29;j++)
{
f[0][0][0]=1,f[0][0][1]=f[0][1][0]=f[0][1][1]=0;
for(int k=1;k<=n;k++)
{
for(int x=0;x<=1;x++)
{
for(int y=0;y<=1;y++)
{
f[k][x][y]=f[k-1][x][y]*(1+mod-p[k])%mod;
bool xx=a[k]&(1<<i),yy=a[k]&(1<<j);
int aa=x^(xx?1:0),bb=y^(yy?1:0);
f[k][x][y]=(f[k][x][y]+f[k-1][aa][bb]*p[k]%mod)%mod;
}
}
}
ans=(ans+(f[n][1][1]*((1ll<<(i+j))%mod)%mod))%mod;
}
}
cout<<ans;
return 0;
}
/*
*/
B. 工地难题
跟 \(5k\) 学的,这里直接粘了(\(5k\) 果然比题解好用)
点击查看代码
#include<bits/stdc++.h>
#define int long long
const int maxn=2e5+10;
const int mod=1e9+7;
using namespace std;
int n,m,jc[maxn],ny[maxn],ans,last;
int qpow(int x,int y)
{
int ans=1;
while(y)
{
if(y&1)ans=ans*x%mod;
x=x*x%mod;
y>>=1;
}
return ans;
}
int c(int n,int m)
{
return jc[n]*ny[m]%mod*ny[n-m]%mod;
}
void pre()
{
jc[0]=1;
for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;
ny[n]=qpow(jc[n],mod-2);
for(int i=n-1;i>=0;i--) ny[i]=ny[i+1]*(i+1)%mod;
}
signed main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
pre();
for(int k=1;k<=m;k++)
{
int temp=c(n,m);
for(int i=1;i<=n-m+1;i++)
{
if(i*(k+1)>m) break;
temp=(temp+(i&1?mod-1:1)*c(n-i*(k+1),n-m)%mod*c(n-m+1,i)%mod)%mod;
}
cout<<(temp-last+mod)%mod<<" ";last=temp;
}
return 0;
}
/*
*/
C. 星空遗迹
考虑加入一个字符,他要么被前面胜者覆盖,无影响,要么直接覆盖前面,变成新的答案,所以我们维护一个栈,使得栈中
靠下的字符会赢他上面的字符,所以一个字符进栈要么输于栈顶,无影响,要么直接清空栈变成新答案,可以发现,当栈
内数量最小时,栈底的就是答案,对每个字符记录与上一个字符输赢,自己赢了为-1,输了为1,平局0,现在我们要维护
一个前缀最小值,和单点修改,这里用前缀和转换为区间修改,区间查询,线段树实现
点击查看代码
#include<bits/stdc++.h>
#define lid id<<1
#define rid id<<1|1
const int maxn=3e5+10;
using namespace std;
int n,q,a[maxn];
string s;
struct lsx
{
int l,r,minn,pos,flag;
}m[maxn<<2];
int cmp(char a,char b)
{
if(a==b) return 0;
if(a=='R'&&b=='S') return 1;
if(a=='S'&&b=='P') return 1;
if(a=='P'&&b=='R') return 1;
return -1;
}
void up(int id)
{
m[id].minn=min(m[lid].minn,m[rid].minn);
m[id].pos=m[lid].minn<m[rid].minn?m[lid].pos:m[rid].pos;
}
void down(int id)
{
if(!m[id].flag) return ;
m[lid].flag+=m[id].flag,m[rid].flag+=m[id].flag;
m[lid].minn+=m[id].flag,m[rid].minn+=m[id].flag;
m[id].flag=0;
}
void build(int id,int l,int r)
{
m[id].l=l,m[id].r=r;
if(l==r)
{
m[id].minn=a[l];
m[id].pos=l;
return ;
}
int mid=l+r>>1;
build(lid,l,mid);
build(rid,mid+1,r);
up(id);
}
int querx(int id,int x)
{
int l=m[id].l,r=m[id].r;
if(l==r) return m[id].minn;
down(id);
int mid=l+r>>1,temp;
if(x<=mid) temp=querx(lid,x);
else temp=querx(rid,x);
up(id);
return temp;
}
void update(int id,int s,int t,int x)
{
int l=m[id].l,r=m[id].r;
if(l>=s&&r<=t)
{
m[id].minn+=x;
m[id].flag+=x;
return ;
}
down(id);
int mid=l+r>>1;
if(s<=mid) update(lid,s,t,x);
if(mid<t) update(rid,s,t,x);
up(id);
}
pair<int,int> query(int id,int s,int t)
{
int l=m[id].l,r=m[id].r;
// cout<<id<<" "<<l<<" "<<r<<" "<<m[id].minn<<endl;
if(l>=s&&r<=t)
{
return {m[id].minn,m[id].pos};
}
down(id);
int mid=l+r>>1;
pair<int,int> k={1e9,0};
if(s<=mid)
{
pair<int,int> tem=query(lid,s,t);
if(tem.first<k.first) k=tem;
}
if(mid<t)
{
pair<int,int> tem=query(rid,s,t);
if(tem.first<k.first) k=tem;
}
up(id);
return k;
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>q;
cin>>s;s=" "+s;
a[1]=1;
for(int i=2;i<=n;i++) a[i]=cmp(s[i-1],s[i]),a[i]+=a[i-1];
build(1,1,n);
int op,x,y;
char k;
for(int i=1;i<=q;i++)
{
cin>>op;
if(op==1)
{
cin>>x>>k;
s[x]=k;
int s1=querx(1,x-1),s2=querx(1,x),s3;
if(x!=n) s3=querx(1,x+1);
// cout<<s1-s2+cmp(s[x-1],s[x])<<" "<<s2-s3+cmp(s[x],s[x+1])<<endl;
update(1,x,n,s1-s2+cmp(s[x-1],s[x]));
if(x!=n)update(1,x+1,n,s2-s3+cmp(s[x],s[x+1]));
}
else
{
cin>>x>>y;
pair<int,int> p=query(1,x,y);
// cout<<p.second<<endl;
cout<<s[p.second]<<'\n';
}
}
return 0;
}