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\) 个查询, 每次给定一个大小为 ...
随机推荐
- PHP编译安装出错configure: error: mcrypt.h not found. Please reinstall libmcrypt的解决办法
1.下载libmcrypt wget http://jaist.dl.sourceforge.net/project/mcrypt/Libmcrypt/2.5.8/libmcrypt-2.5.8.ta ...
- CakePHP之请求与响应对象
请求与响应对象 请求与响应对象在 CakePHP 2.0 是新增加的.在之前的版本中,这两个对象是由数组表示的,而相关的方法是分散在RequestHandlerComponent,Router,Dis ...
- Android开发常见错误类型一览表
这是我的第一个博客,我会一直添加我在Android开发中遇到的错误,用来记录我开发中踩过的那些坑 ------------------------分割线------------------------ ...
- java 更改list 某一元素?
if(!elTd.getElementsByTag("p").isEmpty()){ int i=eduList.size(); if(i>0){ ...
- head标签
1.head标签中有个<meta>,,个人理解知识,可以设置页面字符集,文本格式,还可以加一些注释,例如如下所示
- PHP 进行统一邮箱登陆的代理实现(swoole)
在工作的过程中,经常会有很多应用有发邮件的需求,这个时候需要在每个应用中配置smtp服务器.一旦公司调整了smtp服务器的配置,比如修改了密码等,这个时候对于维护的人员来说要逐一修改应用中smtp的配 ...
- OC - 26.CAAnimationGroup
概述 简介 CAAnimationGroup又称组动画或动画组 将多个动画放到动画组中,并赋值给layer的animations属性,动画组中所有动画就会并发执行 注意事项 动画组中的动画不会被压缩, ...
- UILabel的高度自适应
_content = [UILabel new]; _content.text = @"日落时分,沏上一杯山茶,听一曲意境空远的<禅>,心神随此天籁,沉溺于玄妙的幻境里.仿佛我就 ...
- JavaScript HTML DOM
JavaScript HTML DOM 通过 HTML DOM,可访问 JavaScript HTML 文档的所有元素. HTML DOM (文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象 ...
- 移动端touchstar、touchmove、touchend 事件如果页面有滚动时不让触发 touchend 事件。
/*仅适用于内容中点击元素.对于拖动等元素,需要自行在页面处理. * 主要是绑定touchstart和touchmove事件,并判断用户按下之后手指移动了多少像素. * 如果手指移动距离小于10像素, ...