衝刺CSP聯訓模擬2

_君の名は發表於2024-10-05

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;
}

相關文章