20180330小测

你说我怎么这么菜呢?
请看我直播把260分扔成120分......

T1:


题目就是给你个trie,在trie的每个节点上存在一些点,我们要询问这些点中权值最大的一些。
炸胡题,我们直接在节点上开vector把那些点都push进去就好了......
这不像后缀自动机会卡n^2,这个东西由于有输入数据长度限制所以不会。
于是我写了线段树。虽然不好写吧,但是也不应该爆零啊。
注意输出描述的最后一句,行末不应有空格。也就是说,这题卡行末空格!于是我就华丽爆零了。
(自己不看题还能怪谁?)
考场爆零代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<vector>
  6 #define debug cout
  7 using namespace std;
  8 const int maxn=1e5+1e2,maxe=1e7+1e2;
  9 
 10 int n;
 11 struct Node {
 12     int val,id;
 13     vector<char*> ss;
 14     friend bool operator < (const Node &a,const Node &b) {
 15         return a.val > b.val;
 16     }
 17 }ns[maxn];
 18 
 19 struct SegmentTree {
 20     int lson[maxe],rson[maxe],siz[maxe],cnt;
 21     inline void insert(int &pos,int l,int r,int tar) {
 22         if( !pos ) pos = ++cnt; ++siz[pos];
 23         if( l == r ) return;
 24         const int mid = ( l + r ) >> 1;
 25         if( tar <= mid ) insert(lson[pos],l,mid,tar);
 26         else insert(rson[pos],mid+1,r,tar);
 27     }
 28     inline int find(int pos,int l,int r,int tar) {
 29         if( !pos ) return 0;
 30         if( l == r)  return 1;
 31         const int mid = ( l + r ) >> 1;
 32         if( tar <= mid ) return find(lson[pos],l,mid,tar);
 33         return find(rson[pos],mid+1,r,tar);
 34     }
 35     inline int query(int pos,int l,int r,const int &ll,const int &rr) {
 36         if( !pos ) return 0;
 37         if( ll <= l && r <= rr ) return siz[pos];
 38         const int mid = ( l + r ) >> 1;
 39         if( rr <= mid ) return query(lson[pos],l,mid,ll,rr);
 40         else if( ll > mid ) return query(rson[pos],mid+1,r,ll,rr);
 41         return query(lson[pos],l,mid,ll,rr) + query(rson[pos],mid+1,r,ll,rr);
 42     }
 43     inline int kth(int pos,int l,int r,int k) { // assert it have kth .
 44         if( l == r ) return l;
 45         const int mid = ( l + r ) >> 1;
 46         if( k <= siz[lson[pos]] ) return kth(lson[pos],l,mid,k);
 47         else return kth(rson[pos],mid+1,r,k-siz[lson[pos]]);
 48     }
 49     inline void dfs(int pos,int l,int r,const int &ll,const int &rr) {
 50         if( !pos ) return;
 51         if( l == r ) return void(printf("%d ",ns[l].id));
 52         const int mid = ( l + r ) >> 1;
 53         if( rr <= mid ) dfs(lson[pos],l,mid,ll,rr);
 54         else if( ll > mid ) dfs(rson[pos],mid+1,r,ll,rr);
 55         else dfs(lson[pos],l,mid,ll,rr) , dfs(rson[pos],mid+1,r,ll,rr);
 56     }
 57 }cmt;
 58 
 59 struct Trie {
 60     int ch[maxn][26],roots[maxn],fa[maxn],root,cnt;
 61     Trie() { root = cnt = 1; }
 62     inline void insert(char* s,int li,int id) {
 63         int now = root;
 64         //cerr<<"s = "<<s<<endl;
 65         for(int i=0;i<li;i++) { // starts from 0 !
 66             const int t = s[i] - 'a';
 67             if( !ch[now][t] ) ch[now][t] = ++cnt;
 68             now = ch[now][t];
 69             if( !cmt.find(roots[now],1,n,id) )
 70                 cmt.insert(roots[now],1,n,id);
 71         }
 72     }
 73     inline void query(char* s,int li,int t) {
 74         int now = root;
 75         for(int i=1;i<=li;i++) { // starts from 1 !
 76             const int t = s[i] - 'a';
 77             now = ch[now][t];
 78         }
 79         if( !now ) return void(puts("0"));
 80         int tot = cmt.query(roots[now],1,n,1,n);
 81         printf("%d ",tot);
 82         if( tot <= t ) cmt.dfs(roots[now],1,n,1,n);
 83         else {
 84             int kth = cmt.kth(roots[now],1,n,t);
 85             cmt.dfs(roots[now],1,n,1,kth);
 86         }
 87         putchar('\n');
 88     }
 89 }trie;
 90 
 91 inline void pushstr(int id) {
 92     static char s[maxn];
 93     scanf("%s",s);
 94     int len = strlen(s);
 95     char* t = new char[len+1];
 96     memcpy(t,s,sizeof(char)*(len+1));
 97     ns[id].ss.push_back(t);
 98 }
 99 
100 int main() {
101     static int m;
102     static char in[maxn];
103     scanf("%d%d",&n,&m);
104     for(int i=1,t;i<=n;i++) {
105         scanf("%d%d",&ns[i].val,&t) , ns[i].id = i - 1;
106         while(t--) pushstr(i);
107     }
108     sort(ns+1,ns+1+n);
109     for(int i=1;i<=n;i++)
110         for(unsigned j=0;j<ns[i].ss.size();j++) {
111             trie.insert(ns[i].ss[j],strlen(ns[i].ss[j]),i);
112         }
113     for(int i=1,t,li;i<=m;i++) {
114         scanf("%d%s",&t,in+1) , li = strlen(in+1);
115         trie.query(in,li,t);
116     }
117     return 0;
118 }
View Code

考后AC代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<vector>
  6 #define debug cout
  7 using namespace std;
  8 const int maxn=1e5+1e2,maxe=1e7+1e2;
  9 
 10 int n,sizt;
 11 struct Node {
 12     int val,id;
 13     vector<char*> ss;
 14     friend bool operator < (const Node &a,const Node &b) {
 15         return a.val > b.val;
 16     }
 17 }ns[maxn];
 18 
 19 struct SegmentTree {
 20     int lson[maxe],rson[maxe],siz[maxe],cnt;
 21     inline void insert(int &pos,int l,int r,int tar) {
 22         if( !pos ) pos = ++cnt; ++siz[pos];
 23         if( l == r ) return;
 24         const int mid = ( l + r ) >> 1;
 25         if( tar <= mid ) insert(lson[pos],l,mid,tar);
 26         else insert(rson[pos],mid+1,r,tar);
 27     }
 28     inline int find(int pos,int l,int r,int tar) {
 29         if( !pos ) return 0;
 30         if( l == r)  return 1;
 31         const int mid = ( l + r ) >> 1;
 32         if( tar <= mid ) return find(lson[pos],l,mid,tar);
 33         return find(rson[pos],mid+1,r,tar);
 34     }
 35     inline int query(int pos,int l,int r,const int &ll,const int &rr) {
 36         if( !pos ) return 0;
 37         if( ll <= l && r <= rr ) return siz[pos];
 38         const int mid = ( l + r ) >> 1;
 39         if( rr <= mid ) return query(lson[pos],l,mid,ll,rr);
 40         else if( ll > mid ) return query(rson[pos],mid+1,r,ll,rr);
 41         return query(lson[pos],l,mid,ll,rr) + query(rson[pos],mid+1,r,ll,rr);
 42     }
 43     inline int kth(int pos,int l,int r,int k) { // assert it have kth .
 44         if( l == r ) return l;
 45         const int mid = ( l + r ) >> 1;
 46         if( k <= siz[lson[pos]] ) return kth(lson[pos],l,mid,k);
 47         else return kth(rson[pos],mid+1,r,k-siz[lson[pos]]);
 48     }
 49     inline void dfs(int pos,int l,int r,const int &ll,const int &rr) {
 50         if( !pos ) return;
 51         if( l == r ) return void(printf("%d%c",ns[l].id,--sizt?' ':'\n'));
 52         const int mid = ( l + r ) >> 1;
 53         if( rr <= mid ) dfs(lson[pos],l,mid,ll,rr);
 54         else if( ll > mid ) dfs(rson[pos],mid+1,r,ll,rr);
 55         else dfs(lson[pos],l,mid,ll,rr) , dfs(rson[pos],mid+1,r,ll,rr);
 56     }
 57 }cmt;
 58 
 59 struct Trie {
 60     int ch[maxn][26],roots[maxn],fa[maxn],root,cnt;
 61     Trie() { root = cnt = 1; }
 62     inline void insert(char* s,int li,int id) {
 63         int now = root;
 64         //cerr<<"s = "<<s<<endl;
 65         for(int i=0;i<li;i++) { // starts from 0 !
 66             const int t = s[i] - 'a';
 67             if( !ch[now][t] ) ch[now][t] = ++cnt;
 68             now = ch[now][t];
 69             if( !cmt.find(roots[now],1,n,id) )
 70                 cmt.insert(roots[now],1,n,id);
 71         }
 72     }
 73     inline void query(char* s,int li,int t) {
 74         int now = root;
 75         for(int i=1;i<=li;i++) { // starts from 1 !
 76             const int t = s[i] - 'a';
 77             now = ch[now][t];
 78         }
 79         if( !now ) return void(puts("0"));
 80         int tot = cmt.query(roots[now],1,n,1,n);
 81         printf("%d ",tot);
 82         if( tot <= t ) sizt = tot , cmt.dfs(roots[now],1,n,1,n);
 83         else {
 84             int kth = cmt.kth(roots[now],1,n,t);
 85             sizt = t , cmt.dfs(roots[now],1,n,1,kth);
 86         }
 87     }
 88 }trie;
 89 
 90 inline void pushstr(int id) {
 91     static char s[maxn];
 92     scanf("%s",s);
 93     int len = strlen(s);
 94     char* t = new char[len+1];
 95     memcpy(t,s,sizeof(char)*(len+1));
 96     ns[id].ss.push_back(t);
 97 }
 98 
 99 int main() {
100     static int m;
101     static char in[maxn];
102     scanf("%d%d",&n,&m);
103     for(int i=1,t;i<=n;i++) {
104         scanf("%d%d",&ns[i].val,&t) , ns[i].id = i - 1;
105         while(t--) pushstr(i);
106     }
107     sort(ns+1,ns+1+n);
108     for(int i=1;i<=n;i++)
109         for(unsigned j=0;j<ns[i].ss.size();j++) {
110             trie.insert(ns[i].ss[j],strlen(ns[i].ss[j]),i);
111         }
112     for(int i=1,t,li;i<=m;i++) {
113         scanf("%d%s",&t,in+1) , li = strlen(in+1);
114         trie.query(in,li,t);
115     }
116     return 0;
117 }
View Code



T2:


我们可以f[i][0/1]点i及以后是否去掉边,然后枚举是在下一层及以后去还是现在这层去,胡乱转移就好。
恭喜你,这样是不对的。
详见下面的图:

于是你就被愉悦地WA掉了......
然后我就赶紧交了暴力......
事实证明这么写有60分,而暴力只有20分......
正解是:f[i]表示i之后期望步数,p[i]表示从0能到i的期望,g[i]表示扔掉一条i的出边,能获得的最大期望步数。
答案就是f[1]+max{0,(g[i]-f[i])*p[i]}。看起来很有道理的样子。
注意这题写正解的时候不要写记忆化搜索,否则有些点无法从0到达,他们的出边却计算了度数,这样会导致有些点永远无法被访问到。
所以我们需要从所有没有入度的点开始拓扑排序转移。
60分胡乱DP代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define bool unsigned char
 6 #define debug cout
 7 typedef long double ldb;
 8 using namespace std;
 9 const int maxn=1e4+1e2,maxe=1e5+1e2;
10 
11 int s[maxn],t[maxe],nxt[maxe],l[maxe];
12 ldb f[maxn][2],ans;
13 bool vis[maxn];
14 
15 inline void addedge(int from,int to,int len) {
16     static int cnt = 0;
17     t[++cnt] = to , l[cnt] = len ,
18     nxt[cnt] = s[from] , s[from] = cnt;
19 }
20 
21 inline void dfs(int pos) {
22     if( vis[pos] ) return;
23     vis[pos] = 1;
24     ldb sf,sw,wn,wt;
25     int se = 0;
26     sf = sw = wn = wt = 0;
27     for(int at=s[pos];at;at=nxt[at]) {
28         dfs(t[at]) , sw += l[at] , ++se;
29         sf += l[at] * ( f[t[at]][0] + 1 );
30     }
31     if( !se ) return; // Or you will get "nan" .
32     f[pos][0] = sf / sw;
33     for(int at=s[pos];at;at=nxt[at]) {
34         wn = max( wn , ( sf - ( f[t[at]][0] + 1 ) * l[at] + ( f[t[at]][1] + 1 ) * l[at] ) / sw );
35         if( se != 1 ) wt = max( wt , ( sf - ( f[t[at]][0] + 1 ) * l[at] ) / ( sw - l[at] ) );
36     }
37     f[pos][1] = max( wn , wt );
38 }
39 
40 int main() {
41     static int n,m;
42     scanf("%d%d",&n,&m);
43     for(int i=1,a,b,l;i<=m;i++) {
44         scanf("%d%d%d",&a,&b,&l) , ++a , ++b;
45         addedge(a,b,l);
46     }
47     dfs(1) , ans = max( f[1][0] , f[1][1] );
48     printf("%0.6Lf\n",ans);
49     return 0;
50 }
View Code

正解代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 #define debug cout
 7 using namespace std;
 8 const int maxn=1e4+1e2,maxe=1e5+1e2;
 9 
10 int ina[maxe],inb[maxe],inc[maxe],n,m;
11 int s[maxn],t[maxe],nxt[maxe],l[maxe],deg[maxn],d[maxn],cnt;
12 long double f[maxn],p[maxn],ans;
13 
14 inline void addedge(int from,int to,int len) {
15     t[++cnt] = to , l[cnt] = len , nxt[cnt] = s[from] , s[from] = cnt , ++deg[to];
16 }
17 inline void bfs1() {
18     queue<int> q;
19     for(int i=1;i<=n;i++) if( !deg[i] ) q.push(i);
20     while( q.size() ) {
21         const int pos = q.front(); q.pop();
22         for(int at=s[pos];at;at=nxt[at]) {
23             f[t[at]] += ( f[pos] + 1 ) * l[at] / d[t[at]];
24             if( !--deg[t[at]] ) q.push(t[at]);
25         }
26     }
27 }
28 inline void bfs2(int st) {
29     queue<int> q; p[st] = 1;
30     for(int i=1;i<=n;i++) if( !deg[i] ) q.push(i);
31     while( q.size() ) {
32         const int pos = q.front(); q.pop();
33         for(int at=s[pos];at;at=nxt[at]) {
34             p[t[at]] += p[pos] * l[at] / d[pos];
35             if( !--deg[t[at]] ) q.push(t[at]);
36         }
37     }
38 }
39 inline void getans() {
40     ans = f[1];
41     for(int i=1;i<=m;i++) {
42         const int &a = ina[i] , &b= inb[i] , &c = inc[i];
43         ans = max( ans , ( (  f[a] - ( f[b] + 1 ) * c / d[a] ) * d[a] / ( d[a] - c ) - f[a] )* p[a] + f[1] );
44     }
45 }
46 
47 int main() {
48     scanf("%d%d",&n,&m);
49     for(int i=1;i<=m;i++) {
50         scanf("%d%d%d",ina+i,inb+i,inc+i) , 
51         ++ina[i] , ++inb[i] , d[ina[i]] += inc[i] , 
52         addedge(inb[i],ina[i],inc[i]);
53     }
54     bfs1() , memset(s,0,sizeof(s)) , cnt = 0;
55     for(int i=1;i<=m;i++) addedge(ina[i],inb[i],inc[i]);
56     bfs2(1);
57     getans();
58     printf("%0.6Lf\n",ans);
59     return 0;
60 }
View Code



T3:


我告诉你我考场上唯一AC的题是这题你敢信?
我们考虑大力DP。
首先重新定义代价为:1e13*选择数量-(总高度+总补偿)。这样我们只需要一个long long就能维护。
然后重新定义高度为heighti - i,这样我们能选择高度相同的点,同时可以把无论如何也不会被选择的点扔掉(这样他们的高度<0)。
之后就是转移,我们枚举i前面的被选择的点j,我们要满足的东西有:hj<=hi。
考虑我们再次选择一个点会产生怎样的代价,显然最终的答案一定是一个阶梯状的东西,所以我们选择了i之后之后所有点的高度相对于仅选择j都会上升(hi-hj)。
于是我们就可以转移了,fi=max{fj+(hi-hj)*(n-i+1)}(hj<=hi)+cost[i],cost[i]为单点价值减去选i的补偿代价。于是你可以写对拍用的n^2暴力了。
仔细观察这个转移方程,显然是一个可斜率优化的方程,我们可以把hi当成x,把fi当成j,把(n-i+1)当成a,把1当成b,这样最优答案就是ax+by的形式了。
因为hi不满足单调性,所以我们需要set维护凸包
考虑到我们还有hj<=hi的限制,所以需要再套一层cdq分治......
(您可写着去.jpg)
于是我花了接进1h写完代码后开始对拍,一开始出了一个很愚蠢的错误改了没事了,小数据瞬间安静,几万组都没事。
然后开始对拍5000的大数据,拍了200+组,WA了。
woc这可怎么调啊.....
又回去拍小数据,没错......
接着拍大数据,还是WA......
然后花了2个小时死活调不出来,硬着头皮交了,竟然A了......
这个故事启示我们只要小数据稳定,大数据能过几百组就别管了QAQ。
代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<set>
  6 #include<cmath>
  7 #include<vector>
  8 #define debug cout
  9 typedef long long int lli;
 10 using namespace std;
 11 const int maxn=1e5+1e2;
 12 const lli mul = 1e13+1e10;
 13 
 14 namespace Convex {
 15     int cmp; // 0 compare x , 1 compare slope .
 16     struct Point {
 17         lli x,y;
 18         long double slop;
 19         friend bool operator < (const Point &a,const Point &b) {
 20             if( !cmp ) return a.x != b.x ? a.x < b.x : a.y < b.y;
 21             return a.slop > b.slop;
 22         }
 23         friend Point operator - (const Point &a,const Point &b) {
 24             return (Point){a.x-b.x,a.y-b.y};
 25         }
 26         friend long double operator * (const Point &a,const Point &b) {
 27             return (long double)a.x * b.y - (long double)b.x * a.y;
 28         }
 29         inline lli calc(lli a,lli b) const {
 30             return a * x + b * y;
 31         }
 32     };
 33     set<Point> st;
 34     
 35     inline void Pop_right(set<Point>::iterator nxt,const Point &p) {
 36         set<Point>::iterator lst;
 37         while(1) {
 38             lst = nxt , ++nxt;
 39             if( nxt == st.end() ) return;
 40             if( lst->x == p.x ) {
 41                 if( p.y > lst->y ) st.erase(lst);
 42                 else break;
 43             }
 44             else {
 45                 if( (*lst-p) * (*nxt-*lst) < 0 ) return;
 46                 st.erase(lst);
 47             }
 48         }
 49     }
 50     inline void Pop_left(set<Point>::iterator prv,const Point &p) {
 51         set<Point>::iterator lst;
 52         while(prv!=st.begin()) {
 53             lst = prv , --prv;
 54             if( p.x == lst->x ) {
 55                 if( p.y > lst->y ) st.erase(lst);
 56                 else break;
 57                 continue;
 58             }
 59             else {
 60                 if( (*lst-*prv) * (p-*lst) < 0 ) break;
 61                 st.erase(lst);
 62             }
 63         }
 64     }
 65     inline bool fail(const Point &p) {
 66         set<Point>::iterator it = st.lower_bound((Point){p.x,0,0});
 67         if( it != st.end() && it->x == p.x ) {
 68             if( it->y >= p.y ) return 1; // p is useless at all .
 69             else return 0; // p must be on convex .
 70         }
 71         if( it != st.end() && it != st.begin() ) {
 72             set<Point>::iterator prv = it; --prv;
 73             if( ( p - *prv ) * (*it - p ) > 0  ) return 1;
 74         }
 75         return 0;
 76     }
 77     inline void insert(const Point &p) {
 78         cmp = 0;
 79         if( fail(p) ) return;
 80         set<Point>::iterator prv,nxt,lst=st.lower_bound(p);
 81         if(lst!=st.begin()) Pop_left(--lst,p);
 82         lst=st.lower_bound(p);
 83         if(lst!=st.end()) Pop_right(lst,p);
 84         st.insert(p) , lst = st.find(p);
 85         if(lst!=st.begin()) {
 86             prv = lst , --prv;
 87             Point x = *prv;
 88             x.slop = (long double)( p.y - x.y ) / ( p.x - x.x );
 89             st.erase(prv) , st.insert(x);
 90         }
 91         nxt = lst , ++nxt;
 92         if(nxt!=st.end()) {
 93             Point x = p , n = *nxt;
 94             x.slop = (long double)( n.y - x.y ) / ( n.x - x.x );
 95             st.erase(lst) , st.insert(x);
 96         } else {
 97             Point x = p;
 98             x.slop = -1e18;
 99             st.erase(lst) , st.insert(x);
100         }
101     }
102     inline lli query(const lli &k) {
103         cmp = 1;
104         set<Point>::iterator it = st.lower_bound((Point){0,0,(long double)-k}); // it can't be st.end() if st isn't empty .
105         if( it==st.end() ) return 0;
106         lli ret = it->calc(k,1);
107         if( it != st.begin() ) {
108             --it;
109             ret = max( ret , it->calc(k,1) );
110         }
111         return ret;
112     }
113     inline void clear() {
114         st.clear() , cmp = 0;
115     }
116 }
117 
118 lli ina[maxn],inb[maxn],f[maxn],cst[maxn],ans,add; // f[id] .
119 bool isl[maxn];
120 int n;
121 
122 int cmp; // 0 compare height , 1 compare id .
123 struct Node {
124     lli hei,id;
125     friend bool operator < (const Node &a,const Node &b) {
126         return cmp ? a.id < b.id : a.hei < b.hei;
127     }
128 }ns[maxn];
129 
130 vector<Node> vec;
131 
132 inline void solve(vector<Node> &vec) {
133     if( vec.size() <= 1 ) {
134         if( vec.size() ) f[vec[0].id] = max( f[vec[0].id] , cst[vec[0].id] );
135         return;
136     }
137     vector<Node> vl,vr;
138     const unsigned mid = vec.size() >> 1;
139     for(unsigned i=0;i<mid;i++) vl.push_back(vec[i]);
140     for(unsigned i=mid;i<vec.size();i++) vr.push_back(vec[i]);
141     solve(vl);
142     for(unsigned i=0;i<vl.size();i++) isl[vl[i].id] = 1;
143     for(unsigned i=0;i<vr.size();i++) isl[vr[i].id] = 0;
144     cmp = 1 , sort(vec.begin(),vec.end()) , Convex::clear();
145     for(unsigned i=0;i<vec.size();i++) {
146         if( isl[vec[i].id] ) {
147             Convex::insert((Convex::Point){vec[i].hei,f[vec[i].id],0.0});
148         } else {
149             f[vec[i].id] = max( f[vec[i].id] , cst[vec[i].id] + Convex::query(n-vec[i].id+1));
150         }
151     }
152     solve(vr);
153 }
154 
155 int main() {
156     //freopen("dat.wa3.txt","r",stdin);
157     static lli sel,lst;
158     scanf("%d",&n) , add = (lli) n * ( n + 1 ) >> 1;
159     for(int i=1;i<=n;i++) scanf("%lld",ina+i) , ina[i] -= i;
160     for(int i=1;i<=n;i++) {
161         scanf("%lld",inb+i);
162         if( ina[i] >= 0 ) {
163             cst[i] = mul - inb[i] - ina[i] * ( n - i + 1 ) ,
164             vec.push_back((Node){ina[i],i});
165         }
166     }
167     cmp = 0 , sort(vec.begin(),vec.end());
168     solve(vec);
169     for(int i=1;i<=n;i++) ans = max( ans , f[i] );
170     ans -= add;
171     sel = ( ans + mul ) / mul;
172     lst = mul * sel - ans;
173     printf("%lld %lld\n",sel,lst);
174     return 0;
175 }
View Code

Commit@2018.03.31:
今天终于找到是哪里错了......
cdq分治在排序的时候不能只排单一关键字,需要做双关键字排序,否则会导致一些能更新的东西无法更新。
另外我写的这个维护凸包好像在横坐标相等且上一个点为set的begin的时候有问题......
以下为修正后的代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<set>
  6 #include<cmath>
  7 #include<vector>
  8 #define debug cout
  9 typedef long long int lli;
 10 using namespace std;
 11 const int maxn=1e5+1e2;
 12 const lli mul = 1e13+1e10;
 13 
 14 namespace Convex {
 15     int cmp; // 0 compare x , 1 compare slope .
 16     struct Point {
 17         lli x,y;
 18         long double slop;
 19         friend bool operator < (const Point &a,const Point &b) {
 20             if( !cmp ) return a.x != b.x ? a.x < b.x : a.y < b.y;
 21             return a.slop > b.slop;
 22         }
 23         friend Point operator - (const Point &a,const Point &b) {
 24             return (Point){a.x-b.x,a.y-b.y};
 25         }
 26         friend long double operator * (const Point &a,const Point &b) {
 27             return (long double)a.x * b.y - (long double)b.x * a.y;
 28         }
 29         inline lli calc(lli a,lli b) const {
 30             return a * x + b * y;
 31         }
 32     };
 33     set<Point> st;
 34     
 35     inline void Pop_right(set<Point>::iterator nxt,const Point &p) {
 36         set<Point>::iterator lst;
 37         while(1) {
 38             nxt = st.lower_bound(p);
 39             lst = nxt , ++nxt;
 40             if( nxt == st.end() ) return;
 41             if( lst->x == p.x ) {
 42                 if( p.y > lst->y ) st.erase(lst);
 43                 else break;
 44             }
 45             else {
 46                 if( (*lst-p) * (*nxt-*lst) < 0 ) return;
 47                 st.erase(lst);
 48             }
 49         }
 50     }
 51     inline void Pop_left(set<Point>::iterator prv,const Point &p) {
 52         set<Point>::iterator lst;
 53         prv = st.lower_bound(p) , --prv;
 54         if( prv == st.begin() && prv->x == p.x ) return void(st.erase(prv));
 55         while(prv!=st.begin()) {
 56             prv = st.lower_bound(p) , --prv;
 57             lst = prv , --prv;
 58             if( p.x == lst->x ) {
 59                 if( p.y > lst->y ) st.erase(lst);
 60                 else break;
 61                 continue;
 62             }
 63             else {
 64                 if( (*lst-*prv) * (p-*lst) < 0 ) break;
 65                 st.erase(lst);
 66             }
 67         }
 68     }
 69     inline bool fail(const Point &p) {
 70         set<Point>::iterator it = st.lower_bound((Point){p.x,0,0});
 71         if( it != st.end() && it->x == p.x ) {
 72             if( it->y >= p.y ) return 1; // p is useless at all .
 73             else return 0; // p must be on convex .
 74         }
 75         if( it != st.end() && it != st.begin() ) {
 76             set<Point>::iterator prv = it; --prv;
 77             if( ( p - *prv ) * (*it - p ) > 0  ) return 1;
 78         }
 79         return 0;
 80     }
 81     inline void insert(const Point &p) {
 82         cmp = 0;
 83         if( fail(p) ) return;
 84         set<Point>::iterator prv,nxt,lst=st.lower_bound(p);
 85         if(lst!=st.begin()) Pop_left(--lst,p);
 86         lst=st.lower_bound(p);
 87         if(lst!=st.end()) Pop_right(lst,p);
 88         st.insert(p) , lst = st.find(p);
 89         if(lst!=st.begin()) {
 90             prv = lst , --prv;
 91             Point x = *prv;
 92             x.slop = (long double)( p.y - x.y ) / ( p.x - x.x );
 93             st.erase(prv) , st.insert(x);
 94         }
 95         nxt = lst = st.find(p) , ++nxt;
 96         if(nxt!=st.end()) {
 97             Point x = p , n = *nxt;
 98             x.slop = (long double)( n.y - x.y ) / ( n.x - x.x );
 99             st.erase(lst) , st.insert(x);
100         } else {
101             Point x = p;
102             x.slop = -1e18;
103             st.erase(lst) , st.insert(x);
104         }
105     }
106     inline lli query(const lli &k) {
107         cmp = 1;
108         set<Point>::iterator it = st.lower_bound((Point){0,0,(long double)-k}); // it can't be st.end() if st isn't empty .
109         if( it==st.end() ) return 0;
110         lli ret = it->calc(k,1);
111         if( it != st.begin() ) {
112             --it;
113             ret = max( ret , it->calc(k,1) );
114         }
115         ++it; if( ++it!=st.end() ) ret = max( ret , it->calc(k,1) );
116         return ret;
117     }
118     inline void clear() {
119         st.clear() , cmp = 0;
120     }
121 }
122 
123 lli ina[maxn],inb[maxn],f[maxn],cst[maxn],ans,add; // f[id] .
124 bool isl[maxn];
125 int n;
126 
127 int cmp; // 0 compare height , 1 compare id .
128 struct Node {
129     lli hei,id;
130     friend bool operator < (const Node &a,const Node &b) {
131         if( cmp ) return a.id != b.id ? a.id < b.id : a.hei < b.hei;
132         else return a.hei != b.hei ? a.hei < b.hei : a.id < b.id;
133     }
134 }ns[maxn];
135 
136 vector<Node> vec;
137 
138 inline void solve(vector<Node> &vec) {
139     if( vec.size() <= 1 ) {
140         if( vec.size() ) f[vec[0].id] = max( f[vec[0].id] , cst[vec[0].id] );
141         return;
142     }
143     vector<Node> vl,vr;
144     const unsigned mid = vec.size() >> 1;
145     for(unsigned i=0;i<mid;i++) vl.push_back(vec[i]);
146     for(unsigned i=mid;i<vec.size();i++) vr.push_back(vec[i]);
147     solve(vl);
148     for(unsigned i=0;i<vl.size();i++) isl[vl[i].id] = 1;
149     for(unsigned i=0;i<vr.size();i++) isl[vr[i].id] = 0;
150     cmp = 1 , sort(vec.begin(),vec.end()) , Convex::clear();
151     for(unsigned i=0;i<vec.size();i++) {
152         if( isl[vec[i].id] ) {
153             Convex::insert((Convex::Point){vec[i].hei,f[vec[i].id],0});
154         } else {
155             f[vec[i].id] = max( f[vec[i].id] , cst[vec[i].id] + Convex::query(n-vec[i].id+1));
156         }
157     }
158     solve(vr);
159 }
160 
161 int main() {
162     static lli sel,lst;
163     scanf("%d",&n) , add = (lli) n * ( n + 1 ) >> 1;
164     for(int i=1;i<=n;i++) scanf("%lld",ina+i) , ina[i] -= i;
165     for(int i=1;i<=n;i++) {
166         scanf("%lld",inb+i);
167         if( ina[i] >= 0 ) {
168             cst[i] = mul - inb[i] - ina[i] * ( n - i + 1 ) ,
169             vec.push_back((Node){ina[i],i});
170         }
171     }
172     cmp = 0 , sort(vec.begin(),vec.end());
173     solve(vec);
174     for(int i=1;i<=n;i++) ans = max( ans , f[i] );
175     ans -= add;
176     sel = ( ans + mul ) / mul;
177     lst = mul * sel - ans;
178     printf("%lld %lld\n",sel,lst);
179     return 0;
180 }
View Code

另外这个东西其实不用平衡树维护凸包,如果你外层分治位置,内层分治height的话,height就会有序,这样只需要写一个普通凸包就好了......
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define debug cout
typedef long long int lli;
typedef long double ldb;
using namespace std;
const int maxn=1e5+1e2;
const lli mul = 1e13 + 1e10;


struct Convex {
    struct Point {
        lli x,y;
        friend Point operator - (const Point &a,const Point &b) {
            return (Point){a.x-b.x,a.y-b.y};
        }
        friend ldb operator * (const Point &a,const Point &b) {
            return (ldb)a.x*b.y - (ldb)a.y*b.x;
        }
        friend lli operator ^ (const Point &a,const Point &b) {
            return a.x * b.x + a.y * b.y;
        }
    }ps[maxn];
    int top;
    inline void push(const Point &p) {
        while( top > 1 ) {
            if( p.x == ps[top].x && p.y > ps[top].y ) --top;
            else if( ( ps[top] - ps[top-1] ) * ( p - ps[top] ) > 0 ) --top;
            else break;
        }
        if( top == 1 && p.x == ps[top].x && p.y > ps[top].y ) --top;
        if( !top || p.x != ps[top].x ) ps[++top] = p;
    }
    inline lli query(const Point &p) {
        int l = 1 , r = top , lmid , rmid;
        while( r > l + 2 ) {
            lmid = ( l + l + r ) / 3 , rmid = ( l + r + r ) / 3;
            if( ( p ^ ps[lmid] ) < ( p ^ ps[rmid] ) ) l = lmid;
            else r = rmid;
        }
        lli ret = 0;
        for(int i=l;i<=r;i++) ret = max( ret , p ^ ps[i] );
        return ret;
    }
    inline void clear() {
        top = 0;
    }
}con;

lli ina[maxn],inb[maxn],f[maxn],cst[maxn],ans,add; // f[id] .
bool isl[maxn];
int n;
 
int cmp; // 0 compare height , 1 compare id .
struct Node {
    lli hei,id;
    friend bool operator < (const Node &a,const Node &b) {
        if( cmp ) return a.id != b.id ? a.id < b.id : a.hei < b.hei;
        else return a.hei != b.hei ? a.hei < b.hei : a.id < b.id;
    }
}ns[maxn];
 
vector<Node> vec;
 
inline void solve(vector<Node> &vec) {
    if( vec.size() <= 1 ) {
        if( vec.size() ) f[vec[0].id] = max( f[vec[0].id] , cst[vec[0].id] );
        return;
    }
    vector<Node> vl,vr;
    const unsigned mid = vec.size() >> 1;
    for(unsigned i=0;i<mid;i++) vl.push_back(vec[i]);
    for(unsigned i=mid;i<vec.size();i++) vr.push_back(vec[i]);
    solve(vl);
    for(unsigned i=0;i<vl.size();i++) isl[vl[i].id] = 1;
    for(unsigned i=0;i<vr.size();i++) isl[vr[i].id] = 0;
    cmp = 0 , sort(vec.begin(),vec.end()) , con.clear();
    for(unsigned i=0;i<vec.size();i++) {
        if( isl[vec[i].id] ) {
            con.push((Convex::Point){vec[i].hei,f[vec[i].id]});
        } else {
            f[vec[i].id] = max( f[vec[i].id] , cst[vec[i].id] + con.query((Convex::Point){n-vec[i].id+1,1}));
        }
    }
    solve(vr);
}
 
int main() {
    static lli sel,lst;
    scanf("%d",&n) , add = (lli) n * ( n + 1 ) >> 1;
    for(int i=1;i<=n;i++) scanf("%lld",ina+i) , ina[i] -= i;
    for(int i=1;i<=n;i++) {
        scanf("%lld",inb+i);
        if( ina[i] >= 0 ) {
            cst[i] = mul - inb[i] - ina[i] * ( n - i + 1 ) ,
            vec.push_back((Node){ina[i],i});
        }
    }
    cmp = 1 , sort(vec.begin(),vec.end());
    solve(vec);
    for(int i=1;i<=n;i++) ans = max( ans , f[i] );
    ans -= add;
    sel = ( ans + mul ) / mul;
    lst = mul * sel - ans;
    printf("%lld %lld\n",sel,lst);
    return 0;
}
View Code



既然我这么菜还只会扔分,省选退役稳了......
不,不用等到省选,我大概已经可以滚粗学高考了吧......

posted @ 2018-03-30 16:44  Cmd2001  阅读(208)  评论(1编辑  收藏  举报