2022 ICPC 网络预选赛(9.17)
发现好多人不知道去哪补题。
给出 链接
上方有个签到可以领5金币,不想vp可以不购买时光机这样只需要一个金币。
L 给出一个s和t 求s一个最长子串使得s中不存在t中长度大于2的子串。
直接的想法是状压dp 不过复杂度很高。仔细考虑当前形成子串中若包含t的一个字符所形成的的限制是 该字符后的一些字符无法使用。
那么维护包含最靠前的字符可以把之前的限制包含。同时选这个字符时还需要考虑这个字符最后出现的位置也要比当前字符限制靠前。
限制数为26个 状态数可以接受。
code
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cctype>
#include<cmath>
#include<algorithm>
#include<set>
#define rep(a,b,k) for(int k=a;k<=b;++k)
using namespace std;
//设 f{i,j} 表示 到了i 里面有t字符的靠前位置为j的最大长度
const int MAXN=500010;
int n,m,cnt,cnt2;
char t[MAXN],s[MAXN];
int pos[MAXN];
int a[MAXN],b[MAXN],c[MAXN],w[MAXN],vis[MAXN],last[MAXN];
int f[30];
int main()
{
//freopen("1.in","r",stdin);
scanf("%s",s+1);
scanf("%s",t+1);
n=strlen(s+1);
m=strlen(t+1);
rep(1,n,i){a[i]=s[i]-'a';}
rep(1,m,i)
{
b[i]=t[i]-'a';
if(pos[b[i]]){vis[b[i]]=1;}
if(!pos[b[i]])pos[b[i]]=i,c[++cnt]=i,w[i]=cnt;
last[b[i]]=i;
}
rep(1,n,i)
{
int w1=pos[a[i]];
if(!w1){++cnt2;continue;}
if(!vis[a[i]])++f[w[w1]];
//if(i==n)cout<<w[w1]<<' '<<"ww"<<endl;
rep(w[w1]+1,cnt,j)
{
if(last[a[i]]<c[j])
f[w[w1]]=max(f[w[w1]],f[j]+1);
}
f[w[w1]]=max(f[w[w1]],1);
//cout<<f[1]<<endl;
}
int ww=0;
rep(1,cnt,i)ww=max(ww,f[i]);
printf("%d\n",ww+cnt2);
return 0;
}
K 本题 是给出一个参数w 和atk 初始都是1 有n个回合每回合都可以给w加上1 或者给 atk加上w 之后和一个\(a_i\) 比较。
求最大的胜利轮数。
容易想到dp的时候 w atk都要已知 这样直接dp是\(n^3\)
仔细思考发现输的轮数不大于\(2\cdot \sqrt{n}\)
这样将输的轮数放状态里把atk放f值里就优化了一个根号。
再思考w的大小 可以证明w的大小也不超过\(\sqrt{n}\) 证明:假设w已经到了\(\sqrt{n}\) 此时再选择让w+1 但若使w加到atk上 之后至少要经过w轮方案1才会比方案2好 这是atk早就已经满了。
再根据归纳证明w不超过\(\sqrt{n}\) 又优化了一个根号 此时复杂度为\(n^2\) 可以使用滚动数组来优化空间。
code
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cctype>
#include<cmath>
#include<algorithm>
#include<set>
#define rep(a,b,k) for(int k=a;k<=b;++k)
using namespace std;
const int MAXN=5010;
int n,B,S;
int a[MAXN];
int f[2][150][73];
int main()
{
//freopen("1.in","r",stdin);
scanf("%d",&n);
memset(f,-1,sizeof(f));
f[0][0][1]=1;
int u=0;
rep(1,n,i)
{
scanf("%d",&a[i]);
int v=u;u=u^1;
memset(f[u],-1,sizeof(f[u]));
rep(0,149,j)
{
rep(1,71,k)
{
if(f[v][j][k]==-1)continue;
//s1
if(f[v][j][k]>=a[i])
f[u][j][k+1]=max(f[u][j][k+1],f[v][j][k]);
else f[u][j+1][k+1]=max(f[u][j+1][k+1],f[v][j][k]);
//s2
if(f[v][j][k]+k>=a[i])
{
f[u][j][k]=max(f[u][j][k],f[v][j][k]+k);
}
else f[u][j+1][k]=max(f[u][j+1][k],f[v][j][k]+k);
}
}
}
rep(0,149,j)rep(1,71,k)if(f[u][j][k]!=-1){printf("%d\n",n-j);return 0;}
return 0;
}
J 本题是一个构造题找到合适的期望式子是构造成功的关键。
笔者求期望是这样的 \(E(X)=1+(1-a_1)+(1-a_1)(1-a_2)+...(1-a_1)(1-a_2)...(1-a_{X-1})=Y\)
要求 2<Y<X 考虑归纳构造 将Y-1两边同时除以(1-a_1) 得到新的Y' 容易发现这个2<Y'<X-1
当做完X-1次后使Y等于1即可。怎么完成这个过程呢 考虑每次令 \(\frac{Y-1}{(1-a_i)}=Y-w\) w为某个分数 那么\(a_i\)可以解方程直接解出来。
笔者这里取w为1/99 98/99 这样在Y为最小值2 为最大值99时都有解 那么在Y的任意取值也会有解。
当然你取1/999 和998/999也可 注意在X=2的时候开始收拢 即做出Y'的处理让Y的等于1 因为此时\(2<Y'<3\)所以必然有解。
代码不小心误删了 抱歉抱歉。