[2016 Changzhou No. 1 summer camp Day7], 2016 Changzhou day7
Sequence)
[Description]
Bucket has a sequence, which is initially empty. It inserts 1-n into the sequence sequentially, where I is inserted to the right of the current ai number (ai = 0 indicates inserting to the leftmost part of the sequence ). It wants you to help
It finds the final sequence.
[Input Data]
The first line is an integer n. N positive integers a1 ~ In the second row ~ An.
[Output Data]
Output n integers in a row to indicate the final sequence. Separate the numbers with a space.
[Example input]
5
0 1 1 0 3
[Sample output]
4 1 3 5 2
[Data Scope]
For 30% of data, n <= 1000.
For 70% of data, n <= 100000
For 100% of data, n <= ai <I.
Question
Insert from the back to the front. For a number, insert it to the current space. Use the line segment tree to maintain the subscript of the current space position.
#include<iostream>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;int n;int a[1000005],ans[1000005];struct hh{ int l,r,val; bool flag;};hh lt[5000005];void build(int root,int l,int r){ int mid; lt[root].l=l; lt[root].r=r; if(l==r) { lt[root].val=1; return; } mid=(l+r)>>1; build(root<<1,l,mid); build(root<<1|1,mid+1,r); lt[root].val=lt[root<<1].val+lt[root<<1|1].val;}int query(int root,int now){ int mid; if(lt[root].l==lt[root].r) return lt[root].l; if(lt[root<<1].val>=now) return query(root<<1,now); else return query(root<<1|1,now-lt[root<<1].val);}void del(int root,int pre){ if(lt[root].l<=pre&<[root].r>=pre) lt[root].val--; if(lt[root].l==lt[root].r) { lt[root].flag=true; return; } if(lt[root<<1].l<=pre&<[root<<1].r>=pre) del(root<<1,pre); else if(lt[root<<1|1].l<=pre&<[root<<1|1].r>=pre) del(root<<1|1,pre);}int main(){ int i,j,pre; freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); for(i=n;i>=1;i--) { pre=query(1,a[i]+1); ans[pre]=i; del(1,pre); } for(i=1;i<=n;i++) printf("%d ",ans[i]); fclose(stdin); fclose(stdout); return 0;}
Backpack)
[Description]
He has n items and a m-sized backpack. Each item has a small value. He hopes that you can help him find the maximum number of valuable items in his backpack.
[Input Data]
The first line has two integers, n and m. The next n rows have two integers, xi and wi, indicating the size and value of the I-th item.
[Output Data]
One integer in a row indicates the maximum value.
[Example input]
5 100
95 80
4 18
3 11
99 100
2 10
[Sample output]
101
[Data Scope]
For 20% of data, xi <= 1500.
For 30% of the data, wi <= 1500.
For 100% of the data, n <= 40, 0 <= m <= 10 ^ 18, 0 <= xi, wi <= 10 ^ 15.
Question
Half-fold search + Binary Search
#include<iostream>#include<cstdlib>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>using namespace std;int n,tn,cnt,tot;long long m,ans=0;struct hh{ long long x,w;}a[45],q[2000005];void dfsa(int,long long,long long);void dfsb(int,long long,long long);long long search(long long);bool cmp(hh a,hh b){return a.x==b.x?a.w>b.w:a.x<b.x;}long long maxx(long long a,long long b){return a>b?a:b;}int main(){ int i,j; freopen("pack.in","r",stdin); freopen("pack.out","w",stdout); scanf("%d%lld",&n,&m); tn=n>>1; for(i=1;i<=n;i++) scanf("%lld%lld",&a[i].x,&a[i].w); dfsa(1,0,0);tot=1; sort(q+1,q+cnt+1,cmp); for(i=2;i<=cnt;i++) if(q[i].x!=q[i-1].x) q[++tot]=q[i]; for(i=1;i<=tot;i++) if(q[i].w<q[i-1].w) q[i].w=q[i-1].w; dfsb(tn+1,0,0); printf("%lld",ans); fclose(stdin); fclose(stdout); return 0;}void dfsa(int pre,long long xx,long long ww){ if(pre>tn) { q[++cnt]=(hh){xx,ww}; return; } dfsa(pre+1,xx,ww); if(xx+a[pre].x<=m) dfsa(pre+1,xx+a[pre].x,ww+a[pre].w);}void dfsb(int pre,long long xx,long long ww){ long long temp; if(pre>n) { temp=search(m-xx); ans=maxx(ans,ww+temp); return; } dfsb(pre+1,xx,ww); if(xx+a[pre].x<=m) dfsb(pre+1,xx+a[pre].x,ww+a[pre].w);}long long search(long long xx){ int l,r,mid; if(xx<q[1].x) return 0; l=1;r=tot; while(l<r) { mid=l+r+1>>1; if(q[mid].x<=xx) l=mid; else r=mid-1; } return q[l].w;}
Segment tree)
[Description]
To redefine a line segment tree, the root node still represents [1, n], but the left and right sons of [l, r] represent [l, k] and [k + 1, r]. k can be used in [l, r.
Each access starts from the root node and ends the access only when the current node is a leaf node. Otherwise, the access will be directed down.
He will access m [ai, bi]. You need to help him select the appropriate k for each node and output the minimum sum of the number of nodes accessed each time.
[Input Data]
The first line has two integers, n and m, and the next line has two integers, ai and bi.
[Output Data]
An integer in a row indicates the answer.
[Example input]
6 6
1 4
2 6
3 4
3 5
2 3
5 6
[Sample output]
40
[Data Scope]
For 20% of data, n <= 50, m <= 100.
For 40% of data, n <= 200.
For 70% of data, n <= 1000.
For 100% of data, n <= 5000, m <= 100000.
Question
F [I, j] indicates the minimum number of accesses to the subtree of node [I, j]. w [I, j] indicates the node [I, j, j] the number of accesses, that is, the number of intervals that intersection [I, j.
F [I, j] = min {f [I, k] + f [k + 1, j]} + w [I, j] (I <= k <j)
First, w is pre-processed, so the complexity of this dp is O (n ^ 3), which can be optimized to O (n ^ 2) using a quadrilateral inequality)
#include<iostream>#include<cstdlib>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>using namespace std;int n,m;int l[5005],r[5005],f[5005][5005],w[5005][5005];int main(){ int i,j,k,x,y; freopen("segment.in","r",stdin); freopen("segment.out","w",stdout); scanf("%d%d",&n,&m); for(i=1;i<=m;++i) { scanf("%d%d",&x,&y); l[x]++;r[y]++; } for(i=1;i<=n;++i) r[i]+=r[i-1]; for(i=n;i>=1;i--) l[i]+=l[i+1]; memset(f,9999999,sizeof f); for(i=1;i<=n;i++) f[i][i]=m-r[i-1]-l[i+1]; for(i=1;i<=n;i++) w[i][i]=i; for(k=1;k<=n-1;k++) for(i=1;i<=n-k;i++) { for(j=w[i][i+k-1];j<=w[i+1][i+k]&&j+1<=i+k;++j) if(f[i][j]+f[j+1][i+k]<f[i][i+k]) { f[i][i+k]=f[i][j]+f[j+1][i+k]; w[i][i+k]=j; } f[i][i+k]+=(m-r[i-1]-l[i+k+1]); } printf("%d",f[1][n]); fclose(stdin); fclose(stdout); return 0;}