冲刺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\) 果然比题解好用)
image

点击查看代码
#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;
}
posted @ 2024-10-05 19:58  _君の名は  阅读(26)  评论(1编辑  收藏  举报