您的位置:首页 > 其它

CF#398(Div.2) 解题报告

2017-02-18 23:29 309 查看

A

题意简述

有n个大小为1..n的物品,每一天会得到一个,物品必须由下而上按照从大到小的顺序摆放

每一天会将已有的物品尽量摆放,问这n天的摆放方案

数据范围

1≤n≤100000

题解

只有一个物品只有当比它大的所有物品都得到时才能摆放

模拟即可

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<ctime>
#include<cmath>
#include<map>
using namespace std;
#define N 100005

int n,x,now;
bool vis
;

int main()
{
scanf("%d",&n);
now=n;
for (int i=1;i<=n;++i)
{
scanf("%d",&x);
vis[x]=1;
while (vis[now]) printf("%d ",now--);
puts("");
}
}


B

题意简述

接待处服务时间为0点之后ts~tf-1,每一个人需要的服务时间为t

有一些人在某一个时刻来并且排队

V也会在某一个时间来,如果这个时间也有别人来,他会排在这些人的后面

求V的最小等待时间

数据范围

0≤n≤100000,ts,tf,t≤1012

题解

首先判断服务是否有断层,如果有的话即在那个时刻来

如果没有断层,枚举V在哪一个时间点来,有价值的时间点只有n个时间点以及两个时间点之间的断点

预处理时间点ai来的人需要办理服务到什么时间

注意n=0需要特判

算是贪心吧

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<ctime>
#include<cmath>
#include<map>
using namespace std;
#define LL long long
#define N 100005

const LL inf=1e18;
int n,Max;
LL s,t,l;
LL now,a
,ed
,ans,ansp;

int main()
{
scanf("%I64d%I64d%I64d",&s,&t,&l);--t;
scanf("%d",&n);
if (!n) {printf("%I64d\n",s);return 0;}
for (int i=1;i<=n;++i) scanf("%I64d",&a[i]);
now=s;Max=n;
for (int i=1;i<=n;++i)
{
if (a[i]<=now) now+=l,ed[i]=now-1;
else {printf("%I64d\n",now);return 0;}
if (now>t-l+1) {Max=i;break;}
}
if (ed[Max]<t-l+1) {printf("%I64d\n",ed[Max]+1LL);return 0;}

ans=inf;
for (int i=Max-1;i>=1;--i)
if (a[i]==a[i+1]) ed[i]=max(ed[i],ed[i+1]);

if (a[1]>0)
{
now=s-(a[1]-1LL);
if (now<ans) ans=now,ansp=a[1]-1LL;
}
for (int i=1;i<=Max;++i)
{
if (ed[i]<t-l+1)
{
now=ed[i]+1LL-a[i];
if (now<ans) ans=now,ansp=a[i];
}
if (i==Max||a[i+1]-a[i]<=1LL) continue;
else
{
now=ed[i]+1LL-(a[i+1]-1LL);
if (now<ans) ans=now,ansp=a[i+1]-1LL;
}
}
printf("%I64d\n",ansp);
return 0;
}


C

题意简述

一棵有根树每一个节点有一个权值

需要将这棵树断开两条边变成三棵树,并满足三棵树的权值和相等

无解-1

注意:只能将某一个节点与其父亲相连的那条边断开

数据范围

3≤n≤106,−100≤ti≤100

题解

首先总权值和被3整除

可以满足条件的只有两种情况

1、两棵子树权值和为sum3,并且互不包含

2、一棵子树权值和为2∗sum3,一棵子树权值和为sum3并且前者包含后者

dfs即可

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<ctime>
#include<cmath>
#include<map>
using namespace std;
#define N 1000005

int n,fa,root,sum,id;
int tot,point
,nxt
,v
;
int size
,ans[5];
bool pd,flag
;

void add(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
}
void findse(int x)
{
for (int i=point[x];i;i=nxt[i])
{
if (size[v[i]]==sum/3)
{
ans[2]=v[i];
printf("%d %d\n",ans[1],ans[2]);
exit(0);
}
findse(v[i]);
}
}
void findsy(int x)
{
if (pd) return;
if (size[x]==sum/3)
{
ans[++id]=x;
pd=1;
return;
}
for (int i=point[x];i;i=nxt[i])
findsy(v[i]);
}
void dfs(int x)
{
int cnt=0;
for (int i=point[x];i;i=nxt[i])
{
dfs(v[i]);
size[x]+=size[v[i]];
if (flag[v[i]]) ++cnt;
}
if (cnt>=2)
{
id=0;
for (int i=point[x];i;i=nxt[i])
if (flag[v[i]])
{
pd=0;
findsy(v[i]);
if (id==2) break;
}
printf("%d %d\n",ans[1],ans[2]);
exit(0);
}
if (x!=root&&(cnt||size[x]==sum/3)) flag[x]=1;
if (x!=root&&size[x]==sum/3*2&&flag[x])
{
ans[1]=x;
findse(x);
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%d%d",&fa,&size[i]);
sum+=size[i];
if (fa) add(fa,i);
else root=i;
}
if (sum%3!=0) {puts("-1");return 0;}
dfs(root);
if (ans[1]&&ans[2]) printf("%d %d\n",ans[1],ans[2]);
else puts("-1");
}


一点总结。。。

感觉最近各种傻逼→_→

①认真读题!认真看数据范围!尤其是极限的情况(不光包括上界也包括下界)

②要认真想不合法的情况,加特判

③想清楚再写,非常麻烦的题不要慌,一点一点写
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: