码迷,mamicode.com
首页 > 其他好文 > 详细

20191008

时间:2019-10-21 09:24:50      阅读:63      评论:0      收藏:0      [点我收藏+]

标签:循环   void   lap   ret   line   结果   opened   main   tchar   

前言

  • T3想到正解然而并没有时间打。
  • T1送分几乎都A了,T2概率我啥也不会。
  • 我会的别人都会+别人会的我不会=考挂。

T1

  • 李煜东上有用kmp求最小循环节的例题,当初看了很久,所以……
  • 当然是选择Hash啦!
  • 时间复杂度不超过$\Theta(NlogN)$。空间复杂度$\Theta(N)$。
技术图片
#include<cstdio>
#define ll long long
using namespace std;
int const N=1e6+5,p1=23333,p2=1313131,mod1=1e9+7,mod2=998244353;
int n;
ll ans;
ll pre1[N],b1[N],pre2[N],b2[N];
inline int read(){
    int ss(0),pp(1);char bb(getchar());
    for(;bb<48||bb>57;bb=getchar())if(bb==-)pp=-1;
    while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar();
    return ss*pp;
}
int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    int T=read(),tp;
    b1[0]=b2[0]=1;
    for(register int i=1;i<N;++i)b1[i]=b1[i-1]*p1%mod1,b2[i]=b2[i-1]*p2%mod2;
    while(T--){
        ans=read()-1,n=read(),tp=1;
        ans*=n;
        register char bb=getchar(),la;
        while(bb<A||bb>Z)bb=getchar();la=bb;
        for(register int i=1;i<=n;++i,bb=getchar()){
            pre1[i]=(pre1[i-1]*p1+bb)%mod1,pre2[i]=(pre2[i-1]*p2+bb)%mod2;
            if(bb!=la)tp=0;
        }
        if(tp){printf("%lld\n",ans+n-1);continue;}
        if(!ans){
            register int i=n-1;
            for(;i;--i)
                if(pre1[i]==(pre1[n]-pre1[n-i]*b1[i]%mod1+mod1)%mod1 
                && pre2[i]==(pre2[n]-pre2[n-i]*b2[i]%mod2+mod2)%mod2)
                    break;
            printf("%d\n",i);
            continue;
        }
        for(register int i=2,lt=n>>1;i<=lt;++i){
            if(n%i)continue;
            int bs1=pre1[i],bs2=pre2[i];
            for(register int j=i<<1;j<=n;j+=i)
                if((pre1[j]-pre1[j-i]*b1[i]%mod1+mod1)%mod1!=bs1 
                || (pre2[j]-pre2[j-i]*b2[i]%mod2+mod2)%mod2!=bs2)
                    goto ac;
            ans+=i*(n/i-1);break;
            ac:;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

T2

  • 65的大众分只得了15分。
  • 我的概率是真的垃圾。
  • 题解的思路稍不懂,打的迪哥的思路。
  • 求出每个点的先手胜率和从s开始用奇/偶数步到达每个点的概率。
  • 最大胜率是将自己引到胜率最大的点或将对手引到胜率最小的点得到的结果。
  • 平均胜率综合考虑所有情况即可。
  • 时空复杂度$\Theta(N)$。
技术图片
#include<cstdio>
#define ll long long
using namespace std;
int const N=1e5+5,M=3e5+5;
int n,m,s;
int head[N],Next[M],to[M],t;
int rhc[N],du[N],rnxt[M],rto[M],rt;
double win[N],al[N][2],tot,maxw,minw=2e9;
double mx,av,ansx,ansv;
inline int read(){
    int ss(0),pp(1);char bb(getchar());
    for(;bb<48||bb>57;bb=getchar())if(bb==-)pp=-1;
    while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar();
    return ss*pp;
}
inline void ad2(int x,int y){
    ++du[rto[++rt]=y];
    rnxt[rt]=rhc[x],rhc[x]=rt;
    return ;
}
inline void add(int x,int y){
    to[++t]=y;
    Next[t]=head[x],head[x]=t;
    return ad2(y,x);
}
inline double max(double x,double y){
    return x>y?x:y;
}
inline double min(double x,double y){
    return x<y?x:y;
}
int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    n=read(),m=read(),al[s=read()][0]=1;
    for(register int i=1,ff,tt;i<=m;++i)
        ff=read(),tt=read(),add(ff,tt);
    scanf("%lf%lf",&mx,&av);
    for(register int i=n;i;--i){
        tot+=win[i];
        maxw=max(maxw,win[i]),minw=min(minw,win[i]);
        const double x=1.0-win[i];
        for(register int j=rhc[i];j;j=rnxt[j])
        win[rto[j]]+=x/(double)du[rto[j]];
    }
    for(register int i=1;i<=n;++i){
        const double on=al[i][0]/(double)du[i],jn=al[i][1]/(double)du[i];
        for(register int j=head[i];j;j=Next[j])
            al[to[j]][0]+=jn,al[to[j]][1]+=on;
    }
    double const swin=win[s];
    for(register int i=1;i<=n;++i){
        const double now=1.0/(double)(du[i]+1),nw=now*du[i],
        mxg=al[i][0]<al[i][1]?maxw:minw;
        ansx=max(ansx,
             swin-al[i][0]*win[i]-al[i][1]*(1-win[i])
             +al[i][0]*now*(1-mxg)+al[i][1]*now*mxg
             +al[i][0]*nw*win[i]+al[i][1]*nw*(1-win[i]));
    }
    for(register int i=1;i<=n;++i){
        double now=1.0/(double)(du[i]+1),z=(tot-win[i])/(double)(n-1);
        ansv+=(1-(al[i][0]+al[i][1])*now)*swin+al[i][0]*now*(1-z)+al[i][1]*now*z;
    }
    printf("%.3lf %.3lf\n",ansx,ansv/(double)n);
    return 0;
}
View Code

T3

  • 考试想到了维护子树最大次大次次大的贡献,这样就可以做了。
  • 不过觉得稍毒瘤于是最后才去打,没打完……
  • 原本想用树链剖分,但题解给出了更优越的树上倍增。
  • 想到这些本题就不难解决了。
  • 时空复杂度$\Theta(NlogN)$。
技术图片
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
#define mp make_pair
using namespace std;
int const N=2e5+5,M=4e5+5;
int n,m,ans;
int head[N],Next[M],to[M],t;
int dep[N],Log[N],f[N][19],mx[N][19];
pair<int,int>son[N][3];
int par[N];
inline int read(){
    int ss(0);char bb(getchar());
    while(bb<48||bb>57)bb=getchar();
    while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar();
    return ss;
}
inline void add(int x,int y){
    to[++t]=y;
    Next[t]=head[x],head[x]=t;
    return ;
}
inline int max(int x,int y){
    return x>y?x:y;
}
int dfs(int x,int fa){
    int firs,firw=0,sces,scew=0,thrs,thrw=0,dnow=dep[x]+1;
    for(int i=head[x],y,z;i;i=Next[i])
        if((y=to[i])^fa){
            dep[y]=dnow,f[y][0]=x;
            for(register int j=0;j<Log[dnow];++j)
                f[y][j+1]=f[f[y][j]][j];
            z=dfs(y,x);
            if(z>firw){
                thrs=sces,thrw=scew;
                sces=firs,scew=firw;
                firs=y,firw=z;
            }
            else if(z>scew){
                thrs=sces,thrw=scew;
                sces=y,scew=z;
            }
            else if(z>thrw)
                thrs=y,thrw=z;
        }
    ans=max(ans,firw+scew);
    son[x][0]=mp(firs,firw),son[x][1]=mp(sces,scew),son[x][2]=mp(thrs,thrw);
    return firw+1;
}
void redfs(int x,int fa){
    int anow=par[x]+1,gl=son[x][0].first,
    firw=son[x][0].second,secw=son[x][1].second;
    for(int i=head[x],y,dnow=dep[x]+1;i;i=Next[i])
        if((y=to[i])^fa){
            mx[y][0]=(y==gl?secw:firw);
            par[y]=max(anow,mx[y][0]+1);
            for(register int j=0;j<Log[dnow];++j)
                mx[y][j+1]=max(mx[y][j],mx[f[y][j]][j]);
            redfs(y,x);
        }
    return ;
}
inline void _swap(int &x,int &y){
    int z=x;
    x=y,y=z;
    return ;
}
inline int lca(int x,int y){
    if(dep[x]<dep[y])_swap(x,y);
    int zans=son[x][0].second;
    for(register int i=Log[dep[x]];~i;--i)
        if(dep[f[x][i]]>=dep[y])zans=max(zans,mx[x][i]),x=f[x][i];
    if(x==y)return max(zans,par[x]);
    zans=max(zans,son[y][0].second);
    for(register int i=Log[dep[x]];~i;--i)
        if(f[x][i]^f[y][i])
            zans=max(zans,max(mx[x][i],mx[y][i])),
            x=f[x][i],y=f[y][i];
    int fa=f[x][0];
    zans=max(zans,par[fa]);
    if(son[fa][0].first!=x && son[fa][0].first!=y)return max(zans,son[fa][0].second);
    if(son[fa][1].first!=x && son[fa][1].first!=y)return max(zans,son[fa][1].second);
    return max(zans,son[fa][2].second);
}
int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    n=read();
    Log[0]=-1;
    for(register int i=1,ff,tt;i<n;++i)
        Log[i]=Log[i>>1]+1,ff=read(),tt=read(),add(ff,tt),add(tt,ff);
    Log[n]=Log[n>>1]+1,dep[1]=1;
    dfs(1,0),ans=ans+2>>1;
    redfs(1,0);
    m=read();
    while(m--){
        int x=read(),y=read();
        if(x==y){printf("%d\n",ans);continue;}
        printf("%d\n",lca(x,y));
    }
    return 0;
}
View Code

20191008

标签:循环   void   lap   ret   line   结果   opened   main   tchar   

原文地址:https://www.cnblogs.com/remarkable/p/11710116.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!