计算机科普活动日题解
A~E
不讲了,就是注意一下D没有保证升序,要排序,因为这个挂了55pts。
F
根据题意,很容易想到就是中序遍历,然后求最少修改数使序列严格上升。
由此可得,要修改尽量少的次数和保留尽量多的原数是等价的。
但是因为每个数是整数,所以\(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;
}

浙公网安备 33010602011771号