省选模拟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;
}
posted @ 2022-04-02 15:37  fengwu2005  阅读(53)  评论(0编辑  收藏  举报