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\n",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\n",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\n",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\n",g[full-1]);
76     return 0;
77 }
View Code

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

posted @ 2018-04-18 16:52  Cmd2001  阅读(204)  评论(0编辑  收藏  举报