牛客网NOIP赛前集训营-提高组(第六场)题解

A.最长路

题意:给定有向图,每条边有个字符\([0,10^9]\),求每个点最长路字典序最小的方案.\(N,M\le 10^6\)

建反图跑拓扑排序,显然入过队的点都有最长路,考虑如何判断字典序大小,一种方案是把每个点转移过来的路径字符串哈希一下,然后用倍增比较两个字符串的大小复杂度\(O(N+Mlog_2M)\)

第二种方案是每次对最长路相同的点以入边上的字符为第一关键字,起点的排名(之前已经排过了)为第二关键字排序,这样可以保证字典序小的先更新

代码是第一种方法

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
#define dbg(x) cout<<#x<<" = "<<(x)<<endl
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
using namespace std;
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
inline char smin(int&x,const int&y){return x>y?x=y,1:0;}
inline char smax(int&x,const int&y){return x<y?x=y,1:0;}
const int BUFSIZE=1e6;
char inbuf[BUFSIZE],outbuf[BUFSIZE],*si=inbuf,*ti=inbuf,*so=outbuf,*to=outbuf+BUFSIZE;
struct FastIO{
    ~FastIO(){fwrite(outbuf,1,so-outbuf,stdout);}
    #define gc()  (si==ti&&(ti=inbuf+fread(si=inbuf,1,BUFSIZE,stdin),si==ti)?EOF:*si++)
    #define pc(c) (so==to?fwrite(outbuf,1,BUFSIZE,stdout),so=outbuf,*so++=c:*so++=c)
    template<typename T>inline T&rd(T&w){char c,p=0;
        while(isspace(c=gc()));if(c=='-')p=1,c=gc();
        for(w=c&15;isdigit(c=gc());w=w*10+(c&15));
        if(p)w=-w;return w;}
    inline int read(){int x;return rd(x);}
    template<typename T>inline void print(T w){static char s[20];int top=0;
        if(w<0)pc('-'),w=-w;if(w==0)pc('0');
        for(top=0;w;w/=10)s[++top]=w%10;
        while(top)pc(s[top--]|'0');}
    inline void putstr(const string&u){int l=u.length();REP(i,0,l-1)pc(u[i]);}
}io;
#define read io.read
const int N=1e6+5,p=998244353;
int n,m,head[N],tot,L;
struct node{int v,w,nxt;}e[N];
inline void add(int x,int y,int z){e[++tot]=(node){y,z,head[x]};head[x]=tot;}
int q[N],ind[N],f[N],ans[N],fa[23][N];
ull g[23][N],cf[N];
const ull base=1000000007ull;
inline bool cmp(int x,int y){
    for(int i=L;~i;--i)if(g[i][x]==g[i][y])x=fa[i][x],y=fa[i][y];
    return g[0][x]<g[0][y];
}
void toposort(){
    int l=1,r=0,x;
    REP(i,1,n)if(!ind[i])q[++r]=i,f[i]=0;
    while(l<=r){
        for(int i=head[x=q[l++]];i;i=e[i].nxt){
            int&y=e[i].v;
            if((smax(f[y],f[x]+1)||f[y]==f[x]+1&&(g[0][y]>e[i].w||g[0][y]==e[i].w&&cmp(x,fa[0][y])))){
                ans[y]=(ans[x]+e[i].w)*29ll%p;
                fa[0][y]=x;g[0][y]=e[i].w;
                REP(i,1,L)fa[i][y]=fa[i-1][fa[i-1][y]],g[i][y]=g[i-1][y]*cf[1<<i-1]+g[i-1][fa[i-1][y]];
            }
            if(!--ind[y])q[++r]=y;
        }
    }
}
int main(){
    n=read(),m=read();L=__lg(m);
    REP(i,1,m){int x=read(),y=read(),z=read();add(y,x,z);++ind[x];}
    cf[0]=1;REP(i,1,m)cf[i]=cf[i-1]*base;toposort();
    REP(i,1,n){
        if(ind[i]<=0)io.print(ans[i]),pc('\n');
        else io.putstr("Infinity\n");
    }
    return 0;
}

B.选择题

题意: 有一道选择题有四个选项 现在有 \(n\)个人来做这题,第 \(i\)个人有 \(p_{i,j}\) 的概率选第 \(j\) 个选项。 定义 \(cnt(x)\) 为选第 \(x\) 个选项的人数。 令 \(mx\)\(cnt(x)\) 最大的 \(x\) (如果有多个\(cnt(x)\)最大的 \(x\),则取其中 \(x\) 最小的), 若 img ,则所有人得 0 分; 否则令 \(choice_i\) 表示第 \(i\) 个人选的选项,则第 i 人得 img 分。 求每个人的期望得分。

\(n\le 2000\)

考虑枚举这个最多的是哪个选项,然后只要对每个 \(i\) 算出他选每个选项的概率即可

\(f[i][j]\) 表示前 \(i\) 个人,选了 \(j\)\(mx\) 的概率,那么有
\[ f[i][j]=f[i-1][j-1]*p[i][mx]+f[i-1][j]*(1-p[i][mx]) \]
\(g[i][j]\) 表示\(i \dots n\) ,选了 \(j\)\(mx\) 的概率,转移同理

这样对 \(g\) 做个后缀和就可以算了

复杂度 \(O(16n^2)\)

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
#define dbg(x) cout<<#x<<" = "<<(x)<<endl;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
using namespace std;
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
inline char smin(int&x,const int&y){return x>y?x=y,1:0;}
inline char smax(int&x,const int&y){return x<y?x=y,1:0;}
struct FastIO{
    static const int S=1310720;
    int wpos;char wbuf[S];
    FastIO():wpos(0) {}
    inline int xchar(){
        static char buf[S];
        static int len=0,pos=0;
        if(pos==len)pos=0,len=fread(buf,1,S,stdin);
        if(pos==len)return -1;
        return buf[pos++];
    }
    inline int read(){
        int c=xchar(),x=0;
        while(c<=32&&~c)c=xchar();
        if(c==-1)return -1;
        for(;'0'<=c&&c<='9';c=xchar())x=x*10+c-'0';
        return x;
    }
}io;
#define read io.read
const int N=2005,p=998244353;
int n,a[4][N],f[N][N],g[N][N],w[4][N],ans[N];
inline void inc(int&x,int y){x+=y;if(x>=p)x-=p;}
int main(){
    n=read();
    REP(i,1,n)REP(j,0,3)a[j][i]=read();
    REP(i,0,3)REP(j,0,3)w[i][j]=read();
    int m=n/2+1;
    REP(k,0,3){
        memset(f,0,sizeof f);memset(g,0,sizeof g);
        f[0][0]=g[n+1][0]=1;
        REP(i,1,n)REP(j,0,i)
        f[i][j]=((j?1ll*a[k][i]*f[i-1][j-1]%p:0)+1ll*(1-a[k][i]+p)*f[i-1][j])%p;
        for(int i=n;i;--i)for(int j=n-i+1;~j;--j)
        g[i][j]=((j?1ll*a[k][i]*g[i+1][j-1]%p:0)+1ll*(1-a[k][i]+p)*g[i+1][j])%p;
        REP(i,1,n)for(int j=n-i+1;~j;--j)inc(g[i][j],g[i][j+1]);
        REP(i,1,n)REP(j,0,i-1)if(f[i-1][j]){
            REP(t,0,3)if(t==k)ans[i]=(ans[i]+1ll*f[i-1][j]*g[i+1][max(0,m-1-j)]%p*a[k][i]%p*w[k][k])%p;
            else ans[i]=(ans[i]+1ll*f[i-1][j]*g[i+1][max(0,m-j)]%p*a[t][i]%p*w[k][t])%p;
        }
    }
    REP(i,1,n)printf("%d\n",ans[i]);
    return 0;
}

C.树

题意:给一棵树,有边权,实现4种操作:

1.链查询权值和

2.链修改父亲边的权值

3.链修改儿子边的权值

4.换根查询子树和

数据结构题,按照题意写即可。先树剖,然后线段树里维护一下对父亲的修改,对儿子的修改,和父亲边的权值和,跳轻重链时,轻边上判一下父亲和儿子谁先改即可。

复杂度 \(O(nlog^2n)\)

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
#define dbg(x) cout<<#x<<" = "<<(x)<<endl;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
using namespace std;
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
inline char smin(int&x,const int&y){return x>y?x=y,1:0;}
inline char smax(int&x,const int&y){return x<y?x=y,1:0;}
struct FastIO{
    static const int S=1310720;
    int wpos;char wbuf[S];
    FastIO():wpos(0) {}
    inline int xchar(){
        static char buf[S];
        static int len=0,pos=0;
        if(pos==len)pos=0,len=fread(buf,1,S,stdin);
        if(pos==len)return -1;
        return buf[pos++];
    }
    inline int read(){
        int c=xchar(),x=0;
        while(c<=32&&~c)c=xchar();
        if(c==-1)return -1;
        for(;'0'<=c&&c<='9';c=xchar())x=x*10+c-'0';
        return x;
    }
}io;
#define read io.read
const int N=1e5+5;
int n,m,head[N],v[N<<1],nxt[N<<1],tot;
inline void add(int x,int y){v[++tot]=y,nxt[tot]=head[x];head[x]=tot;}
int top[N],in[N],siz[N],fa[N],dep[N],son[N],cnt;
#define y v[i]
inline void go1(int x){
    siz[x]=1;
    for(int i=head[x];i;i=nxt[i])if(y!=fa[x])
    fa[y]=x,dep[y]=dep[x]+1,go1(y),siz[x]+=siz[y],siz[y]>siz[son[x]]&&(son[x]=y);
}
inline void go2(int x,int anc){
    in[x]=++cnt;top[x]=anc;
    if(!son[x])return;go2(son[x],anc);
    for(int i=head[x];i;i=nxt[i])if(y!=fa[x]&&y!=son[x])go2(y,y);
}
#undef y
#define ls o<<1
#define rs o<<1|1
#define all 1,1,n
struct data{int t,w;};
struct tree{int sum[3],len;data tag,son;}t[N<<2];
int T,opt;
inline void pushup(int o){REP(i,0,2)t[o].sum[i]=t[ls].sum[i]+t[rs].sum[i];}
inline void build(int o,int l,int r){
    t[o].sum[0]=t[o].len=r-l+1;
    t[o].tag=t[o].son=(data){-1,-1};
    if(l==r){t[o].tag=(data){0,0};return;}
    int mid=l+r>>1;build(ls,l,mid),build(rs,mid+1,r);
}
inline void change(int o,const data&x,bool f){
    if(f){
        REP(i,0,2)t[o].sum[i]=i==x.w?t[o].len:0;t[o].tag=x;
    }else t[o].son=x;
}
#define pushdown()\
    if(~t[o].tag.t)change(ls,t[o].tag,1),change(rs,t[o].tag,1),t[o].tag=(data){-1,-1};\
    if(~t[o].son.t)change(ls,t[o].son,0),change(rs,t[o].son,0),t[o].son=(data){-1,-1};
inline void update(int o,int l,int r,int x,int y,const data&z){
    if(l>r)return;if(x<=l&&r<=y)return change(o,z,opt);
    int mid=l+r>>1;pushdown();
    if(x<=mid)update(ls,l,mid,x,y,z);if(y>mid)update(rs,mid+1,r,x,y,z);
    pushup(o);
}
inline int ask(int o,int l,int r,int x,int y,int z){
    if(x<=l&&r<=y)return t[o].sum[z];
    if(x>r||y<l||l>r)return 0;
    int mid=l+r>>1;pushdown();
    return ask(ls,l,mid,x,y,z)+ask(rs,mid+1,r,x,y,z);
}
inline data&ask(int o,int l,int r,int x,int z){
    if(l==r)return z?t[o].tag:t[o].son;
    int mid=l+r>>1;pushdown();
    return x<=mid?ask(ls,l,mid,x,z):ask(rs,mid+1,r,x,z);
}
data t1,t2;
inline int ask(int x,int y,int z){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=ask(all,in[top[x]]+1,in[x],z);
        t1=ask(all,in[top[x]],1);t2=ask(all,in[fa[top[x]]],0);
        if(t2.t==-1||t1.t>=t2.t)ans+=t1.w==z;else ans+=t2.w==z;
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    return ans+ask(all,in[x]+1,in[y],z);
}
inline void update(int x,int y,int c1,int c2){
    ++T;t1=(data){T,c1},t2=(data){T,c2};
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        opt=0,update(all,in[top[x]],in[x],t2);
        opt=1,update(all,in[top[x]],in[x],t1);
        if(son[x])update(all,in[x]+1,in[x]+1,t2);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    opt=0,update(all,in[x],in[y],t2);
    opt=1,update(all,in[x]+1,in[y],t1);
    update(all,in[x],in[x],t2);
    if(son[y])update(all,in[y]+1,in[y]+1,t2);
}
inline int jump(int x,int y){while(top[x]!=top[y])if(fa[top[x]]==y)return top[x];else x=fa[top[x]];return son[y];}
int main(){
    n=read();
    REP(i,2,n){int x=read(),y=read();add(x,y),add(y,x);}
    go1(1),go2(1,1),build(1,1,n);
    m=read();
    while(m--){
        int op=read(),x=read(),y=read(),z=read();
        if(op==1)printf("%d\n",ask(x,y,z));
        else if(op==2)update(x,y,z,read());
        else{
            opt=1;t1=(data){++T,z};
            if(x==y)update(all,1,n,t1);else
            if(in[x]>in[y]&&in[x]<in[y]+siz[y]){
                int p=jump(x,y);
                update(all,1,in[p]-1,t1),update(all,in[p]+siz[p],n,t1);
            }else update(all,in[y]+1,in[y]+siz[y]-1,t1);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/HolyK/p/9828719.html