HNOI 2016 省队集训日记
第一天
DeepDarkFantasy
从东京出发,不久便到一处驿站,写道:日暮里。 ——鲁迅《藤野先生》
定义一个置换的平方为对1~n的序列做两次该置换得到的序列。已知一个置换的平方,并且这个结果是一个排列,求该置换。
输入第一行一个数n表示排列长度,接下来一行n个数描述排列。
有解则输出一行n个数表示原排列。否则输出一行一个-1。
测试点编号 |
特征 |
0~1 |
n<=10 |
2~9 |
n<=1000000 |
此题有spj。
考试的时候懵逼了,根本没想清就开始乱打。
题解:由题易得每一个置换相当于一个n个点n条边的图,那么相当于是已知每个点在图上走两步的终点,求这个图。于是我们可以很快的得到,无论图中的环是奇环还是偶环,最终得到的答案都会是偶环。然后对于两种不同的情况分类讨论一下就可以得到解法了。
代码写丑了,虽然是O(N)的,但因为常数问题没能过。
- #include <algorithm>
- #include <iostream>
- #include <cstring>
- #include <cstdio>
- using namespace std;
- const int maxn=;
- int a[maxn],num[maxn];
- int ans[maxn],p[maxn];
- int b[maxn],n;
- int st[maxn],top;
- int vis[maxn],c[maxn];
- bool cmp(int x,int y){
- return num[x]<num[y];
- }
- int main(){
- #ifndef ONLINE_JUDGE
- freopen("deepdarkfantasy.in","r",stdin);
- freopen("deepdarkfantasy.out","w",stdout);
- #endif
- scanf("%d",&n);
- for(int i=,x;i<=n;i++){
- scanf("%d",&x);
- a[x]=i;p[i]=i;
- }
- int x,y,t,q,tot;
- for(int i=;i<=n;i++){
- if(a[i]==i){
- b[i]=i;
- continue;
- }
- if(!vis[i]){
- x=i,tot=;
- while(!vis[x]){
- tot+=;
- vis[x]=;
- x=a[x];
- }
- st[++top]=x;
- num[top]=tot;
- c[tot]+=;
- }
- }
- for(int i=;i<=n;i++)
- if(i%==&&c[i]%){
- printf("-1\n");
- return ;
- }
- sort(p+,p+top+,cmp);
- for(int i=;i<=top;i++){
- x=p[i],t=st[x];
- if(num[x]%){
- for(int j=,k=;j<=num[x];j++){
- ans[k]=t;
- t=a[t];k+=;
- if(k>num[x])k=;
- }
- ans[]=ans[num[x]];
- for(int j=;j<=num[x];j++)
- b[ans[j-]]=ans[j];
- }
- else{
- y=p[++i],q=st[y];
- for(int j=;j<=*num[x];j++){
- if(j%){
- ans[j]=t;
- t=a[t];
- }
- else{
- ans[j]=q;
- q=a[q];
- }
- }
- ans[]=ans[*num[x]];
- for(int j=;j<=*num[x];j++)
- b[ans[j-]]=ans[j];
- }
- }
- for(int i=;i<=n;i++)
- printf("%d ",b[i]);
- printf("\n");
- return ;
- }
Wallace
“看来华莱士先生不太懂历史和哲♂学” ——自长者与美国记者华莱士的谈话
有两颗各含N个点的无根树,每棵树中点分别被编号为0,1,2,....,N-1;注意两棵树并不保证同构。另外给一个N长的整数数组Score[],记录N个编号的得分,Score中的每个元素可正可负。问题的任务是寻找 集合{0,1,2,3,4,...,N-1}的一个最优子集subset(可以是空集),要求满足以下条件:
1)在第一棵树中,subset中包含的编号对应的点能构成一个连通的子图;即去掉这棵树中所有subset中不包含的点后,剩下的点依然是一棵连通的树。
2)在第二棵树中,subset中包含的编号对应的点也能构成一个连通的子图;
3)使subset包含编号的总得分尽可能的大;即SUM{ Score[i] | i∈subset }能取到尽可能大的值。
输入第一行一个正整数N。第二行N个整数Score[]代表0~N-1每个点的权值。
后面N-1行每行两个整数u,v代表第一棵树里面u点和v点之间有连边。
再后面N-1行每行两个整数u,v代表第二棵树里面u点和v点之间有连边。
输出一行一个整数代表这个subset包含编号的总分的最大值。
测试点编号 |
特征 |
0~5 |
n<=15 |
6~9 |
两棵树形状与编号完全相同 |
12~24 |
2<=n<=50且|Score[i]|<=1000且0<=u,v<n |
这道题并不是很难,枚举一个点必选,则可以用网络流做。
- #include <iostream>
- #include <cstring>
- #include <cstdio>
- #include <queue>
- using namespace std;
- const int maxn=;
- const int maxm=;
- const int INF=;
- int cnt,tot,fir[maxn],fron[maxn],dis[maxn];
- int to[maxm],nxt[maxm],gap[maxn],path[maxn];
- int cap[maxm];queue<int>q;
- struct Max_Flow{
- void Init(int tot_=){
- tot=tot_;cnt=;
- memset(fir,,sizeof(fir));
- memset(dis,,sizeof(dis));
- memset(gap,,sizeof(gap));
- }
- void add(int a,int b,int c){
- nxt[++cnt]=fir[a];
- fir[a]=cnt;
- cap[cnt]=c;
- to[cnt]=b;
- }
- void addedge(int a,int b,int c){
- add(a,b,c);
- add(b,a,);
- }
- bool BFS(int s,int t){
- dis[t]=;q.push(t);
- while(!q.empty()){
- int x=q.front();q.pop();
- for(int i=fir[x];i;i=nxt[i])
- if(!dis[to[i]]){
- dis[to[i]]=dis[x]+;
- q.push(to[i]);
- }
- }
- return dis[s];
- }
- int Aug(int s,int t,int &p){
- int f=INF;
- while(p!=s){
- f=min(f,cap[path[p]]);
- p=to[path[p]^];
- }p=t;
- while(p!=s){
- cap[path[p]]-=f;
- cap[path[p]^]+=f;
- p=to[path[p]^];
- }
- return f;
- }
- int ISAP(int s,int t){
- if(!BFS(s,t))return ;
- for(int i=s;i<=t;i++)fron[i]=fir[i];
- for(int i=s;i<=t;i++)gap[dis[i]]+=;
- int p=s,ret=;
- while(dis[s]<=tot){
- if(p==t)ret+=Aug(s,t,p);
- for(int &i=fron[p];i;i=nxt[i])
- if(cap[i]&&dis[p]==dis[to[i]]+){
- path[p=to[i]]=i;
- break;
- }
- if(!fron[p]){
- if(--gap[dis[p]]==)
- break;
- int Min=tot;
- for(int i=fir[p];i;i=nxt[i])
- if(cap[i])Min=min(Min,dis[to[i]]);
- gap[dis[p]=Min+]+=;fron[p]=fir[p];
- if(p!=s)p=to[path[p]^];
- }
- }
- return ret;
- }
- }isap;
- int w[maxn],n;
- int G[maxn][maxn];
- int G2[maxn][maxn];
- int dep[maxn],pre[maxn];
- void Build(int x,int y){
- int py=y;
- while(x!=py){
- if(dep[x]>dep[py]){
- x=pre[x];
- isap.addedge(y,x,INF);
- }
- else{
- py=pre[py];
- isap.addedge(y,py,INF);
- }
- }
- }
- int DFS(int x,int fa){
- int ret=;
- if(w[x]>=){
- isap.addedge(,x,w[x]);
- ret+=w[x];
- }
- else isap.addedge(x,n+,-w[x]);
- for(int i=;i<=n;i++)
- if(G[x][i]&&i!=fa){
- isap.addedge(i,x,INF);
- Build(x,i);ret+=DFS(i,x);
- }
- return ret;
- }
- void Prepare(int x,int fa){
- for(int i=;i<=n;i++)
- if(G2[x][i]&&i!=fa){
- dep[i]=dep[x]+;
- pre[i]=x;Prepare(i,x);
- }
- }
- int main(){
- freopen("wallace.in","r",stdin);
- freopen("wallace.out","w",stdout);
- scanf("%d",&n);
- for(int i=;i<=n;i++)
- scanf("%d",&w[i]);
- for(int i=,a,b;i<n;i++){
- scanf("%d%d",&a,&b);
- G[a+][b+]=G[b+][a+]=;
- }
- for(int i=,a,b;i<n;i++){
- scanf("%d%d",&a,&b);
- G2[a+][b+]=G2[b+][a+]=;
- }Prepare(,);
- int ans=,tmp;
- for(int i=;i<=n;i++){
- isap.Init(n+);tmp=DFS(i,);
- ans=max(ans,tmp-isap.ISAP(,n+));
- }
- printf("%d\n",ans);
- return ;
- }
第二天
永不落幕的 永不落幕的 zy
【背景】
人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。 人们的感情像洪水一样袭来,头晕目眩。
【题目 描述】 描述】
zy 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 是一位拥有“共感”能力的少年,他总意无地知别人心情。 sm 是一位 是一位 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 有着“心墙”的少女,她感情无法传递出去。就像命运一般他们相遇了仿佛 zy (的 能力)就是为了 能力)就是为了 能力)就是为了 能力)就是为了 sm 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。 而存在一样(事实上也确如此)。
sm 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 的心墙由许多迷茫组成,每个都希望从 X轴上某一点去到另,而只有 轴上某一点去到另,而只有 轴上某一点去到另,而只有 轴上某一点去到另,而只有 轴上某一点去到另,而只有 轴上某一点去到另,而只有 轴上某一点去到另,而只有 zy 能 消除 sm 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, 的迷茫。面对数量如此庞大, zy 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。 不曾想要放弃,但有些迷失了方向。
假设现在时间是 假设现在时间是 假设现在时间是 假设现在时间是 0,zy 在心墙的 在心墙的 在心墙的 1位置, 位置, zy 每单位时间的移动速度是 每单位时间的移动速度是 每单位时间的移动速度是 每单位时间的移动速度是 每单位时间的移动速度是 每单位时间的移动速度是 1。
若现在 若现在 zy 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 携带的迷茫想要去地点和心墙上剩下中在他右边个数大于等左 边,则 边,则 zy 会向右移动,反之左。若现在 会向右移动,反之左。若现在 会向右移动,反之左。若现在 会向右移动,反之左。若现在 会向右移动,反之左。若现在 会向右移动,反之左。若现在 会向右移动,反之左。若现在 会向右移动,反之左。若现在 sm 没有任何迷茫,则 没有任何迷茫,则 没有任何迷茫,则 没有任何迷茫,则 没有任何迷茫,则 zy 原地不动。现在 原地不动。现在 原地不动。现在 原地不动。现在 zy 想 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。 知道,组成心墙的每个迷茫分别在什么时候消失。
为了尽快地让 为了尽快地让 为了尽快地让 zy 能拥抱 能拥抱 sm ,请你帮他。 ,请你帮他。 ,请你帮他。 ,请你帮他。
【输入描述】 【输入描述】
第一行两个数 第一行两个数 第一行两个数 N,M表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 表示迷茫的数量和心墙大小。接下来 N行 ,每行 ,每行 ,每3个整 数, t, a,b,表示这个迷茫出现在时刻 ,表示这个迷茫出现在时刻 ,表示这个迷茫出现在时刻 ,表示这个迷茫出现在时刻 ,表示这个迷茫出现在时刻 ,表示这个迷茫出现在时刻 ,表示这个迷茫出现在时刻 t,希望从 ,希望从 a到 b。
【输出描述】 【输出描述】
N行 N个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失 个整数,表示每迷茫分别在什么时候消失
【样例输入】 【样例输入】
2 102 102 102 10
1 2 51 2 51 2 51 2 5
7 4 57 4 57 4 57 4 5
【样例输出】 【样例输出】
5
9
【样例解释】 【样例解释】
时刻 1,有迷茫出现了! ,有迷茫出现了! ,有迷茫出现了! ,有迷茫出现了! ,有迷茫出现了!
时刻 2,zy 移动到了位置 移动到了位置 移动到了位置 移动到了位置 2。
时刻 5,zy 移动到了位置 移动到了位置 移动到了位置 移动到了位置 5,迷茫消失。 ,迷茫消失。 ,迷茫消失。
时刻 7,有迷茫出现了! ,有迷茫出现了! ,有迷茫出现了! ,有迷茫出现了! ,有迷茫出现了!
时刻 8,zy 移动到了位置 移动到了位置 移动到了位置 移动到了位置 4。
时刻 9,zy 移动到了位置 移动到了位置 移动到了位置 移动到了位置 5,迷茫消失。 ,迷茫消失。 ,迷茫消失。
【数据范围】 【数据范围】
对于 30%30%30%的数据 的数据 : N, M, t <= 100t <= 100 t <= 100t <= 100 t <= 100t <= 100
对于 60%60%60%的数据 的数据 : N, M, t <= N, M, t <= N, M, t <= N, M, t <= N, M, t <= N, M, t <= 1000010000100001000010000
对于 100%100%100%100%的数据 的数据 : N, M, t <= 100000 N, M, t <= 100000 N, M, t <= 100000N, M, t <= 100000N, M, t <= 100000 N, M, t <= 100000N, M, t <= 100000N, M, t <= 100000N, M, t <= 100000N, M, t <= 100000N,
这么长的题面,呵呵了。
发现如果每次处理一个迷惘,则只有O(N)次操作,考虑将每次的复杂度降为log2N。
这里用的treap。
- #include <algorithm>
- #include <iostream>
- #include <cstring>
- #include <cstdlib>
- #include <cstdio>
- using namespace std;
- const int maxn=;
- const long long INF=10000000000000000LL;
- struct Node{
- long long t,a,b;
- int id,tp;
- Node(long long t_=,long long a_=,long long b_=,int id_=,int tp_=){
- t=t_;a=a_;b=b_;id=id_;tp=tp_;
- }
- }px[maxn],t[maxn];
- bool cmp(Node x,Node y){
- return x.t<y.t;
- }
- int cnt;
- int sz[maxn],rt;
- int ch[maxn][];
- void Push_up(int x){
- sz[x]=sz[ch[x][]]+sz[ch[x][]]+;
- }
- int Newnode(Node x){
- sz[++cnt]=;t[cnt]=x;
- ch[cnt][]=ch[cnt][]=;
- return cnt;
- }
- int Merge(int x,int y){
- if(!x||!y)return x|y;
- if(rand()%){
- ch[x][]=Merge(ch[x][],y);
- Push_up(x);return x;
- }
- else{
- ch[y][]=Merge(x,ch[y][]);
- Push_up(y);return y;
- }
- }
- int ta,tb;
- void Split(int p,long long k){
- if(p==)return;
- if(k==sz[ch[p][]]+){
- ta=ch[p][];tb=p;
- ch[p][]=;Push_up(p);
- return;
- }
- if(k<sz[ch[p][]]+){
- Split(ch[p][],k);
- ch[p][]=tb;tb=p;
- Push_up(p);
- }
- else{
- k-=sz[ch[p][]]+;
- Split(ch[p][],k);
- ch[p][]=ta;ta=p;
- Push_up(p);
- }
- }
- int tx,ty,tz;
- void Get_div(int l,int r){
- Split(rt,r+);ty=ta;tz=tb;
- Split(ty,l);tx=ta;ty=tb;
- }
- void Get_mer(){
- tx=Merge(tx,ty);
- rt=Merge(tx,tz);
- }
- int ID,POS;
- void Get_Prev(long long k){
- int p=rt,num=;
- while(p){
- if(t[p].a<=k){
- ID=p;num+=sz[ch[p][]]+;
- POS=num;p=ch[p][];
- }
- else p=ch[p][];
- }
- return;
- }
- void Get_Succ(long long k){
- int p=rt,num=;
- while(p){
- if(t[p].a<k){
- num+=sz[ch[p][]]+;
- p=ch[p][];
- }
- else{
- ID=p;POS=num+sz[ch[p][]]+;
- p=ch[p][];
- }
- }
- return;
- }
- //严格小于x的个数
- long long Get_Min(long long x){
- Get_Succ(x);
- return POS-;
- }
- void Insert(Node x){
- Get_Prev(x.a);
- Split(rt,POS+);
- ta=Merge(ta,Newnode(x));
- rt=Merge(ta,tb);
- }
- void Delete(int p){
- Get_div(p,p);
- rt=Merge(tx,tz);
- }
- int n,m;
- long long nt=,np=;
- int Get_Tow(){
- long long Min=Get_Min(np);
- long long Max=sz[rt]-Min;
- return Min<=Max?:-;
- }
- void Init(){
- rt=Newnode(Node(,-,,,));
- rt=Merge(rt,Newnode(Node(,INF,,,)));
- }
- void Print(long long p){
- if(!p)return;
- Print(ch[p][]);
- printf("%lld ",t[p].a);
- Print(ch[p][]);
- }
- void Debug(){
- printf("~~~~~~~~~~~~~~~~~\n");
- Print(rt);
- printf("\n~~~~~~~~~~~~~~~~~\n");
- }
- long long ans[maxn];
- int main(){
- freopen("sm.in","r",stdin);
- freopen("sm.out","w",stdout);
- Init();
- scanf("%d%d",&n,&m);srand(n);
- for(int i=;i<=n;i++){
- long long t,a,b;
- scanf("%lld%lld%lld",&t,&a,&b);
- px[i]=Node(t,a,b,i,);
- }
- sort(px+,px+n+,cmp);
- for(int i=;i<=n;i++){
- while(sz[rt]>){
- int tow=Get_Tow();
- if(tow==){
- Get_Succ(np);
- if(nt+t[ID].a-np>=px[i].t){
- np+=px[i].t-nt;
- break;
- }
- nt+=t[ID].a-np;
- np=t[ID].a;
- Delete(POS);
- if(t[ID].tp==)
- Insert(Node(,t[ID].b,,t[ID].id,));
- else
- ans[t[ID].id]=nt;
- }
- else{
- Get_Prev(np);
- if(nt+np-t[ID].a>=px[i].t){
- np-=px[i].t-nt;
- break;
- }
- nt+=np-t[ID].a;
- np=t[ID].a;
- Delete(POS);
- if(t[ID].tp==)
- Insert(Node(,t[ID].b,,t[ID].id,));
- else
- ans[t[ID].id]=nt;
- }
- }
- Insert(px[i]);
- nt=px[i].t;
- //Debug();
- }
- while(sz[rt]>){
- int tow=Get_Tow();
- if(tow==){
- Get_Succ(np);
- nt+=t[ID].a-np;
- np=t[ID].a;
- Delete(POS);
- if(t[ID].tp==)
- Insert(Node(,t[ID].b,,t[ID].id,));
- else
- ans[t[ID].id]=nt;
- }
- else{
- Get_Prev(np);
- nt+=np-t[ID].a;
- np=t[ID].a;
- Delete(POS);
- if(t[ID].tp==)
- Insert(Node(,t[ID].b,,t[ID].id,));
- else
- ans[t[ID].id]=nt;
- }
- }
- for(int i=;i<=n;i++)
- printf("%lld\n",ans[i]);
- return ;
- }
第三天
博士的选取器(Selector.cpp)
【题目描述】
浏览到好图好句的时候,为了避免被删帖、封图、和谐,博士会掏出他的选取器,将好图好句框住,然后Ctrl+C,Ctrl+V。博士从初一开始坚持到现在,已经有2GB了。在反复地与吧主斗争之后,博士总结出了经验。
1).对于一篇帖子,可以从上至下分成N个片段,每个片段不可分割,且只有序号相邻的片段才相邻。
2).每次框选只能框选连续一段片段[L,R],而且这连续一段片段的总字符量不能超过LIMIT,否则会出错。
3).对于每次框选与复制,耗时只与这连续一段片段中字符量最大的那一个片段有关,而且满足正比例函数关系。为了让题目简单,规定耗时等于字符量。
4).两次框选之间的时间间隔可以视为0。
正在博士总结完经验的时候,他瞅到了一篇掺杂大量好图好句的帖子。于是,一场新的战争爆发了…………战局紧张,博士想知道他的最小耗时是多少。
【输入】
第一行两个整数N和Limit。
接下来的N行,每行一个整数,代表第I个片段的字符量
【输出】
仅一行,为博士的最小耗时。
【样例】
Sample Input (Selector.in)
Sample Output (Selector.out)
8 17
2
2
2
8
1
8
2
1
12
{解释:222/818/21,2+8+2=12}
【数据范围】
40%的数据N<=1000
100%的数据N<=300000
这个代码被卡常,无力吐槽,比时限长了0.05S左右,TM还是稳定的。
别人再带一个单调栈复杂度的,线段树优化一下照样踩我程序,QAQ……
- #include <algorithm>
- #include <iostream>
- #include <cstring>
- #include <cstdio>
- using namespace std;
- const int maxn=;
- const long long INF=1000000000000000LL;
- int a[maxn];
- long long sum[maxn],dp[maxn];
- long long tx[maxn*],ty[maxn*],tz[maxn*],tw[maxn*];
- void Push_down(int x){
- if(ty[x]==INF)return;
- ty[x<<]=ty[x];
- ty[x<<|]=ty[x];
- tz[x<<]=tx[x<<]+ty[x];
- tz[x<<|]=tx[x<<|]+ty[x];
- ty[x]=INF;
- }
- void Push_up(int x){
- tx[x]=min(tx[x<<],tx[x<<|]);
- tz[x]=min(tz[x<<],tz[x<<|]);
- }
- void Update(int x,int l,int r,int a,int b,int m){
- if(a>b)return;
- if(l>=a&&r<=b){
- ty[x]=m;
- tz[x]=m+tx[x];
- return;
- }
- Push_down(x);
- if(l+r>>>=a)Update(x<<,l,l+r>>,a,b,m);
- if(l+r>><b)Update(x<<|,(l+r>>)+,r,a,b,m);
- Push_up(x);
- }
- void Insert(int x,int l,int r,int g){
- if(l==r){
- tx[x]=dp[l];
- ty[x]=INF;
- return;
- }Push_down(x);
- if(l+r>>>=g)Insert(x<<,l,l+r>>,g);
- else Insert(x<<|,(l+r>>)+,r,g);
- Push_up(x);
- }
- long long Query(int x,int l,int r,int a,int b){
- if(a>b)return INF;
- if(l>=a&&r<=b)return tz[x];
- Push_down(x);
- long long ret=INF;
- int mid=(l+r)>>;
- if(mid>=a)
- ret=Query(x<<,l,mid,a,b);
- if(mid<b)
- ret=min(ret,Query(x<<|,mid+,r,a,b));
- return ret;
- }
- void Insert2(int x,int l,int r,int g){
- if(l==r){
- tw[x]=a[l];
- return;
- }
- if(l+r>>>=g)Insert2(x<<,l,l+r>>,g);
- else Insert2(x<<|,(l+r>>)+,r,g);
- tw[x]=max(tw[x<<],tw[x<<|]);
- }
- int Q(int x,int l,int r,long long g){
- if(l==r)return l;
- if(tw[x<<|]<g)
- return Q(x<<,l,l+r>>,g);
- else
- return Q(x<<|,(l+r>>)+,r,g);
- }
- int n,lim;
- int main(){
- freopen("Selector.in","r",stdin);
- freopen("Selector.out","w",stdout);
- scanf("%d%d",&n,&lim);
- for(int i=;i<=n;i++){
- scanf("%d",&a[i]);
- sum[i]=sum[i-]+a[i];
- }
- int Max0=;
- memset(tx,,sizeof(tx));
- memset(dp,,sizeof(dp));
- int p=;
- for(int i=;i<=n;i++){
- while(sum[i]-lim>sum[p])p+=;
- if(p==){
- Max0=max(Max0,a[i]);
- dp[i]=Max0;p+=;
- }
- int q=Q(,,n,a[i]);
- Insert2(,,n,i);
- Update(,,n,q,i-,a[i]);
- dp[i]=min(dp[i],Query(,,n,p,i-));
- Insert(,,n,i);
- if(p==&&sum[i]<=lim)p=;
- }
- printf("%lld\n",dp[n]);
- return ;
- }
HNOI 2016 省队集训日记的更多相关文章
- HN2018省队集训
HN2018省队集训 Day1 今天的题目来自于雅礼的高二学长\(dy0607\). 压缩包下载 密码: 27n7 流水账 震惊!穿着该校校服竟然在四大名校畅通无阻?霸主地位已定? \(7:10\)从 ...
- JS省队集训记
不知不觉省队集训已经结束,离noi也越来越近了呢 论考前实战训练的重要性,让我随便总结一下这几天的考试 Day 1 T1 唉,感觉跟xj测试很像啊?meet in middle,不过这种题不多测是什么 ...
- [HNOI 2016]树
Description 题库链接 给你一棵 \(N\) 个节点根节点为 \(1\) 的有根树,结点的编号为 \(1\sim N\) :我们称这颗树为模板树.需要通过这棵模板树来构建一颗大树.构建过程如 ...
- [2018HN省队集训D9T1] circle
[2018HN省队集训D9T1] circle 题意 给定一个 \(n\) 个点的竞赛图并在其中钦定了 \(k\) 个点, 数据保证删去钦定的 \(k\) 个点后这个图没有环. 问在不删去钦定的这 \ ...
- [2018HN省队集训D8T1] 杀毒软件
[2018HN省队集训D8T1] 杀毒软件 题意 给定一个 \(m\) 个01串的字典以及一个长度为 \(n\) 的 01? 序列. 对这个序列进行 \(q\) 次操作, 修改某个位置的字符情况以及查 ...
- [2018HN省队集训D8T3] 水果拼盘
[2018HN省队集训D8T3] 水果拼盘 题意 给定 \(n\) 个集合, 每个集合包含 \([1,m]\) 中的一些整数, 在这些集合中随机选取 \(k\) 个集合, 求这 \(k\) 个集合的并 ...
- [2018HN省队集训D6T2] girls
[2018HN省队集训D6T2] girls 题意 给定一张 \(n\) 个点 \(m\) 条边的无向图, 求选三个不同结点并使它们两两不邻接的所有方案的权值和 \(\bmod 2^{64}\) 的值 ...
- [Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform
[Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform 题意 给定一个小写字母构成的字符串, 每个字符有一个非负权值. 输出所有满足权值和等于这个子串在所有本质 ...
- [2018HN省队集训D5T2] party
[2018HN省队集训D5T2] party 题意 给定一棵 \(n\) 个点以 \(1\) 为根的有根树, 每个点有一个 \([1,m]\) 的权值. 有 \(q\) 个查询, 每次给定一个大小为 ...
随机推荐
- Datum Form Goole Android
1. <TurboChargeYourUI-How to make your AndroidUI fast and efficient> 2. <The World of List ...
- dnw for linux: Ubuntu下可用,无需编译驱动,mini2440可用
1.安装所需库文件 sudo apt-get install libusb-dev 2.源代码如下 /* dnw2 linux main file. This depends on libusb. * ...
- Ubuntu系统中安装RPM格式包的方法
Ubuntu的软件包格式为deb,而RPM格式的包则是Red Hat 相关系统所用的软件包.当我们看到一个想用的软件包时,如果他是RPM格式,而你的操作系统是Ubuntu,那岂不是很遗憾?其实,在Ub ...
- oracle-同义词,又学到东西了
select col1 from tab1@db_link1; create or replace synonym test123 as se,ect col1 from tab1@db_link ...
- HTTP请求返回的NSData无法转换为NSString
最近在做的一个项目中有一个功能是有一个网页,模拟http请求获取到这个网页返回的相应的数据. 在请求完成后获取到的数据为NSData类型,按照我们通常的转换为NSString的方法: NSString ...
- 微信小程序开发之 下拉刷新,上拉加载更多
本文记载了如何在微信小程序里面实现下拉刷新,上拉加载更多 先开看一下界面 大致如此的界面吧. 这个Demo使用了微信的几个Api和事件,我先列出来. 1.wx.request (获取远程服务器的数据, ...
- java中jdk环境配置
配置java环境,俗称jdk环境 首先进入配置环境的目录下:右键鼠标我的电脑->属性->高级系统设置->环境变量,在对应的"系统变量"框下配置一下变量: 规范的配 ...
- 30多条mysql数据库优化方法【转】
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...
- Ubuntu14.02 Sublimte2安装
$sudo add-apt-repository ppa:webupd8team/sublime-text-2 $sudo apt-get update $sudo apt-get install s ...
- NameNode元数据的管理机制(三)
元数据的管理: 第一步:客户端通过DistributedFilesystem 对象中的creat()方法来创建文件,此时,RPC会 通过一个RPC链接协议来调用namenode,并在命名空间中创建一个 ...