省选模拟43
额,今天算是整个模拟赛以来打的最顺手的一场了吧......
开场看T1,直接切掉,可惜我\(\mathcal{O(n)}\)的比带log的还要慢...
然后T2看错题,5min码完发现假了,不要紧,想想就切了
T3开始瞎搞,真·瞎搞,直接爆蛋
T1 图案
可以直接hash,枚举a+b的长度,然后二分公共前缀,打标记即可
我用的KMP,最长border和长度之差就是delta,循环节长度一定是delta的倍数,并且剩下的一部分一定小于循环节长度
于是解个不等式即可...
AC_code
#include<bits/stdc++.h>
using namespace std;
// #define ull unsigned long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=1e6+5;
// const ull bas=131;
int n,m;char a[N];
int fail[N];
// ull ba[N],hs[N];
// ull get(int l,int r){return hs[r]-hs[l-1]*ba[r-l+1];}
signed main(){
freopen("pattern.in","r",stdin);
freopen("pattern.out","w",stdout);
n=read();m=read();
scanf("%s",a+1);
// fo(i,1,n){
// hs[i]=hs[i-1]*bas+a[i]-'a'+1;
// ba[i]=ba[i-1]*bas;
// }
for(int i=2,j=0;i<=n;i++){
while(a[i]!=a[j+1]&&j)j=fail[j];
if(a[i]==a[j+1])j++;
fail[i]=j;
}
fo(i,1,n){
int dt=i-fail[i];
// cerr<<i<<" "<<fail[i]<<endl;
int dw=(i-1)/dt/(m+1)+1,up=i/dt/m;
// cerr<<dw<<" "<<up<<endl;
if(dw<=up)printf("1");
else printf("0");
}
return 0;
}
T2 树点购买
开始看错题了,看成每个点买了之后可以知道子树内所有叶子的值,没想到是他们的和
难在记录哪些点出现过,可以记录每个点的前驱,如果他可以那么前驱也是可以的,还可以记录等价类...
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=1e6+5;
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
int ksm(int x,int y){
int ret=1;
while(y){
if(y&1)ret=ret*x%mod;
x=x*x%mod;y>>=1;
}return ret;
}
int n,m,c[N];
struct E{int to,nxt;}e[N*2];
int head[N],rp;
void add_edg(int x,int y){
e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;
}
int dp[N][2],pr[N],fas[N][2];
// pr 0 直接上来 1 自己和下面 2 都行
bool vs[N][2],pt[N],lf[N];
vector<int> vec[N][2];
void dfs_dp(int x,int fa){
lf[x]=true;fas[x][0]=1;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa)continue;
lf[x]=false;dfs_dp(y,x);
dp[x][0]+=dp[y][0];
fas[x][0]=fas[x][0]*fas[y][0]%mod;
}
if(lf[x]){
dp[x][0]=c[x];fas[x][0]=1;
dp[x][1]=0;fas[x][1]=1;
}
else {
dp[x][1]=inf;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa)continue;
// dp[x][1]=min(dp[x][1],dp[x][0]-dp[y][0]+dp[y][1]);
if(dp[x][1]>dp[x][0]-dp[y][0]+dp[y][1]){
vec[x][1].clear();vec[x][1].push_back(y);
dp[x][1]=dp[x][0]-dp[y][0]+dp[y][1];
fas[x][1]=fas[x][0]*ksm(fas[y][0],mod-2)%mod*fas[y][1]%mod;
}
else if(dp[x][1]==dp[x][0]-dp[y][0]+dp[y][1]){
vec[x][1].push_back(y);
fas[x][1]=(fas[x][1]+fas[x][0]*ksm(fas[y][0],mod-2)%mod*fas[y][1]%mod)%mod;
}
}
// dp[x][0]=min(dp[x][0],dp[x][1]+c[x]);
if(dp[x][0]<dp[x][1]+c[x]){
pr[x]=0;
}
else if(dp[x][0]>dp[x][1]+c[x]){
pr[x]=1;dp[x][0]=dp[x][1]+c[x];
fas[x][0]=fas[x][1];
}
else if(dp[x][0]==dp[x][1]+c[x]){
pr[x]=2;fas[x][0]=(fas[x][0]+fas[x][1])%mod;
}
}
}
void dfs_vs(int x,int fa){
// cerr<<x<<" "<<fa<<" "<<vs[x][0]<<" "<<vs[x][1]<<endl;
if(!vs[x][0]&&!vs[x][1])return ;
if(lf[x]){
if(vs[x][0])pt[x]=true;
return ;
}
bool fl=false;
if(vs[x][0]){
if(pr[x]==0){
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa)continue;
vs[y][0]=true;
}
}
else if(pr[x]==1)fl=true;
else if(pr[x]==2){
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa)continue;
vs[y][0]=true;
}fl=true;
}
}
if(fl)pt[x]=true;
if(vs[x][1]||fl){
for(int y:vec[x][1])vs[y][1]=true;
int sz=vec[x][1].size(),id=vec[x][1][0];
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa)continue;
if(sz==1&&id==y)vs[y][1]=true;
else vs[y][0]=true;
}
}
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa)continue;
dfs_vs(y,x);
}
}
signed main(){
freopen("purtree.in","r",stdin);
freopen("purtree.out","w",stdout);
n=read();
fo(i,1,n)c[i]=read();
fo(i,1,n-1){
int x=read(),y=read();
add_edg(x,y);add_edg(y,x);
}m=read();
dfs_dp(1,0);
vs[1][0]=true;dfs_vs(1,0);
if(m>=1)printf("%lld\n",dp[1][0]);
if(m>=2){
fo(i,1,n)if(pt[i])printf("%lld ",i);
printf("\n");
}
if(m>=3){
printf("%lld\n",fas[1][0]);
}
return 0;
}
T3 舰队游戏
所以这是个凸包题,发现每个点可以回城,于是设dp[i][j]表示在i点,还剩j点血量的期望步数
发现转移是和回城取min,于是我们可以二分答案,直接二分答案是啥就行
第一个点是不可以回城的,所以我们看二分出来的和求出来的大小关系就行,大了就减小,小了就增大
为什么可以二分,发现每个点值都是随着二分的值的增大而增大的,而增速小于点值的变化,所以我们可以二分
增速的问题可以看变化率,就是可以将点值看做关于二分的值的函数,增速就是斜率,发现斜率是随着二分值的增大而递减的
因为递减所以点值的增速小于二分值的增速,一定存在一个点使得斜率是等于1的,这个就是答案,也就是点值和二分值相等的地方
AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=105;
const double inf=1e9;
int n,m,h,d[N];
struct E{int to,nxt;}e[N*N];
int head[N],rp;
void add_edg(int x,int y){e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;}
double dp[N][N],A;
bool vis[N][N];
double dfs_pre(int x,int b){
if(b<=0)return 0;
if(x==n)return 1;
if(vis[x][b])return dp[x][b];
vis[x][b]=true;int sum=0;
for(int i=head[x];i;i=e[i].nxt)sum++;
if(!sum)return dp[x][b]=0;
double gl=1.0/sum;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(b<=d[y]){dp[x][b]=0;break;}
dp[x][b]+=dfs_pre(y,b-d[y])*gl;
}
return dp[x][b];
}
double dfs_dp(int x,int b){
if(b<=0)return inf;
if(x==n)return 0;
if(vis[x][b])return dp[x][b];
vis[x][b]=true;int sum=0;
for(int i=head[x];i;i=e[i].nxt)sum++;
double gl;
if(sum==0)dp[x][b]=inf;
else gl=1.0/sum;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
dp[x][b]+=(dfs_dp(y,b-d[y])+1)*gl;
}
if(x!=1)dp[x][b]=min(dp[x][b],h-b+A);
return dp[x][b];
}
double ck(double md){A=md;
memset(vis,false,sizeof(vis));
memset(dp,0,sizeof(dp));
return dfs_dp(1,h);
}
signed main(){
freopen("kancolle.in","r",stdin);
freopen("kancolle.out","w",stdout);
n=read();m=read();h=read();
fo(i,1,m){
int x=read(),y=read();
add_edg(x,y);
}
fo(i,1,n)d[i]=read();
// if(!dfs_pre(1,h)){printf("-1");return 0;}
// cerr<<dp[1][h]<<endl;
double l=1e-6,r=2e6,mid;
while(r-l>1e-8){
mid=(l+r)/2;
double ret=ck(mid);
// if(mid==ret){l=mid;break;}
if(mid<ret)l=mid;
else r=mid;
}
if(l>1e6)printf("-1");
else printf("%.10lf",l);
return 0;
}
QQ:2953174821