zoukankan      html  css  js  c++  java
  • 20180418小测

    T1:


    看到这种东西就想二维数点。
    如果圆弧i和圆弧j能贡献答案的话(假设i在左边),需要满足 Li<Lj && Ri<Rj && Lj<Ri && Coli!=Colj 。
    我们先不管最后颜色的那个限制,如果我们确定了i之后,能有贡献的j需要满足: Li<Lj && Lj<Ri && Rj>Ri .
    这样我们按照左端点建立主席树,把右端点插进去,就能统计了。
    然后再按照颜色分类,计算颜色相同的贡献减去,就能得到答案。
    复杂度O(sigma(Si^2)logn),能获得70分。
    正解大概是均衡不同复杂度算法之类的东西,然而并不能想到不同复杂度的算法(然后题解真是这样的)。
    70分暴力代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<vector>
     6 #include<map>
     7 #include<cctype>
     8 #define debug cout
     9 using namespace std;
    10 const int maxn=1e5+1e2,maxe=2e7+1e2;
    11 const int mod=1e9+7;
    12 
    13 struct PersistentSegmentTree {
    14     int lson[maxe],rson[maxe],dat[maxe],cnt;
    15     inline void insert(int &pos,int pre,int l,int r,const int &tar) {
    16         dat[pos=++cnt] = dat[pre] + 1;
    17         if( l == r ) return;
    18         const int mid = ( l + r ) >> 1;
    19         if( tar <= mid ) insert(lson[pos],lson[pre],l,mid,tar) , rson[pos] = rson[pre];
    20         else insert(rson[pos],rson[pre],mid+1,r,tar) , lson[pos] = lson[pre];
    21     }
    22     inline int query(int pos,int pre,int l,int r,const int &ll,const int &rr) {
    23         if( !pos || dat[pos] == dat[pre] ) return 0;
    24         if( ll <= l && r <= rr ) return dat[pos] - dat[pre];
    25         const int mid = ( l + r ) >> 1;
    26         if( rr <= mid ) return query(lson[pos],lson[pre],l,mid,ll,rr);
    27         else if( ll > mid ) return query(rson[pos],rson[pre],mid+1,r,ll,rr);
    28         return query(lson[pos],lson[pre],l,mid,ll,rr) + query(rson[pos],rson[pre],mid+1,r,ll,rr);
    29     }
    30     inline void reset() {
    31         memset(dat+1,0,sizeof(int)*cnt) , memset(lson+1,0,sizeof(int)*cnt) , memset(rson+1,0,sizeof(int)*cnt) , cnt = 0;
    32     }
    33 }pst;
    34 
    35 int in[maxn],root[maxn],n,cnt,ans,sub;
    36 vector<int> pos[maxn];
    37 map<int,int> id;
    38 
    39 inline int getint() {
    40     int ret = 0 , fix = 1 , ch;
    41     while( !isdigit(ch=getchar()) ) fix = ch == '-' ? -fix : fix;
    42     do ret=ret*10+ch-'0'; while( isdigit(ch=getchar()) );
    43     return ret * fix;
    44 }
    45 
    46 int main() {
    47     n = getint();
    48     for(int i=1;i<=n;i++) {
    49         in[i] = getint();
    50         if( id.find(in[i]) == id.end() ) id[in[i]] = ++cnt;
    51         pos[id[in[i]]].push_back(i);
    52     }
    53     for(int i=n,iid;i;i--) {
    54         root[i] = root[i+1] , iid = id[in[i]];
    55         for(unsigned j=0;j<pos[iid].size();j++) if( pos[iid][j] > i ) {
    56             pst.insert(root[i],root[i],1,n,pos[iid][j]);
    57             ans += pst.query(root[i+1],root[pos[iid][j]],1,n,pos[iid][j]+1,n);
    58         }
    59         ans %= mod;
    60     }
    61     for(int i=1;i<=cnt;i++) {
    62         pst.reset() , memset(root,0,sizeof(int)*(pos[i].size()+2));
    63         for(int j=(signed)pos[i].size()-1;j>=0;j--) { // j is left point of now .
    64             root[j] = root[j+1];
    65             for(unsigned k=j+1;k<pos[i].size();k++) { // k is right point of now .
    66                 pst.insert(root[j],root[j],1,n,pos[i][k]);
    67                 sub += pst.query(root[j+1],root[k],1,n,pos[i][k]+1,n);
    68             }
    69             sub %= mod;
    70         }
    71     }
    72     ans = ( ans - sub + mod ) % mod;
    73     printf("%d
    ",ans);
    74     return 0;
    75 }
    View Code


    T2:


    全场就我不会做这题,高一学弟都会做......
    我考虑枚举中间点,然后计算两遍有长度限制的大于/小于点数,发现并不可做,然后就O(n^2)暴力滚粗了。
    正解是枚举右端点,计算中间点和左端点的贡献。
    显然先要断环成链,我们用一颗权值线段树维护权值为i的点,左边比他小的点的个数fi。然后从左向右(n->2*n-1)枚举当前右端点,需要记录答案的就是sum(f1->f(in[i]-1))。
    考虑怎么预处理出前n个点的区间的这个值,直接线段树求顺序对即可。
    考虑怎么从区间[i,i+n-1]转移到区间[i+1,i+n]。显然对于权值>in[i]的所有点,其左边的点少了一个,应该区间-1。
    考虑新加入的in[i+n],所有的点都在他的左边,所以他的权值应该为in[i+n]-1。并且更新前权值为0(因为左边没有其他点)。
    然后就是老年选手身败名裂的故事了。
    60分暴力代码:

     1 #include<cstdio>
     2 typedef long long int lli;
     3 const int maxn=5e3+1e2;
     4 
     5 int in[maxn<<1],n;
     6 lli f[maxn][maxn],ans;
     7 
     8 int main() {
     9     scanf("%d",&n);
    10     for(int i=1;i<=n;i++) scanf("%d",in+i) , in[i+n] = in[i];
    11     for(int i=1;i<=n;i++) for(int j=1;j<n;j++) f[i][j] = f[i][j-1] + ( in[i+j] > in[i] );
    12     for(int i=1;i<=n;i++) for(int j=i+1;j<i+n;j++) if( in[j] > in[i] ) ans += f[j>n?j-n:j][n-(j-i+1)];
    13     printf("%lld
    ",ans);
    14     return 0;
    15 }
    View Code

    正解代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define debug cout
     6 typedef long long int lli;
     7 using namespace std;
     8 const int maxn=2e5+1e2;
     9 
    10 class SegmentTree {
    11     private:
    12     int l[maxn<<3],r[maxn<<3],lson[maxn<<3],rson[maxn<<3],cnt;
    13     lli dat[maxn<<3],lazy[maxn<<3];
    14     public:
    15     SegmentTree() { cnt = 1; }
    16     inline void build(int pos,int ll,int rr) {
    17         l[pos] = ll , r[pos] = rr;
    18         if( ll == rr ) return;
    19         const int mid = ( ll + rr ) >> 1;
    20         build(lson[pos]=++cnt,ll,mid) , build(rson[pos]=++cnt,mid+1,rr);
    21     }
    22     inline void apply(int pos,lli x) {
    23         dat[pos] += ( r[pos] - l[pos] + 1 ) * x , lazy[pos] += x;
    24     }
    25     inline void push(int pos) {
    26         apply(lson[pos],lazy[pos]) , apply(rson[pos],lazy[pos]) , lazy[pos] = 0;
    27     }
    28     inline void update(int pos,const int &ll,const int &rr,const lli &x) {
    29         if( rr < l[pos] || r[pos] < ll ) return;
    30         if( ll <= l[pos] && r[pos] <= rr ) return apply(pos,x);
    31         push(pos) , update(lson[pos],ll,rr,x) , update(rson[pos],ll,rr,x) , dat[pos] = dat[lson[pos]] + dat[rson[pos]];
    32     }
    33     inline lli query(int pos,const int &ll,const int &rr) {
    34         if( rr < l[pos] || r[pos] < ll ) return 0;
    35         if( ll <= l[pos] && r[pos] <= rr ) return dat[pos];
    36         return push(pos) , query(lson[pos],ll,rr) + query(rson[pos],ll,rr);
    37     }
    38 }pre,sgt;
    39 
    40 int in[maxn<<1],n;
    41 lli ans;
    42 
    43 int main() {
    44     scanf("%d",&n) , pre.build(1,1,n) , sgt.build(1,1,n);
    45     for(int i=1;i<=n;i++) scanf("%d",in+i) , in[i+n] = in[i] , pre.update(1,in[i]+1,n,1) , sgt.update(1,in[i],in[i],pre.query(1,in[i],in[i]));
    46     for(int i=n,lst=1;i<n<<1;i++,lst++) ans += sgt.query(1,1,in[i]-1) , sgt.update(1,in[lst]+1,n,-1) , sgt.update(1,in[lst],in[lst],in[lst]-1);
    47     printf("%lld
    ",ans);
    48     return 0;
    49 }
    View Code


    T3:


    这不是BZOJ4774吗?斯坦纳树板子题。
    写写写,和原来的代码对拍,发现要跑5s?
    赶紧大力卡常,卡到3s,没办法了不管了(不知道评测机具体体位架构所以不敢target("avx"))。
    然后发现这题竟然A了(震惊!1.5s竟然能让斯坦纳树AC)
    然后又发现zhy的乱搞算法也A了(他枚举点对顺序然后贪心最短路,显然不对),这数据是有多水?
    辣鸡出题人不会造数据费我时间掉我排名!
    代码:

     1 #pragma GCC optimize("Ofast,no-stack-protector")
     2 //#pragma GCC target("avx")
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<queue>
     7 #include<cctype>
     8 #define bool unsigned char
     9 const unsigned maxn=1e4+1e2+3,maxs=(1<<9)+5,maxq=11;
    10 const unsigned inf=0x3f3f3f3f;
    11 // I know it's impossible for me to AC this problem in 1.5s, but I have to try.
    12 
    13 unsigned s[maxn],t[maxn<<1],nxt[maxn<<1],l[maxn<<1];
    14 unsigned f[maxs][maxn],g[maxs],pts[maxq];
    15 unsigned n,m,d,full;
    16 
    17 __inline void addedge(unsigned from,unsigned to,unsigned len) {
    18     static unsigned cnt = 0;
    19     t[++cnt] = to , l[cnt] = len ,
    20     nxt[cnt] = s[from] , s[from] = cnt;
    21 }
    22 __inline void spfa(unsigned* dis) {
    23     static bool inq[maxn];
    24     static std::queue<unsigned> q;
    25     for(unsigned i=1;i<=n;i++) if( dis[i] != inf ) q.push(i) , inq[i] = 1;
    26     while( q.size() ) {
    27         const unsigned pos = q.front(); q.pop() , inq[pos] = 0;
    28         for(register unsigned at=s[pos];at;at=nxt[at])
    29             if( dis[t[at]] > dis[pos] + l[at] ) {
    30                 dis[t[at]] = dis[pos] + l[at];
    31                 if( !inq[t[at]] ) q.push(t[at]) , inq[t[at]] = 1;
    32             }
    33     }
    34 }
    35 __inline void getf() {
    36     memset(f,0x3f,sizeof(f));
    37     for(register unsigned i=0;i<(d<<1);i++) f[1<<i][pts[i]] = 0;
    38     for(register unsigned sta=0;sta<full;sta++) {
    39         for(register unsigned ss=sta;ss;ss=(ss-1)&sta)
    40             for(register unsigned i=1;i<=n;i++)
    41                 f[sta][i] = std::min( f[sta][i] , f[ss][i] + f[sta^ss][i] );
    42         spfa(f[sta]);
    43     }
    44 }
    45 __inline bool legal(unsigned sta) {
    46     for(register unsigned i=0;i<=(d<<1);i++)
    47         if( ( ( sta >> i ) & 1 ) != ( sta >> ( ( d << 1 ) - i - 1 ) & 1 ) ) return 0;
    48     return 1;
    49 }
    50 __inline void getg() {
    51     memset(g,0x3f,sizeof(g));
    52     for(register unsigned sta=0;sta<full;sta++) if( legal(sta) ) for(register unsigned i=1;i<=n;i++) g[sta] = std::min( g[sta] , f[sta][i] );
    53     for(register unsigned sta=0;sta<full;sta++) for(register unsigned ss=sta;ss;ss=(ss-1)&sta) g[sta] = std::min( g[sta] , g[ss] + g[sta^ss] );
    54 }
    55 
    56 __inline unsigned char nextchar() {
    57     static const unsigned BS = 1 << 22;
    58     static unsigned char buf[BS],*st=buf+BS,*ed=buf+BS;
    59     if( st == ed ) ed = buf + fread(st=buf,1,BS,stdin);
    60     return st == ed ? -1 : *st++;
    61 }
    62 __inline unsigned getint() {
    63     register unsigned ret = 0 , ch;
    64     while( !isdigit(ch=nextchar()) );
    65     do ret=ret*10+ch-'0'; while( isdigit(ch=nextchar()) );
    66     return ret;
    67 }
    68 
    69 int main() {
    70     n = getint() , m = getint() , full = 1 << ( ( d = getint() ) << 1 );
    71     for(register unsigned i=1,a,b,l;i<=m;i++) a = getint() , b = getint() , l = getint() , addedge(a,b,l) , addedge(b,a,l);
    72     for(register unsigned i=0;i<d;i++) pts[i] = i + 1 , pts[(d<<1)-i-1] = n - i;
    73     getf() , getg();
    74     if( g[full-1] == inf ) puts("-1");
    75     else printf("%u
    ",g[full-1]);
    76     return 0;
    77 }
    View Code

     
    话说我似乎是这个机房中历届存在过的常数最大的人了。
    虽然我知道怎么优化,然而我懒......
    于是就有了自带大常数的属性。
    话说这不是萌点吗,怎么就变成槽点了(雾)。
    我怎么知道......

  • 相关阅读:
    Linux之Shell编程read读取控制台输入
    Linux之Shell编程while循环基本使用
    Linux之Shell编程for循环基本使用
    Linux之Shell编程case语句
    C语言 ##__VA_ARGS__
    C语言 __VA_ARGS__
    C语言 ##运算符
    C语言 __cplusplus
    C语言 #运算符
    C语言 extern “C”
  • 原文地址:https://www.cnblogs.com/Cmd2001/p/8875984.html
Copyright © 2011-2022 走看看