zoukankan      html  css  js  c++  java
  • 多省联测

     画风上来讲是最正常的一套省选题了,虽然我还是菜菜的。

    d1t1一双木棋chess

    签到题,轮廓线状压dp。然而愚蠢如我还是写挂了。
    怕被卡常开链表hash存状态,大的hash值因为n最大到10应该用11进制,用了10进制然后GG。

    sxy同学map+记忆化搜索踩爆我。

    //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--)
    typedef long long LL; 
    typedef double db;
    using namespace std;
    const int N=4e6+7,bs=13,mod=1799797;
    int n,m,tot,p[15],fir[mod+2],nxt[N];
    LL hash[N],hash2[N],power[15],power2[15];
    int A[15][15],B[15][15],f[2][N];
    
    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;
    }
    
    void add() {
        LL H=0,H2=0;
        For(i,1,m) {
            H=H*11+p[i];
            H2=(H2*bs+p[i])%mod;
        }
        nxt[++tot]=fir[H2]; fir[H2]=tot; hash[tot]=H; hash2[tot]=H2;
    }
    
    void dfs(int pos) {
        if(pos==m+1) {
            add();
            return ;
        }
        Rep(i,p[pos-1],0) {
            p[pos]=i; 
            dfs(pos+1);
        }
    }
    
    int get(LL H,int pos) {
        return H/power[pos-1]%11;
    }
    
    int get_id(LL H,LL H2,int pos,int h) {
        H=H+power[pos-1];
        H2=(H2+power2[pos-1])%mod;
        for(int i=fir[H2];i;i=nxt[i]) if(hash[i]==H)
            return i;
    }
    
    #define DEBUG 
    int main() {
    #ifdef DEBUG
        freopen("chess.in","r",stdin);
        freopen("chess.out","w",stdout);
    #endif
        memset(f[0],127,sizeof(f[0]));
        memset(f[1],128,sizeof(f[1]));
        read(n); read(m);
        p[0]=n; dfs(1); power[0]=power2[0]=1; 
        For(i,1,10) {
            power[i]=power[i-1]*11;
            power2[i]=power2[i-1]*bs%mod;
        }
        For(i,1,n) For(j,1,m) read(A[i][j]);
        For(i,1,n) For(j,1,m) read(B[i][j]);
        f[0][1]=0; f[1][1]=0;//1:hei 0:bai
        For(i,1,tot) {
            LL H=hash[i],H2=hash2[i];
            For(j,1,m) {
                int h=get(H,j),hpr=get(H,j+1);
                if(h==n||(j!=m&&h==hpr)) continue;
                int id=get_id(H,H2,j,h);
                f[0][i]=min(f[0][i],f[1][id]-B[h+1][m-j+1]);
                f[1][i]=max(f[1][i],f[0][id]+A[h+1][m-j+1]);
            }
        }
        printf("%d
    ",f[1][tot]);
        return 0;
    }
    View Code

     

    d1t2IIIDX

    太菜啦只会55分贪心,然后数据良心有60.

    正解奥妙重重。

    因为存在相同值,贪心显然是不对的,一个可以卡的数据是

    考虑将数从大到小排序,选第一个数时,若它的子树大小为x,我们会选第x大的数作为它的值,然后1~x的值给它和它的子树。

    然而若x右边还存在一些和x相等的数,把这些数中的一部分给x的儿子,就可以从x前面更大的数中选一些来给x的兄弟——x的兄弟的优先级一定比x的儿子高,结果也就更优了。

    怎么办,emmmmm,我也不知道为什么就想到了这种奥妙的操作,我们考虑找到x右边最后一个和x相等的值的位置,在这个位置之前给x的子树预留sz那么多个数,然后再去考虑x的兄弟。

    具体的做法是,用f[i]表i左边还可以选多少个数,f[i]=i-(i左边已经被预定的数)。

    当找到一个最靠右的x,要在它左边预留sz个数的时候,把x右边包括x在内所有数的f值减去sz。

    然后每次找当前可用最大值是在线段树上二分到一个右边所有f都大于sz的位置。

    为什么这样是对的。考虑二分到一个位置x,x及右边所有f的最小值即为x及左边可用的位置数,因为所有预定区间中,完全包括在x左边的区间的值在x上已经减去了,预定在x右边的值又会在去min的时候限制到整段大区间,从而限制到x。

      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=5e5+7;
     14 typedef long long LL; 
     15 typedef double db;
     16 using namespace std;
     17 int n,d[N],dd[N],sta[N],v[N],sz[N],cnt[N],tot,top,fa[N],vis[N];
     18 db k;
     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 bool cmp(const int &A,const int &B) {
     28     return A>B;
     29 }
     30 
     31 int ecnt,fir[N],nxt[N<<1],to[N<<1];
     32 void add(int u,int v) {
     33     nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
     34 }
     35 
     36 int sg[N<<2],lz[N<<2];
     37 #define lc x<<1
     38 #define rc ((x<<1)|1)
     39 #define mid ((l+r)>>1)
     40 void down(int x,int l_len,int r_len) {
     41     if(!lz[x]) return;
     42     if(l_len) sg[lc]+=lz[x],lz[lc]+=lz[x];
     43     if(r_len) sg[rc]+=lz[x],lz[rc]+=lz[x];
     44     lz[x]=0;
     45 }
     46 
     47 void update(int x,int l,int r,int ql,int qr,int v) {
     48     if(l>=ql&&r<=qr) {
     49         sg[x]+=v; lz[x]+=v; return;
     50     }
     51     down(x,mid-l+1,r-mid);
     52     if(ql<=mid) update(lc,l,mid,ql,qr,v);
     53     if(qr>mid) update(rc,mid+1,r,ql,qr,v);
     54     sg[x]=min(sg[lc],sg[rc]);
     55 } 
     56 
     57 void build(int x,int l,int r) {
     58     if(l==r) { sg[x]=cnt[l]; return; }
     59     build(lc,l,mid); build(rc,mid+1,r);
     60     sg[x]=min(sg[lc],sg[rc]); 
     61 }
     62 
     63 int qry(int x,int l,int r,int mi) {
     64     if(sg[x]>=mi) return l;
     65     if(l==r) return 0;
     66     down(x,mid-l+1,r-mid);
     67     if(sg[rc]>=mi) {
     68         int rs=qry(lc,l,mid,mi);
     69         if(!rs) rs=mid+1; return rs;
     70     } 
     71     else return qry(rc,mid+1,r,mi);
     72 }
     73 
     74 void dfs(int x) {
     75     sz[x]=1;
     76     for(int i=fir[x];i;i=nxt[i]) {
     77         dfs(to[i]);
     78         sz[x]+=sz[to[i]];
     79     }
     80 }
     81 
     82 #define DEBUG
     83 int main() {
     84 #ifdef DEBUG
     85     freopen("iiidx.in","r",stdin);
     86     freopen("iiidx.out","w",stdout);
     87 #endif
     88     read(n); scanf("%lf",&k);
     89     For(i,1,n) read(d[i]);
     90     sort(d+1,d+n+1,cmp);
     91     For(i,1,n) {
     92         if(i==1||d[i]!=d[i-1]) tot++;
     93         cnt[tot]++; dd[tot]=d[i];
     94     }
     95     For(i,2,tot) cnt[i]+=cnt[i-1];
     96     build(1,1,tot);
     97     Rep(i,n,1) {
     98         db f=(db)i/k;
     99         fa[i]=f;
    100         if(fa[i]) add(fa[i],i);
    101         else sta[++top]=i;
    102     }
    103     while(top) {
    104         dfs(sta[top--]);
    105     }
    106     For(i,1,n) {
    107         if(fa[i]&&!vis[fa[i]]) {
    108             update(1,1,tot,v[fa[i]],tot,sz[fa[i]]-1);
    109             vis[fa[i]]=1;
    110         }
    111         v[i]=qry(1,1,tot,sz[i]);
    112         update(1,1,tot,v[i],tot,-sz[i]);
    113     }
    114     For(i,1,n-1) printf("%d ",dd[v[i]]);
    115     printf("%d
    ",dd[v[n]]); 
    116     return 0;
    117 }
    View Code

     

    d1t3秘密袭击coat

    这里就是题解中说的学傻了在想点分治+FFT的人。

    然后写了个NTT暴力,死活过不了样例,发现模数不能NTT(需满足p=2^k*奇数+1且2^k>2*p)

    然后失去信仰打了个暴力树dp吊打标解。

    标解似乎是什么拉格朗日+线段树合并优化背包。Orz orz%%%完全不会。

     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=2149,mod=64123;
    14 typedef long long LL; 
    15 typedef double db;
    16 using namespace std;
    17 LL f[1995][N],ans;
    18 int v[N],tot,n,k,w,d[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 int ecnt,fir[N],nxt[N<<1],to[N<<2],sz[N];
    28 void add(int x,int y) {
    29     nxt[++ecnt]=fir[x]; fir[x]=ecnt; to[ecnt]=y;
    30     nxt[++ecnt]=fir[y]; fir[y]=ecnt; to[ecnt]=x;
    31 }
    32 
    33 void dfs(int x,int fa) {
    34     For(i,0,k) f[x][i]=0;
    35     f[x][v[x]]=1; sz[x]=v[x];
    36     for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
    37         dfs(to[i],x);
    38         Rep(j,sz[x],0) {
    39             LL tp=f[x][j];
    40             Rep(l,sz[to[i]],0) { 
    41                 int y=min(j+l,k);
    42                 f[x][y]+=tp*f[to[i]][l]%mod;
    43                 if(f[x][y]>=mod) f[x][y]-=mod;
    44             }
    45         }
    46         sz[x]+=sz[to[i]]; sz[x]=min(sz[x],k);
    47     }
    48 }
    49 
    50 #define DEBUG
    51 int main() {
    52 #ifdef DEBUG
    53     freopen("coat.in","r",stdin);
    54     freopen("coat.out","w",stdout);
    55 #endif
    56     read(n); read(k); read(w);
    57     For(i,1,n) read(d[i]);
    58     For(i,2,n) {
    59         int x,y;
    60         read(x); read(y);
    61         add(x,y);
    62     }
    63     For(W,1,w) {
    64         tot=0;
    65         For(i,1,n) { v[i]=(d[i]>=W); tot+=v[i]; }
    66         if(tot<k) continue;
    67         dfs(1,0);
    68         For(i,1,n) {
    69             ans+=f[i][k];
    70             if(ans>=mod) ans-=mod;
    71         }
    72     }
    73     printf("%lld
    ",ans);
    74     return 0;
    75 }
    View Code

     

    d2t1劈配

    匈牙利乱搞瞎暴力,然后就过了。

    把匈牙利中每个导师的pr换成一个vector,只要还没满就继续往vector里塞。

    每个人连出去的边也用vector存,对于匹配到的当前选手,用边集由志愿从小到大的顺序尝试匹配,之前匹配的选手就只能用它的答案的边集了。

    第二问二分再暴力匹配,我直接用vector把第一问每个选手匹配前的pr状态复制下来了,然后二分后直接回到那个状态去重新暴力匹配。

      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=207;
     14 typedef long long LL; 
     15 typedef double db;
     16 using namespace std;
     17 int n,m,b[N],bb[N],s[N],a[N][N],ans[N][2],vis[N];
     18 vector<int>vc[N][N];
     19 vector<int>pr[N];
     20 vector<int>tppr[N];
     21 vector<int>P[N][N];
     22 
     23 template<typename T> void read(T &x) {
     24     char ch=getchar(); x=0; T f=1;
     25     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
     26     if(ch=='-') f=-1,ch=getchar();
     27     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
     28 }
     29 
     30 int find(int x,int k) {
     31     int up=vc[x][k].size();
     32     For(i,0,up-1) {
     33         int y=vc[x][k][i];
     34         if(!vis[y]) {
     35             vis[y]=1;
     36             int upp=pr[y].size();
     37             if(upp<b[y]) {
     38                 pr[y].push_back(x);
     39                 return 1;
     40             }
     41             else {
     42                 For(j,0,upp-1) {
     43                     int z=pr[y][j];
     44                     if(find(z,ans[z][0])) {
     45                         pr[y][j]=x;
     46                         return 1;
     47                     }
     48                 }
     49             }
     50         }
     51     }
     52     return 0;
     53 }
     54 
     55 int find2(int x,int k) {
     56     int up=vc[x][k].size();
     57     For(i,0,up-1) {
     58         int y=vc[x][k][i];
     59         if(!vis[y]) {
     60             vis[y]=1;
     61             int upp=tppr[y].size();
     62             if(upp<b[y]) {
     63                 tppr[y].push_back(x);
     64                 return 1;
     65             }
     66             else {
     67                 For(j,0,upp-1) {
     68                     int z=tppr[y][j];
     69                     if(find2(z,ans[z][0])) {
     70                         tppr[y][j]=x;
     71                         return 1;
     72                     }
     73                 }
     74             }
     75         }
     76     }
     77     return 0;
     78 }
     79 
     80 int ck(int x,int pos) {
     81     For(i,1,m) {
     82         tppr[i]=P[pos][i];
     83         //cerr<<tppr[i].size()<<endl;
     84     }
     85     int rs=0;
     86     Rep(i,s[x],1) {
     87         memset(vis,0,sizeof(vis));
     88         rs=find2(x,i);
     89         if(rs) break;
     90     }
     91     return rs;
     92 }
     93 
     94 #define DEBUG
     95 int main() {
     96 #ifdef DEBUG
     97     freopen("mentor.in","r",stdin);
     98     freopen("mentor.out","w",stdout);
     99 #endif
    100     int T,C;
    101     read(T); read(C);
    102     while(T--) {
    103         read(n); read(m);
    104         For(i,1,n) For(j,1,m) vc[i][j].clear();
    105         For(i,1,m) pr[i].clear();
    106         For(i,1,m) read(b[i]);
    107         For(i,1,n) For(j,1,m) {
    108             int x;
    109             read(x);
    110             a[i][j]=x;
    111             if(x) vc[i][x].push_back(j);
    112         }
    113         For(i,1,n) read(s[i]);
    114         For(i,1,n) {
    115             For(j,1,m) {
    116                 P[i][j]=pr[j];
    117                 //cerr<<P[i][j].size()<<endl;    
    118             }
    119             int rs=0;
    120             For(j,1,m) {
    121                 if(!vc[i][j].empty()) {
    122                     memset(vis,0,sizeof(vis));
    123                     rs=find(i,j);
    124                 }
    125                 if(rs) { ans[i][0]=j; break;}
    126             }
    127             if(!rs) ans[i][0]=m+1;
    128         }
    129         For(i,1,n) {
    130             int fl=0;
    131             if(ans[i][0]<=s[i]) { ans[i][1]=0; continue; }
    132             For(j,1,s[i]) if(!vc[i][j].empty()) { fl=1; break; }
    133             if(!fl) ans[i][1]=i;
    134             else {
    135                 int l=1,r=i-1,ok=0;
    136                 while(l<=r) {
    137                     int mid=((l+r)>>1);
    138                     if(ck(i,mid)) ok=mid,l=mid+1;
    139                     else r=mid-1;
    140                 }
    141                 ans[i][1]=i-ok;
    142             } 
    143         }
    144         For(i,1,n-1) printf("%d ",ans[i][0]);
    145         printf("%d
    ",ans[n][0]);
    146         For(i,1,n-1) printf("%d ",ans[i][1]);
    147         printf("%d
    ",ans[n][1]);
    148     }
    149     return 0;
    150 }
    151 /*
    152 3 5
    153 2 2
    154 1 1
    155 2 2
    156 1 2
    157 1 1
    158 2 2
    159 1 1
    160 1 2
    161 1 2
    162 2 1
    163 2 2
    164 1 1
    165 0 1
    166 0 1
    167 2 2
    168 */ 
    View Code

     

    d2t2林克卡特树

    60分做法,k很小。

    题目等价于在树上选k条点不相交的链,使权值和最大。

    f[x][k][0/1/2]表示在x的子树中选了k条链,x的度数为0,1,2的最优方案。

    100分做法,发现答案对于k是凸包

    然后二分斜率卡凸包

    ????我也不知道它在说什么

    问了学长,还没得到回复

     

    d2t3制胡窜

    一道毒瘤数据结构码农题。

    我写不出来。。。

     太神啦 %%%%%

     

     

     

  • 相关阅读:
    放大镜功能
    background兼容IE9以下版本
    JSON解析
    vue.js 组件-全局组件和局部组件
    i++ ++i的原子性
    【转】程序员面试笔试宝典
    【转】函数调用栈 格式化操作
    【转】TCP三次握手过程
    一些面试题
    【转】HP(惠普)大中华区总裁孙振耀退休感言
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8869906.html
Copyright © 2011-2022 走看看