链接:http://codeforces.com/contest/681
problemA:水题
problemB:水题
problemC:给定一个堆的操作序列,操作有:insert x,getmin x,removemin。这个序列可能是非法的,求将这个序列补充成合法的并且添加的操作最少。
分析:按照给定的序列用优先队列模拟就行了,少了就加多了就删。
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=100010;
const int MAX=1000000100;
const int mod=100000000;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=998244353;
const int INF=1000000010;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned long long ull;
priority_queue<int, vector<int>, greater<int> >Q;
char s[20];
int a[N],b[N];
int main()
{
int i,n,m=0;
scanf("%d", &n);
for (i=1;i<=n;i++) {
scanf("%s", s);
if (s[0]=='i') { a[i]=1;scanf("%d", &b[i]); }
else if (s[0]=='g') { a[i]=2;scanf("%d", &b[i]); }
else { a[i]=3;b[i]=0; }
}
for (i=1;i<=n;i++)
if (a[i]==1) {
m++;Q.push(b[i]);
} else if (a[i]==2) {
if (Q.empty()||Q.top()>b[i]) {
Q.push(b[i]);m+=2;
} else {
while (!Q.empty()&&Q.top()<b[i]) { m++;Q.pop(); }
if (!Q.empty()&&Q.top()==b[i]) m++;
else { Q.push(b[i]);m+=2; }
}
} else {
if (Q.empty()) m+=2;
else { m++;Q.pop(); }
}
printf("%d\n", m);
while (!Q.empty()) Q.pop();
for (i=1;i<=n;i++)
if (a[i]==1) {
printf("insert %d\n", b[i]);
m++;Q.push(b[i]);
} else if (a[i]==2) {
if (Q.empty()||Q.top()>b[i]) {
printf("insert %d\n", b[i]);
printf("getMin %d\n", b[i]);
Q.push(b[i]);m+=2;
} else {
while (!Q.empty()&&Q.top()<b[i]) {
printf("removeMin\n");
m++;Q.pop();
}
if (!Q.empty()&&Q.top()==b[i]) {
printf("getMin %d\n", b[i]);m++;
} else {
Q.push(b[i]);
printf("insert %d\n", b[i]);
printf("getMin %d\n", b[i]);
m+=2;
}
}
} else {
if (Q.empty()) {
printf("insert 0\n");
printf("removeMin\n");
m+=2;
} else {
printf("removeMin\n");
m++;Q.pop();
}
}
return 0;
}
problemD:给定n个人和m对父子关系,给定n个人想要送礼物的祖先a[i]。要求输出一个最短的序列满足:对于第i个人,a[i]一定是i的所有祖先中最先在序列里出现的祖先。
分析:我的做法是将所有人的愿望按a[i]的深度从大到小排列,然后每次先插入深度更深的点到序列尾部,这是显然的。然后我们用dfs序+树状数组判断一下当前这个点的祖先中是否已经有非a[i]的点在序列中出现了。O(nlogn)。看了卿神的思路,才恍然大悟。这个题其实限制条件有点过于充足,限制得太紧。对于所有父子i-j,a[j]一定为j或者a[i],否则一定无解,因为这样的话i和j要送礼物的祖先的顺序是无解的。那么这题就只要dfs一下就行了。O(n)
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=100010;
const int MAX=1000000100;
const int mod=100000000;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=998244353;
const int INF=1000000010;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned long long ull;
struct node{
int x,y;
}a[N];
int tot,d[N],u[N],v[N],pre[N];
void add(int x,int y) {
v[tot]=y;pre[tot]=u[x];u[x]=tot++;
}
int n,f[N],q[N],de[N],in[N],out[N],ans[N];
void dfs(int x,int f) {
de[x]=de[f]+1;
in[x]=++tot;
for (int i=u[x];i!=-1;i=pre[i]) dfs(v[i],x);
out[x]=tot;
}
int cmd(node x,node y) {
return de[x.y]>de[y.y];
}
void add_x(int x,int y) {
for (;x<=n+1;x+=x&-x) f[x]+=y;
}
int getsum(int x) {
int ret=0;
for (;x;x-=x&-x) ret+=f[x];
return ret;
}
int main()
{
int i,m,x,y,bo,sum;
scanf("%d%d", &n, &m);
tot=0;memset(u,-1,sizeof(u));
for (i=1;i<=m;i++) {
scanf("%d%d", &x, &y);
add(x,y);d[y]++;
}
for (i=1;i<=n;i++)
if (d[i]==0) add(0,i);
x=0;memset(q,0,sizeof(q));
for (i=1;i<=n;i++) {
a[i].x=i;scanf("%d", &a[i].y);
if (!q[a[i].y]) { x++;q[a[i].y]=1; }
}
tot=0;dfs(0,0);
sort(a+1,a+n+1,cmd);
bo=1;y=0;
memset(q,0,sizeof(q));
memset(f,0,sizeof(f));
for (i=1;i<=n;i++) {
sum=getsum(in[a[i].x]);
if (sum==0) {
ans[++y]=a[i].y;q[a[i].y]=1;
add_x(in[a[i].y],1);add_x(out[a[i].y]+1,-1);
} else if (sum>1) bo=0;
else if (!q[a[i].y]) bo=0;
}
if (!bo) printf("-1\n");
else {
printf("%d\n", x);
for (i=1;i<=x;i++) printf("%d\n", ans[i]);
}
return 0;
}

本文解析了CodeForces竞赛中的两个题目,包括堆操作序列修正的最小化问题及基于父子关系的人际礼物交换序列设计问题,并提供了详细的算法思路与代码实现。
1665

被折叠的 条评论
为什么被折叠?



