2016.8.29 解题报告之我会做的题都是简单题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2016.8.29 解题报告之我会做的题都是简单题相关的知识,希望对你有一定的参考价值。
老规矩,要相关资料联系邮箱;
考试分析:
1. 画图确定性质,其实我开始也打算用二进制判重的,但进制题一般不会使状态无法用longlong表示出来,然后那种确定了某种状态以后就排除了无关变量,直接取最优的思路也很不错;
2. 最早入手的题以及死在上面的题,还想了了很久的复杂度证明和对拍,无话可说,希望这次AK之路被断能让我涨一点记性,以后要抓住脑海里的每一点信息(本来还想了longlong这个问题的);
3. 找性质,把在线决策问题转化为线性判断类问题,排除任务之间有一点橡树的关系的无关干扰,发现贪心以后就一路顺畅了;
4. 总的来说这次还是考得不错了,中午觉都没睡好难过了好久,只想告诉自己以后路还有很长机会还有很多,而后悔是世界上最没有用的东西了,每一次考试的意义都不是排名与他人的赞誉,而是发现自己还有哪些问题——那些问题不是运气不好出现的,不是if only就可以避免的,而是注定会发生的,从中汲取教训,才是最重要的,毕竟,OI可是一场修行那;
5. 然后是正经的考试分析:
思维很重要,要努力让优秀成为一种惯性,学会发散性思考和举一反三,30min是看题和专注思考,也就是说只有专注于某一道题才能更快地找到突破口,不要有太大的压力,毕竟我可是只要检查了程序名检查了题意就绝对不会跪的可爱的Yuta啊xxxxx;,多画多算多思考,对了还有,一定要把算法想清楚了确认到循环和判断了再开始写,这样可以最小化找错的时间,今天考得好最最最主要的原因就是基本上程序都一次过了!以及,写完以后先自己检查一次再试数据,毕竟站在程序的高度上去调试可比对着数据调试的数据要高不止一倍那;
解题报告:
一.A
题意:找一棵树上的两个点线都不相交的子链,使得长度乘积最大,所有直接相连的链长度都为1;
注意:“不是每个点都直接或间接相连,不是连接仅n-1条,都不算是树xxx”
分析:这道题的数据范围小到可以直接暴力求距离,不擅长求距离的我感恩地五体投地QAQ,然后多fa图就能发现,其实要确保两条链不相交只需要枚举边就可以了,于是接下来就很容易了,枚举边,对于边相连的两个点求一次最长链然后再求一次最长链就可以了(这样才能保证一定是最长链),注意就是第二次求最长链的时候一定要避免走正在被枚举的那条边;
程序:
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
vector<int>e[205];
int maxn,ans,n,flg,sta[205],fin[205];
void dfs1(int u,int fr,int dep)
{
int tmp=e[u].size();
for(int i=0;i<tmp;i++)if(e[u][i]!=fr){
dfs1(e[u][i],u,dep+1);
}
maxn=max(dep,maxn);
if(dep==maxn)flg=u;
}
void dfs2(int u,int fr,int dep,int banana)
{
int tmp=e[u].size();
for(int i=0;i<tmp;i++)if(e[u][i]!=fr&&e[u][i]!=banana){
dfs2(e[u][i],u,dep+1,banana);
}
maxn=max(dep,maxn);
}
int dfsctr(int u,int fr)
{
maxn=0;flg=0;dfs1(u,fr,0);maxn=0;dfs2(flg,fr,0,fr);
return maxn;
}
int main()
{
freopen("A.input","r",stdin);
freopen("A.output","w",stdout);
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d %d",&sta[i],&fin[i]);
e[sta[i]].push_back(fin[i]);
e[fin[i]].push_back(sta[i]);
}
for(int i=1;i<n;i++){
ans=max(ans,dfsctr(sta[i],fin[i])*dfsctr(fin[i],sta[i]));
}
printf("%d",ans);
return 0;
}
二.B
题意:每个病人都有需要看病的次数,当前看完病以后就从队尾重新排,求k次以后的队列;
注意:无言以对,唯有沉默,第一次冲AK之旅就在这里失败,哀哉叹哉,呜呼噫嘻(这都是些什么啊),然后,要规范化写程序的步骤,比如用了longlong的,最后一定要检查赋值,即使不全部都强制转化,至少要做个实验看看会不会出问题;
分析:这道题涉及到一个很常见的算法,就是快排加取整体,这样优化以后可以每次减很多k,基本上就过了,这道题一看就是数学性质比较重的找规律题,通过自己列举大量数据发现实现方法;还有几个注意点
程序:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,last,tmp,cnt,roa[100005];
long long k;
struct pat
{
int val,num;
}a[100005];
bool cmp(pat x,pat y)
{
if(x.val<y.val)return true;
return false;
}
bool cmp2(pat x,pat y)
{
if(x.num<y.num)return true;
return false;
}
int main()
{
freopen("B.input","r",stdin);
freopen("B.output","w",stdout);
scanf("%d %I64d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i].val);
a[i].num=i;}
sort(a+1,a+n+1,cmp);tmp=0;cnt=0;
for(int i=1;i<=n;i++)if(a[i].val!=a[i-1].val)roa[cnt++]=i;
cnt=0;
while(k){
k-=(long long)(a[roa[cnt]].val-tmp)*(n-roa[cnt]+1);//long long//至少要试一下
if(k>=0){
tmp=a[roa[cnt]].val;cnt++;
}
else {
k+=(a[roa[cnt]].val-tmp)*(n-roa[cnt]+1);
tmp+=k/(n-roa[cnt]+1);//不然最后判断门槛会出错;
k%=(n-roa[cnt]+1);//优化后面的模拟
break;
}
}
sort(a+roa[cnt],a+n+1,cmp2);tmp++;
for(int i=k+roa[cnt];i<=n;i++){
if(last)
printf("%d ",last);
last=a[i].num;
}
for(int i=roa[cnt];i<k+roa[cnt];i++)if(a[i].val>tmp){
if(last)
printf("%d ",last);
last=a[i].num;
}
printf("%d",last);
return 0;
}
三.C
题意:有三个相连的房间,顺序距离为1,逆序距离为2,每个房间有一些任务,完成任务的时间也是1,选定开始房间,求最短时间;
注意:不能够把已经完成的点直接从链表里去掉,因为一共要枚举3个起点;
分析:其实这个逆序长度很有启发性,可以从贪心的角度得到决策的唯一性,也就是说不管怎么说顺序都不会比逆序要差,甚至可能要好(毕竟要多走一个点),所以直接模拟走就行了,但是算出来其实是会T一部分的,可以用拓扑排序优化掉一个长度(不可能因为后面的任务完成而可以做前面的任务;
程序:
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
int n,tmp,k,used[205],lef,nowy,timey,mini=2e9;
vector<int>tas[5],e[205];
int main()
{
freopen("C.input","r",stdin);
freopen("C.output","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&tmp);
tas[tmp].push_back(i);
}
for(int i=1;i<=n;i++){
scanf("%d",&k);
for(int j=1;j<=k;j++){
scanf("%d",&tmp);
e[i].push_back(tmp);
}
}
for(int i=1;i<=3;i++){
lef=n;memset(used,0,sizeof(used));
nowy=i;timey=0;
while(lef){
int ll=tas[nowy].size();
for(int jk=0;jk<ll;jk++){
int flg=0;ll=tas[nowy].size();
for(int z=0;z<ll;z++)if(!used[tas[nowy][z]]){
int u=tas[nowy][z];
int kk=0,len=e[u].size();
for(kk=0;kk<len;kk++)if(!used[e[u][kk]])break;
if(kk==len){
lef--;used[u]=1;timey++;flg=1;;
}
}
if(!flg)break;
}
timey++;nowy++;if(nowy>3)nowy=1;
}
mini=min(mini,timey-1);
}
printf("%d",mini);
return 0;
}
以上是关于2016.8.29 解题报告之我会做的题都是简单题的主要内容,如果未能解决你的问题,请参考以下文章