计算机科普活动日题解

A~E

不讲了,就是注意一下D没有保证升序,要排序,因为这个挂了55pts。

F

LG P3365

根据题意,很容易想到就是中序遍历,然后求最少修改数使序列严格上升。

由此可得,要修改尽量少的次数和保留尽量多的原数是等价的。

但是因为每个数是整数,所以\(n-LIS\) 肯定是错的。

\(LIS\) 的第 \(i\) 位为 \(d_{i},\)\(j\) 位为 \(d_{j}(1\leq j < i\leq n)\),任意一组 \((i,j)\) 都要满足 \(d_{i}-d_{j}\ge i-j\),变型可得,\(d_{i}-i\ge d_{j}-j\)

求出最长不降子序列,再用 \(n\) 减去即可。

先写暴力,时间复杂度 \(O(n^2)\)

暴力60pts代码:

#include <bits/stdc++.h>
using namespace std;

#define For(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<=(y);++i)
#define foR(i,x,y,...) for(int i=(x),##__VA_ARGS__;i>=(y);--i)
#define Rep(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<(y);++i)
#define endl '\n'
#define debug(...)
#define debug1(a,i,...) cout<<i<<" "<<a[i]<<endl;
typedef long long ll;
#define fi first
#define se second
#define PII pair<int,int>
#define me(s,x) memset(s,x,sizeof s)
#define pb emplace_back

template<typename T=int>T read(){T x;cin>>x;return x;}
const int mod=998244353;
struct mint{
	int x;mint(int x=0):x(x<0?x+mod:x<mod?x:x-mod){}
	mint(ll y){y%=mod,x=y<0?y+mod:y;}
	mint& operator += (const mint &y){x=x+y.x<mod?x+y.x:x+y.x-mod;return *this;}
	mint& operator -= (const mint &y){x=x<y.x?x-y.x+mod:x-y.x;return *this;}
	mint& operator *= (const mint &y){x=1ll*x*y.x%mod;return *this;}
	friend mint operator + (mint x,const mint &y){return x+y;}
	friend mint operator - (mint x,const mint &y){return x-y;}
	friend mint operator * (mint x,const mint &y){return x*y;}
};mint Pow(mint x,ll y=mod-2){mint z(1);for(;y;y>>=1,x*=x)if(y&1)z*=x;return z;}
const int N=1e5+10;
int s[N],a[N],lson[N],rson[N],f[N];
int n,tot,cnt;
void dfs(int u){
	if(lson[u]) dfs(lson[u]);
	a[++tot]=s[u];
	if(rson[u]) dfs(rson[u]);
} 
void MAIN(){
	cin>>n;
	For(i,1,n) cin>>s[i];
	For(i,2,n,fa,ch){
		cin>>fa>>ch;
		if(ch==0){
			lson[fa]=i;
		}
		else rson[fa]=i;
	}
	dfs(1);
	For(i,1,n) a[i]-=i;
	For(i,1,n){
		f[i]=1;
		Rep(j,1,i){
			if(a[i]>=a[j]){
				f[i]=max(f[i],f[j]+1);
			} 
		}
		cnt=max(cnt,f[i]);
	}
	cout<<n-cnt<<endl;
}signed main(){
	int t=1;while(t--){
		MAIN();
	}
	return 0;
}

接下来的问题是怎么把 \(O(n^2)\) 变为 \(O(nlogn)\)

考虑维护一个单调栈,使这个栈单调不降。

  • 当该元素 \(\ge\) 栈顶元素时,把这个元素压入栈中。
  • 否则,在单调栈中找到第一个大于该元素的项,把这一项改为这个元素。(因为要使每个元素尽可能小,才有更大的空间,可以证明,一定更优。)注意要用 upper_bound 而不是 lower_bound

时间复杂度 \(O(nlogn)\)

100pts代码:

#include <bits/stdc++.h>
using namespace std;

#define For(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<=(y);++i)
#define foR(i,x,y,...) for(int i=(x),##__VA_ARGS__;i>=(y);--i)
#define Rep(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<(y);++i)
#define endl '\n'
#define debug(...)
#define debug1(a,i,...) cout<<i<<" "<<a[i]<<endl;
typedef long long ll;
#define fi first
#define se second
#define PII pair<int,int>
#define me(s,x) memset(s,x,sizeof s)
#define pb emplace_back

template<typename T=int>T read(){T x;cin>>x;return x;}
const int mod=998244353;
struct mint{
	int x;mint(int x=0):x(x<0?x+mod:x<mod?x:x-mod){}
	mint(ll y){y%=mod,x=y<0?y+mod:y;}
	mint& operator += (const mint &y){x=x+y.x<mod?x+y.x:x+y.x-mod;return *this;}
	mint& operator -= (const mint &y){x=x<y.x?x-y.x+mod:x-y.x;return *this;}
	mint& operator *= (const mint &y){x=1ll*x*y.x%mod;return *this;}
	friend mint operator + (mint x,const mint &y){return x+y;}
	friend mint operator - (mint x,const mint &y){return x-y;}
	friend mint operator * (mint x,const mint &y){return x*y;}
};mint Pow(mint x,ll y=mod-2){mint z(1);for(;y;y>>=1,x*=x)if(y&1)z*=x;return z;}
const int N=1e5+10;
int s[N],a[N],lson[N],rson[N],f[N];
int n,tot,cnt=1;
void dfs(int u){
	if(lson[u]) dfs(lson[u]);
	a[++tot]=s[u];
	if(rson[u]) dfs(rson[u]);
} 
void MAIN(){
	cin>>n;
	For(i,1,n) cin>>s[i];
	For(i,2,n,fa,ch){
		cin>>fa>>ch;
		if(ch==0){
			lson[fa]=i;
		}
		else rson[fa]=i;
	}
	dfs(1);
	For(i,1,n) a[i]-=i;
	f[1]=a[1];
	For(i,2,n){
		if(a[i]>=f[cnt]){
			f[++cnt]=a[i];
		}
		else{
			f[upper_bound(f+1,f+cnt+1,a[i])-f]=a[i]; 
		}
	}
	cout<<n-cnt<<endl;
}signed main(){
	int t=1;while(t--){
		MAIN();
	}
	return 0;
}

G题

字符串

非常好dp,使我的大脑旋转。

首先想到 \(dfs\) 暴力。

是我菜完了(

20pts代码

#include<bits/stdc++.h>
using namespace std;

#define For(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<=(y);++i)
#define foR(i,x,y,...) for(int i=(x),##__VA_ARGS__;i>=(y);--i)
#define Rep(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<(y);++i)
typedef long long ll;
#define me(s,x) memset(s,x,sizeof s)
#define fi first
#define se second
#define pb emplace_back
const int N=310,MOD=1e9+7;
#define int ll
int n,q,ans;
string s;
string l;
void dfs(int u,int x,int y,int z,char lst){
	if(u==n){
		ans++;
		ans%=MOD;
		return;
	}
	if(s[u]!='?'&&s[u]==lst) return;
	if(s[u]!='?') dfs(u+1,x,y,z,s[u]);
	else{
		if(lst!='a'&&x) dfs(u+1,x-1,y,z,'a');
		if(lst!='b'&&y) dfs(u+1,x,y-1,z,'b');
		if(lst!='c'&&z) dfs(u+1,x,y,z-1,'c');
	}
}
void MAIN(){
	scanf("%d%d%s",&n,&q,s);
	while(q--){
		ans=0;
		int x,y,z;
		cin>>x>>y>>z;
		dfs(0,x,y,z,' ');
		cout<<ans<<endl;
	}
}signed main(){
	int t=1;while(t--){
		MAIN();
	}
	return 0;
}

\(f_{i,j,k,0/1/2}\) 表示前 \(i\) 位,用了 \(j\)\(a\), \(k\)\(b\),当前位置是 \(a/b/c\)

\(C_{i,j,k}\) 表示恰好用了 \(i\)\(a\),\(j\)\(b\),\(k\)\(c\) 的方案数。设 \(SC_{i,j,k}\)\(C_{i,j,k}\) 的三维前缀和,\(SC_{x,y,z}\)即为最终答案。

直接 \(dp\) 即可,细节有点多(尤其是取模)。

不能使用mint,会卡空间。

时间复杂度 \(O(n^3)\),空间复杂度 \(O(n^3)\)

100pts代码:

#include <bits/stdc++.h>
using namespace std;

#define For(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<=(y);++i)
#define foR(i,x,y,...) for(int i=(x),##__VA_ARGS__;i>=(y);--i)
#define Rep(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<(y);++i)
#define endl '\n'
#define debug(...)
#define debug1(a,i,...) cout<<i<<" "<<a[i]<<endl;
typedef long long ll;
#define fi first
#define se second
#define PII pair<int,int>
#define me(s,x) memset(s,x,sizeof s)
#define pb emplace_back

template<typename T=int>T read(){T x;cin>>x;return x;}
const int mod=1e9+7;
struct mint{
	int x;mint(int x=0):x(x<0?x+mod:x<mod?x:x-mod){}
	mint(ll y){y%=mod,x=y<0?y+mod:y;}
	mint& operator += (const mint &y){x=x+y.x<mod?x+y.x:x+y.x-mod;return *this;}
	mint& operator -= (const mint &y){x=x<y.x?x-y.x+mod:x-y.x;return *this;}
	mint& operator *= (const mint &y){x=1ll*x*y.x%mod;return *this;}
	friend mint operator + (mint x,const mint &y){return x+y;}
	friend mint operator - (mint x,const mint &y){return x-y;}
	friend mint operator * (mint x,const mint &y){return x*y;}
};mint Pow(mint x,ll y=mod-2){mint z(1);for(;y;y>>=1,x*=x)if(y&1)z*=x;return z;}
const int N=301;
unsigned int f[N][N][N][3],c[N][N][N],sc[N][N][N];
int sm[N];
string s;
int n,q,x,y,z;
void MAIN(){
	cin>>n>>q>>s;
	s=' '+s;
	For(i,1,n) sm[i]=sm[i-1]+(s[i]=='?');
	if(s[1]=='a') f[1][0][0][0]=1;
	else if(s[1]=='b') f[1][0][0][1]=1;
	else if(s[1]=='c') f[1][0][0][2]=1;
	else f[1][1][0][0]=f[1][0][1][1]=f[1][0][0][2]=1;
	For(i,2,n){
		For(ca,0,300){
			For(cb,0,300){
				if(s[i]=='a')((f[i][ca][cb][0]+=f[i-1][ca][cb][1])+=f[i-1][ca][cb][2])%=mod;
				else if(s[i]=='b')((f[i][ca][cb][1]+=f[i-1][ca][cb][0])+=f[i-1][ca][cb][2])%=mod;
				else if(s[i]=='c')((f[i][ca][cb][2]+=f[i-1][ca][cb][0])+=f[i-1][ca][cb][1])%=mod;
				else{
					((f[i][ca+1][cb][0]+=f[i-1][ca][cb][1])+=f[i-1][ca][cb][2])%=mod;//a
					((f[i][ca][cb+1][1]+=f[i-1][ca][cb][0])+=f[i-1][ca][cb][2])%=mod;//b
					((f[i][ca][cb][2]+=f[i-1][ca][cb][0])+=f[i-1][ca][cb][1])%=mod;//c
				}
			}
		}
	}
	For(ca,0,sm[n])For(cb,0,sm[n]-ca){
		int cc=sm[n]-ca-cb;
		For(k,0,2)c[ca][cb][cc]+=f[n][ca][cb][k];
	}
	For(ca,0,sm[n])For(cb,0,sm[n])For(cc,0,sm[n]){
		int res=0;
		if(ca) (res+=sc[ca-1][cb][cc])%=mod;
		if(cb) (res+=sc[ca][cb-1][cc])%=mod;
		if(cc) (res+=sc[ca][cb][cc-1])%=mod;
		if(ca&&cb) (res-=sc[ca-1][cb-1][cc])%=mod;
		if(ca&&cc) (res-=sc[ca-1][cb][cc-1])%=mod;
		if(cb&&cc) (res-=sc[ca][cb-1][cc-1])%=mod;
		if(ca&&cb&&cc) (res+=sc[ca-1][cb-1][cc-1])%=mod;
		sc[ca][cb][cc]=(c[ca][cb][cc]+res+mod)%mod;
	}
	while(q--){cin>>x>>y>>z;cout<<sc[x][y][z]<<endl;}
}signed main(){
	int t=1;while(t--){
		MAIN();
	}
	return 0;
}

完结撒花!

posted @ 2025-05-24 15:34  cruisexsy2011  阅读(10)  评论(0)    收藏  举报