zoukankan      html  css  js  c++  java
  • 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('
    ');
     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?' ':'
    '));
     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
    ",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
    ",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
    ",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
    ",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
    ",sel,lst);
        return 0;
    }
    View Code



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

  • 相关阅读:
    [转]jQuery知识总结
    sqlserver2008 函数1
    使用触发器生成流水号
    日期格式
    数据库正在使用,删除不了的问题
    continue 语句
    逻辑语句和函数
    ASP.NET中的随机密码生成
    相对路径
    “基类包括字段,但其类型与控件的类型不兼容”的解决方法
  • 原文地址:https://www.cnblogs.com/Cmd2001/p/8677157.html
Copyright © 2011-2022 走看看