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 }
考后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 }
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 }
正解代码:
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 }
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 }
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 }
另外这个东西其实不用平衡树维护凸包,如果你外层分治位置,内层分治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; }
既然我这么菜还只会扔分,省选退役稳了......
不,不用等到省选,我大概已经可以滚粗学高考了吧......