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吊打我这种辣鸡滚粗选手

    你们都太强啦%%%

  • 相关阅读:
    每日一篇文献:Robotic pick-and-place of novel objects in clutter with multi-affordance grasping and cross-domain image matching
    每日一篇文献:Intuitive Bare-Hand Teleoperation of a Robotic Manipulator Using Virtual Reality and Leap Motion
    每日一篇文献:Virtual Kinesthetic Teaching for Bimanual Telemanipulation
    HEBI Robotic Arm VR Teleoperation
    「iQuotient Case」AR device teleoperated robotic arm
    VR and Digital Twin Based Teleoperation of Robotic Arm
    HEBI Robotic Arm VR Teleoperation
    Human Robot Interaction
    Immersive Teleoperation Project
    机器人演示学习
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8921650.html
Copyright © 2011-2022 走看看