zoukankan      html  css  js  c++  java
  • HNOI2018

    d1t1[HNOI/AHOI2018]寻宝游戏

    感觉很神,反正我完全没想到

    分开考虑每一位,对于每一位i计算一个二进制数b[i],

    对于第i位,从后往前第j个数这一位是1,那么b[i]^=(1<<j)

    对于操作,从后往前考虑每个数前面的符号,把&看成1,|看成0

    把一个操作序列看成一个二进制数c

    发现|0和&1等于无影响,一个操作序列的最后一个|1或者&0决定结果的值

    那么对于第i位,要使这一位为1,必须满足c<b[i]

    (这一位是1,则要选择一个b[i]中是1的位置取|,并将它之前的所有操作任意取,之后的操作有唯一取法,相当于将二进制位中某个1变成0,高位不变,低位任意取,最后得到c<b[i])

    那么将b从大到小排序,对于每个询问,首先满足找到最靠左的0必须在1后面,然后最靠左的0的位置为pos,答案为b[pos-1]-b[pos]

    要取模,一开始傻乎乎地在那里写高精...

     1 //Achen
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdlib>
     6 #include<vector>
     7 #include<cstdio>
     8 #include<queue>
     9 #include<cmath>
    10 #define For(i,a,b) for(int i=(a);i<=(b);i++)
    11 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
    12 const int N=5007,mod=1e9+7;
    13 typedef long long LL;
    14 typedef double db;
    15 using namespace std;
    16 const LL mxup=(1LL<<58);
    17 int n,m,q,sa[N],rak[N],L;
    18 LL ans[N];
    19 char s[1007][N],ss[N];
    20 
    21 template<typename T>void read(T &x)  {
    22     char ch=getchar(); x=0; T f=1;
    23     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    24     if(ch=='-') f=-1,ch=getchar();
    25     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    26 }
    27 
    28 bool cmp(const int &A,const int &B) {
    29     Rep(i,n,1) {
    30         if(s[i][A]!=s[i][B]) return s[i][A]>s[i][B];
    31     } return 1;
    32 }
    33 
    34 void pre() {
    35     For(i,0,m) 
    36         Rep(j,n,1) {
    37             int x=i==0?1:s[j][i]-'0';
    38             ans[i]=((ans[i]<<1)%mod+x)%mod;
    39         }
    40     ans[0]=(ans[0]+1)%mod;
    41 }
    42 
    43 //#define DEBUG
    44 int main() {
    45 #ifdef DEBUG
    46     freopen("hunt.in","r",stdin);
    47     freopen("hunt.out","w",stdout);
    48 #endif
    49     read(n); read(m); read(q);
    50     For(i,1,n) scanf("%s",s[i]+1);
    51     For(i,1,m) sa[i]=i;
    52     sort(sa+1,sa+m+1,cmp);
    53     For(i,1,m) rak[sa[i]]=i;
    54     pre();
    55     while(q--) {
    56         int ll=0,rr=m+1;
    57         scanf("%s",ss+1);
    58         For(i,1,m) {
    59             int x; x=ss[i]-'0';
    60             if(x==1) ll=max(ll,rak[i]); 
    61             else if(!rr||rr>rak[i]) rr=rak[i];
    62         }
    63         if(rr<ll) puts("0");
    64         else {
    65             LL rs=(rr==m+1?ans[sa[rr-1]]:(ans[sa[rr-1]]-ans[sa[rr]]+mod)%mod);
    66             printf("%lld
    ",rs);
    67         }
    68     }
    69     return 0;
    70 }
    71 /*
    72 5 5 1
    73 01110
    74 11011
    75 10000
    76 01010
    77 00100
    78 00100
    79 */
    View Code

    d1t2[HNOI/AHOI2018]转盘

    贪心.发现一定有一种最优答案是在某个起点待着不动一会,然后一路走下去

    考虑如果答案是走了很多圈,最后一个取的点为x,那么从最后时刻从x往前走一圈,一路上所有东西肯定都是已经出现了的,把游戏倒过来,就是从x往前走,在每个物品消失前取到它,那么最优策略一定是从x一步不停地走下去,那么正过来也是一样.

    把原序列倍长,答案就等于 

    $ans=min_{i=1}^n(max_{j=i}^{2*n}T[j]-(j-i)+n-1)$

    $设A[i]=T[i]-i$

    $ans=min_{i=1}^n(max_{j=i}^{2*n}A[j]+i)+n+1$

    维护和楼房重建很像.

    用线段树维护答案,线段树上分别维护A[i]的最大值,和在l~r这段区间中来算(即n=r,i=l~n),i在l~mid中的答案的最小值

    支持询问qry(x,l,r,suf)表示i在l,r这段去就,A[i]和suf取max后的答案,那么修改时可以调用qry在两个log的时间里更新线段树里的值

    注意询问时直接输出线段树中根的答案,而不是调用qry(suf会出问题),

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    #include<set>
    #define For(i,a,b) for(int i=(a);i<=(b);i++)
    #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
    const int N=200007;
    typedef long long LL; 
    typedef double db;
    using namespace std;
    int n,m,p,T[N],A[N],ans;
    
    template<typename T> void read(T &x) {
        char ch=getchar(); x=0; T f=1;
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    #define lc x<<1
    #define rc ((x<<1)|1)
    #define mid ((l+r)>>1)
    int mx[N<<2],sg[N<<2];
    int qry(int x,int l,int r,int suf) {
        if(l==r) return max(suf,mx[x])+l;
        if(mx[rc]>=suf) return min(sg[x],qry(rc,mid+1,r,suf));
        else return min(qry(lc,l,mid,suf),suf+mid+1);
    }
    
    void update(int x,int l,int r) {
        mx[x]=max(mx[lc],mx[rc]);
        sg[x]=qry(lc,l,mid,mx[rc]);
    }
    
    void change(int x,int l,int r,int pos) {
        if(l==r) {
            mx[x]=A[l]; sg[x]=A[l]+l; return;
        }
        if(pos<=mid) change(lc,l,mid,pos);
        else change(rc,mid+1,r,pos);
        update(x,l,r);
    }
    
    void build(int x,int l,int r) {
        if(l==r) { mx[x]=A[l]; sg[x]=A[l]+l; return; }
        build(lc,l,mid); build(rc,mid+1,r);
        update(x,l,r);
    }
    
    //#define DEBUG
    int main() {
    #ifdef DEBUG
        freopen("circle.in","r",stdin);
        freopen("circle.out","w",stdout);
    #endif
        read(n); read(m); read(p);
        For(i,1,n) { 
            read(T[i]); A[i]=T[i]-i; 
            T[i+n]=T[i]; A[i+n]=T[i+n]-(i+n);    
        }
        build(1,1,n*2);
        ans=sg[1]+n-1;
        printf("%d
    ",ans);
        For(i,1,m) {
            int x,y;
            read(x); read(y);
            if(p) x^=ans,y^=ans;
            T[x]=y; A[x]=T[x]-x;
            change(1,1,n*2,x);
            T[x+n]=y; A[x+n]=T[x+n]-(x+n);
            change(1,1,n*2,x+n);
            ans=sg[1]+n-1;
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    d1t3[HNOI/AHOI2018]毒瘤

    如果给出的一棵树,可以直接树dp,时间复杂度O(n)

    发现非树边很少,可以枚举非树边上的点的状态,然后dp,时间复杂度为2^d*n(只用枚举每条非树边中一个点的状态)

    考虑优化这个算法,发现每次树dp只有非树边上的点有影响,重复计算了很多没有必要的过程

    那么把非树边拿出来建虚树,每次在虚树上dp

    先对原树dp一次求出在虚树上dp要用到的系数

    设g[x][0/1]表示常数,即x的那些没有任何关键点的儿子的贡献.

    k[x][0/1][0/1]表示我对于我下面(包括我)第一个关键点的转移系数

    即(设我下面第一个关键点为w) 

    f[x][0]= k[x][0][0]*f[w][0]+k[x][0][1]*f[w][1];

    f[x][1]= k[x][1][0]*f[w][0]+k[x][1][1]*f[w][1];

    边界为若我为关键点,

    k[x][0][0]=1,k[x][0][1]=0;

    k[x][1][0]=0,k[x][1][1]=1;

    dp出k和g,就可以在虚树上转移了

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    #include<set>
    #define For(i,a,b) for(int i=(a);i<=(b);i++)
    #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
    const int N=200007,p=998244353;
    typedef long long LL; 
    typedef double db;
    using namespace std;
    int n,m,eu[N],ev[N],tot;
    
    template<typename T> void read(T &x) {
        char ch=getchar(); x=0; T f=1;
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    int ecnt,fir[N],nxt[N<<1],to[N<<1];
    void add(int u,int v) {
        nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
        nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
    }
    
    int sz[N],is[N],vis[N];
    void dfs(int x,int fa) {
        vis[x]=1;
        for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
            if(!vis[to[i]]) {
                dfs(to[i],x);
                sz[x]+=sz[to[i]];
            }
            else {
                is[x]=1;
                if(to[i]<x) eu[++tot]=x,ev[tot]=to[i];
            }
        }
        is[x]=(is[x]||sz[x]>=2);
        sz[x]=(sz[x]||is[x]);
    }
    
    struct pt {
        LL a,b;
        pt(){}
        pt(int a,int b):a(a),b(b){}
        friend pt operator +(const pt&A,const pt&B) {
            return pt((A.a+B.a)%p,(A.b+B.b)%p);
        }
        friend pt operator *(const pt&A,const LL&B) {
            return  pt(A.a*B%p,A.b*B%p);
        }
    }k[N][2];
    
    struct edge {
        int u,v,nx;
        pt x,y;
        edge(){}
        edge(int u,int v,pt x,pt y,int nx):u(u),v(v),x(x),y(y),nx(nx){}
    }e[N];
    
    int fi[N],ec;
    void ADD(int u,int v,pt x,pt y) {
        e[++ec]=edge(u,v,x,y,fi[u]); fi[u]=ec;
    }
    
    LL g[N][2],bx[N][2],f[N][2],ans;
    int pre(int x,int fa) {
        vis[x]=1;
        g[x][0]=g[x][1]=1;
        int rs=0;
        if(x==2874) {
            int debug=1;
        }
        for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]) {
            int w=pre(to[i],x); if(!rs) rs=w;
            if(!w) {
                g[x][0]=g[x][0]*((g[to[i]][0]+g[to[i]][1])%p)%p;
                g[x][1]=g[x][1]*g[to[i]][0]%p;
            }
            else if(is[x]) ADD(x,w,k[to[i]][0]+k[to[i]][1],k[to[i]][0]);
            else k[x][0]=k[to[i]][0]+k[to[i]][1],k[x][1]=k[to[i]][0];
        } 
        if(is[x]) k[x][0]=pt(1,0),k[x][1]=pt(0,1);
        else k[x][0]=k[x][0]*g[x][0],k[x][1]=k[x][1]*g[x][1];
        if(is[x]) rs=x;
        return rs;
    }
    
    void dp(int x) {
        f[x][0]=bx[x][1]?0:g[x][0];
        f[x][1]=bx[x][0]?0:g[x][1];
        for(int i=fi[x];i;i=e[i].nx) {
            int v=e[i].v; 
            pt a=e[i].x,b=e[i].y;
            dp(v);
            f[x][0]=(f[x][0]*(a.a*f[v][0]%p+a.b*f[v][1]%p))%p;
            f[x][1]=(f[x][1]*(b.a*f[v][0]%p+b.b*f[v][1]%p))%p;
        }
    }
    
    //#define DEBUG
    int main() {
    #ifdef DEBUG
        freopen("duliu.in","r",stdin);
        freopen("duliu.out","w",stdout);
    #endif
        read(n); read(m);
        For(i,1,m) {
            int u,v;
            read(u); read(v);
            add(u,v);    
        }
        dfs(1,0); is[1]=1;
        memset(vis,0,sizeof(vis));
        pre(1,0);
        int nn=(1<<tot)-1;
        For(i,0,nn) {
            For(j,1,tot) { 
                if(i&(1<<j-1)) {
                    bx[eu[j]][1]=1; bx[ev[j]][0]=1;
                }
                else bx[eu[j]][0]=1;
            }
            dp(1);
            ans=((ans+f[1][0])%p+f[1][1])%p;
            For(j,1,tot) { 
                if(i&(1<<j-1)) {
                    bx[eu[j]][1]=0; bx[ev[j]][0]=0;
                }
                else bx[eu[j]][0]=0;
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    /*
    12 17
    12 3
    12 5
    11 12
    7 5
    5 10
    1 5
    5 8
    8 7
    11 9
    3 6
    10 1
    1 9
    1 7
    12 4
    2 9
    11 2
    7 3
    */
    View Code

    d2t1游戏

    sxy的做法:

      一个点能走到的是一段区间,记为l[x],r[x]

      若一段路的钥匙在左端点及左边,那么只能从左走到右,从左到右连单向边.

      若钥匙在右端点及右边,那么只能从右走到左,单向边

      否则连双向边.预处理出这些边都能走的情况下左右最远走到哪里,记为ld,rd

      然后从左到右计算l,r,

      1.若我可以到左边,且钥匙在我这里或者不需要钥匙,那么l[x]=l[x-1],r[x]=r[x-1]

      2.若我到不了左边,在x~rd[x]中二分一个位置pos,使这从x到pos这一段的每一个位置的钥匙都在从x到它之间,l[x]=x,r[x]=pos

      3.我能到左边,拿不到钥匙.先和2一样二分一个pos,看在这一段中能不能拿到左边的钥匙,l[x]拓展到l[x-1],拿到这一段钥匙后继续往右边二分,然后再试图向左拓展

        发现每次向左拓展的点一定是之前未拓展到的,那么每条向左的边最多会使我向左拓展一次,每次向右拓展复杂的是一个log,总复杂的nlogn

    我的一个及其蠢的做法:

      发现如果从x能走到y(假使x在y左边,右边同理),设x到y的路径上最靠左的钥匙位置在z,走过的路径即为z,x,y这一段

      这一段路径要能走需要满足,x到y路径上任意一个点a,它的钥匙在的地方b,从x到b的每个点的钥匙必须在它右边且在a左边

      那么对于每个点x,它的钥匙在它左边的y,可以二分一个最靠右的z使y到z的路径上所有点的钥匙都在自己的右边且在x的左边,记录这个最靠右的位置为rans[x]

      那么x能走到y需要满足从x到y的rans都大于x

      对于rans可以用线段树记录所有点钥匙所在的位置,在线段树上二分,求出rans后第二个问题可以用线段树解决.

      同理考虑左边的lans

      x在y右边的情况同理

      时间复杂度nlogn,然而常数巨大..本机卡常卡过了,洛谷t了两个点

      1 // luogu-judger-enable-o2
      2 //Achen
      3 #include<algorithm>
      4 #include<iostream>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<vector>
      8 #include<cstdio>
      9 #include<queue>
     10 #include<cmath>
     11 #include<set>
     12 #define For(i,a,b) for(register int i=(a);i<=(b);i++)
     13 #define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
     14 const int N=1e6+7;
     15 typedef long long LL; 
     16 typedef double db;
     17 using namespace std;
     18 int n,m,q,yl[N];
     19 
     20 template<typename T> void read(T &x) {
     21     char ch=getchar(); x=0; T f=1;
     22     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
     23     if(ch=='-') f=-1,ch=getchar();
     24     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
     25 }
     26 
     27 #define lc x<<1
     28 #define rc ((x<<1)|1)
     29 #define mid ((l+r)>>1)
     30 int mx[N<<2],mi[N<<2];
     31 inline void build(int x,int l,int r) {
     32     if(l==r) { 
     33         mx[x]=mi[x]=yl[l]; 
     34         if(yl[l]==0) mx[x]=0,mi[x]=n+1; 
     35         return; 
     36     }
     37     build(lc,l,mid); build(rc,mid+1,r);
     38     mx[x]=max(mx[lc],mx[rc]);
     39     mi[x]=min(mi[lc],mi[rc]);
     40 }
     41 
     42 inline int qryl(int x,int l,int r,int ql,int qr,int v) {
     43     if(l>=ql&&r<=qr) {
     44         if(mx[x]<=v) return r;
     45         if(l==r) return 0;
     46         if(mx[lc]<=v) {
     47             int rs=qryl(rc,mid+1,r,ql,qr,v);
     48             if(!rs) rs=mid;
     49             return rs;
     50         }
     51         else return qryl(lc,l,mid,ql,qr,v);
     52     }
     53     int rs=0;
     54     if(ql>mid) return qryl(rc,mid+1,r,ql,qr,v);
     55     if(qr<=mid) return qryl(lc,l,mid,ql,qr,v);
     56     else {
     57         rs=qryl(lc,l,mid,ql,qr,v);
     58         int rs2=0;
     59         if(rs==mid) rs2=qryl(rc,mid+1,r,ql,qr,v);
     60         if(rs2) rs=rs2;
     61         return rs;
     62     }  
     63 }
     64 
     65 inline int qryr(int x,int l,int r,int ql,int qr,int v) {
     66     if(l>=ql&&r<=qr) {
     67         if(mi[x]>=v) return l;
     68         if(l==r) return 0;
     69         if(mi[rc]>=v) {
     70             int rs=qryr(lc,l,mid,ql,qr,v);
     71             if(!rs) rs=mid+1;
     72             return rs;
     73         }
     74         else return qryr(rc,mid+1,r,ql,qr,v);
     75     }
     76     int rs=0;
     77     if(ql>mid) return qryr(rc,mid+1,r,ql,qr,v);
     78     if(qr<=mid) return qryr(lc,l,mid,ql,qr,v);
     79     else {
     80         rs=qryr(rc,mid+1,r,ql,qr,v);
     81         int rs2=0;
     82         if(rs==mid+1) rs2=qryr(lc,l,mid,ql,qr,v);
     83         if(rs2) rs=rs2;
     84         return rs;    
     85     }
     86 }
     87 
     88 int lans[N],rans[N];
     89 int sgmi[N<<2],sgmx[N<<2];
     90 inline void build2(int x,int l,int r) {
     91     if(l==r) { sgmi[x]=rans[l]; sgmx[x]=lans[l]; return; }
     92     build2(lc,l,mid); build2(rc,mid+1,r);
     93     sgmi[x]=min(sgmi[lc],sgmi[rc]);    
     94     sgmx[x]=max(sgmx[lc],sgmx[rc]);
     95 }
     96 
     97 inline int qrymi(int x,int l,int r,int ql,int qr,int sg[]) {
     98     if(l>=ql&&r<=qr) return sg[x];
     99     if(qr<=mid) return qrymi(lc,l,mid,ql,qr,sg);
    100     if(ql>mid) return qrymi(rc,mid+1,r,ql,qr,sg);
    101     return min(qrymi(lc,l,mid,ql,qr,sg),qrymi(rc,mid+1,r,ql,qr,sg));
    102 }
    103 
    104 inline int qrymx(int x,int l,int r,int ql,int qr,int sg[]) {
    105     if(l>=ql&&r<=qr) return sg[x];
    106     if(qr<=mid) return qrymx(lc,l,mid,ql,qr,sg);
    107     if(ql>mid) return qrymx(rc,mid+1,r,ql,qr,sg);
    108     return max(qrymx(lc,l,mid,ql,qr,sg),qrymx(rc,mid+1,r,ql,qr,sg));
    109 }
    110 
    111 //#define DEBUG
    112 int main() {
    113 #ifdef DEBUG
    114     freopen("game.in","r",stdin);
    115     freopen("game.out","w",stdout);
    116 #endif
    117     read(n); read(m); read(q);
    118     For(i,1,m) {
    119         int x,y;
    120         read(x); read(y);
    121         yl[x]=y;
    122     }
    123     build(1,1,n-1);
    124     For(i,1,n) {
    125         if(yl[i]==0) {
    126             lans[i]=0;
    127             rans[i]=n+1;
    128         }
    129         else {
    130             if(yl[i]>i) 
    131                 lans[i]=qryr(1,1,n-1,1,yl[i]-1,i+1);
    132             else lans[i]=n+1;
    133             if(yl[i]<=i) 
    134                 rans[i]=qryl(1,1,n-1,yl[i],n,i);
    135             else rans[i]=0;
    136         }
    137     }
    138     build2(1,1,n-1);
    139     For(i,1,q) {
    140         int x,y;
    141         read(x); read(y);
    142         if(x==y) puts("YES");
    143         else if(x<=y) {
    144             int z=qrymi(1,1,n-1,x,y-1,mi);
    145             int tp1=qrymi(1,1,n-1,x,y-1,sgmi);
    146             int tp2=z>x-1?x:qrymx(1,1,n-1,z,x-1,sgmx);
    147             if(tp1>=max(1,x-1)&&tp2<=min(n,x+1)) puts("YES");
    148             else puts("NO");
    149         }
    150         else {
    151             int z=qrymx(1,1,n-1,y,x-1,mx);
    152             int tp2=qrymx(1,1,n-1,y,x-1,sgmx);
    153             int tp1=z-1<x?x:qrymi(1,1,n-1,x,z-1,sgmi);
    154             if(tp1>=max(1,x-1)&&tp2<=min(n,x+1)) puts("YES");
    155             else puts("NO");
    156         }
    157     }
    158     return 0;
    159 }
    View Code

    正解:按sxy的做法把图建出来后,按拓扑序拓展,似乎就可以直接做到O(n)了

    d2t2排列

    读题读好久..转换过来就是,给一棵树,父亲必须比儿子先选,选出来的序列记为p,答案为i*p[i]的和

    贪心

    考虑合并两段区间a,b,区间内已经合并好了,若a放在b前面更优,则说明len[a]*val[b]>len[b]*val[a]

    即len[a]/val[a]>len[b]/val[b];

    那么优先队列存每段区间的len和val,每次取出队首和父亲合并即可.

     1 //Achen
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdlib>
     6 #include<vector>
     7 #include<cstdio>
     8 #include<queue>
     9 #include<cmath>
    10 #include<set>
    11 #define For(i,a,b) for(int i=(a);i<=(b);i++)
    12 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
    13 const int N=1000007;
    14 typedef long long LL; 
    15 typedef double db;
    16 using namespace std;
    17 int n,a[N],w[N],fa[N],len[N];
    18 LL sum[N];
    19 
    20 template<typename T> void read(T &x) {
    21     char ch=getchar(); x=0; T f=1;
    22     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    23     if(ch=='-') f=-1,ch=getchar();
    24     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    25 }
    26 
    27 struct node {
    28     int x,sz; LL sum;
    29     node(int x,int sz,LL sum):x(x),sz(sz),sum(sum){}
    30     friend bool operator <(const node&A,const node&B) {
    31         return A.sz*B.sum<B.sz*A.sum;
    32     }
    33 };
    34 
    35 int ecnt,fir[N],nxt[N],to[N],in[N];
    36 void add(int u,int v) {
    37     nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; in[v]++;
    38 }
    39 
    40 queue<int>q;
    41 LL tpsort() {
    42     int tot=0;
    43     For(i,1,n) if(!in[i]) q.push(i);
    44     while(!q.empty()) {
    45         int x=q.front();
    46         q.pop();
    47         tot++;
    48         for(int i=fir[x];i;i=nxt[i]) {
    49             in[to[i]]--;
    50             if(!in[to[i]]) q.push(to[i]);
    51         }
    52     } 
    53     if(tot!=n) return -1;
    54     return 1;
    55 }
    56 
    57 int f[N];
    58 int find(int x) { return x==f[x]?f[x]:f[x]=find(f[x]); }
    59 
    60 priority_queue<node>que;
    61 LL solve() {
    62     LL rs=0;
    63     For(i,1,n) rs+=w[i],f[i]=i;
    64     while(!que.empty()) {
    65         node tp=que.top();
    66         que.pop(); 
    67         if(tp.sz!=len[tp.x]) continue;
    68         int F=find(fa[tp.x]);
    69         rs+=sum[tp.x]*len[F];
    70         sum[F]+=sum[tp.x]; 
    71         len[F]+=len[tp.x];
    72         f[tp.x]=F;
    73         if(F) que.push(node(F,len[F],sum[F])); 
    74     }
    75     return rs;
    76 }
    77 
    78 //#define DEBUG
    79 int main() {
    80 #ifdef DEBUG
    81     freopen("perm.in","r",stdin);
    82     freopen("perm.out","w",stdout);
    83 #endif
    84     read(n);
    85     For(i,1,n) {
    86         read(a[i]);
    87         if(a[i]) { fa[i]=a[i]; add(a[i],i); }
    88     }
    89     For(i,1,n) read(w[i]);
    90     if(tpsort()==-1) puts("-1");
    91     else {
    92         For(i,1,n) {
    93             sum[i]=w[i]; len[i]=1;
    94             que.push(node(i,1,sum[i])); 
    95         }
    96         printf("%lld
    ",solve());
    97     }
    98     return 0;
    99 }
    View Code

    d2t3[HNOI/AHOI2018]道路

    一道水题,直接树形dp,记录上面的公路和铁路的条数.

    一开始不知道为什么以为是满二叉树,空间炸了.

    深度有40,不炸空间要开map存.

      1 //Achen
      2 #include<algorithm>
      3 #include<iostream>
      4 #include<cstring>
      5 #include<cstdlib>
      6 #include<vector>
      7 #include<cstdio>
      8 #include<queue>
      9 #include<cmath>
     10 #include<set>
     11 #include<map>
     12 #define For(i,a,b) for(int i=(a);i<=(b);i++)
     13 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
     14 const int N=40007;
     15 typedef long long LL; 
     16 typedef double db;
     17 using namespace std;
     18 LL n,a[N],b[N],c[N],gls[N],tls[N];
     19 map<int,LL>dp[N];
     20 
     21 template<typename T> void read(T &x) {
     22     char ch=getchar(); x=0; T f=1;
     23     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
     24     if(ch=='-') f=-1,ch=getchar();
     25     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
     26 }
     27 
     28 void add(int u,int v,int o) {
     29     if(!o) gls[u]=v;
     30     else tls[u]=v;
     31 }
     32 
     33 void dfs(int x,int l1,int l2) { //i gonglu
     34     if(!gls[x]) {
     35         For(i,0,l1) For(j,0,l2) dp[x][i*100+j]=c[x]*(a[x]+i)*(b[x]+j);
     36         return ;
     37     }
     38     int gl=gls[x],tl=tls[x];
     39     dfs(gl,l1+1,l2); dfs(tl,l1,l2+1);
     40     For(i,0,l1) For(j,0,l2) 
     41         dp[x][i*100+j]=min(dp[gl][i*100+j]+dp[tl][i*100+j+1],dp[gl][(i+1)*100+j]+dp[tl][i*100+j]);
     42 }
     43 
     44 //#define DEBUG
     45 int main() {
     46 #ifdef DEBUG
     47     freopen("road.in","r",stdin);
     48     freopen("road.out","w",stdout);
     49 #endif
     50     read(n);
     51     For(i,1,n-1) {
     52         int si,ti;
     53         read(si); read(ti);
     54         if(si>0) add(i+n,n+si,0);
     55         else add(i+n,-si,0);
     56         if(ti>0) add(i+n,n+ti,1);
     57         else add(i+n,-ti,1);
     58     }
     59     For(i,1,n) { read(a[i]); read(b[i]); read(c[i]); }
     60     dfs(1+n,0,0);
     61     printf("%lld
    ",dp[n+1][0]);
     62     return 0;
     63 }
     64 /*
     65 6
     66 2 3
     67 4 5
     68 -1 -2
     69 -3 -4
     70 -5 -6
     71 1 2 3
     72 1 3 2
     73 2 1 3
     74 2 3 1
     75 3 1 2
     76 3 2 1
     77 
     78 9
     79 2 -2
     80 3 -3
     81 4 -4
     82 5 -5
     83 6 -6
     84 7 -7
     85 8 -8
     86 -1 -9
     87 1 60 1
     88 1 60 1
     89 1 60 1
     90 1 60 1
     91 1 60 1
     92 1 60 1
     93 1 60 1
     94 1 60 1
     95 1 60 1
     96 
     97 12
     98 2 4
     99 5 3
    100 -7 10
    101 11 9
    102 -1 6
    103 8 7
    104 -6 -10
    105 -9 -4
    106 -12 -5
    107 -2 -3
    108 -8 -11
    109 53 26 491
    110 24 58 190
    111 17 37 356
    112 15 51 997
    113 30 19 398
    114 3 45 27
    115 52 55 838
    116 16 18 931
    117 58 24 212
    118 43 25 198
    119 54 15 172
    120 34 5 524
    121 */
    View Code

    Orz cai大佬day2AK进队

    Orz sxyday2AK吊打我这种辣鸡滚粗选手

    你们都太强啦%%%

  • 相关阅读:
    PHP 如何阻止用户上传成人照片或者裸照
    centos 从php5.1升级php到5.3的方法
    用jQuery实现鼠标移动切换图片动画
    利用表格实现大图轮播
    css导行下拉动画
    java script 基本函数
    java script 数组去重两种方法
    java script两个列表之间移动数据
    JavaScript做个时间表 Date()
    JS For 循环详解;棋盘放粮食 64;冒泡排序实例
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8921650.html
Copyright © 2011-2022 走看看