【test】2015.7.31测试解题报告(二)

来源:互联网 发布:淘宝怎么直播呀 编辑:程序博客网 时间:2024/06/05 11:13
五、events

ProblemXX: County Fair Events

FJ回到Fair村庄参加一些特别的比赛,他希望尽量多地参加这N(1 <= N <= 10,000)个比赛。

由于FJ懂得闪烁技能,所以他能在0时间内到达任意一个比赛,即可以瞬间到达任意一个比赛场地。

给你一个 FJ 希望参加比赛的列表, 包括开始时间T (1 <= T <= 100,000) 和持续时间L (1 <= L <=100,000), 请你求出FJ最多能参加几个比赛,而且FJ不会提前退出比赛。.

输入:

第一行:一个整数N

2~N+1行:两个整数TL

输出:

一行:一个整数SFJ最多参加几个比赛。

文件名: events

样例输入:events.in

7

1 6

8 6

14 5

19 2

1 8

18 3

10 6

样例输出:event.out

4

样例解释:

FJ 参加 1, 2, 3, 4个比赛.

 

【题目分析】

其实这题比较简单,不小心放得后了一点……看到这个和以前的room问题(前缀和)有点类似。但实际上两题性质不同,这道题可以用贪心解答。

我们想,比赛结束得越早,意味着有更多机会去参加其它比赛,所以说第一步我们按照结束时间(开始时间加结束时间)进行排序。第二步就是看看第二场比赛的开始时间是否大于等于第一场比赛的结束时间,如果是就ans++,看第三场比赛开始时间是否大于等于第二场比赛的结束时间;否则看第三场比赛的开始时间是否大于第一场比赛的结束时间,以此类推,保证是最优解。

 

【例程】

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int n,nowend,ans=1;

struct Teven
{
int begin,end;
};
Teven game[10001];

int cmp(Teven a,Teven b)
{
if(a.end==b.end)return a.begin<b.begin;
return a.end<b.end;
}

int main()
{
freopen("events.in","r",stdin);
freopen("events.out","w",stdout);

scanf("%d",&n);
for(int i=0;i<n;++i)
{
scanf("%d%d",&game[i].begin,&game[i].end);
game[i].end+=game[i].begin;
}

sort(game+0,game+n,cmp);

nowend=game[0].end;
for(int i=1;i<n;++i)
{
if(game[i].begin>=nowend)
{
ans++;
nowend=game[i].end;
}
}

printf("%d\n",ans);
return 0;
}


六、moooo

问题 XXMoooo [Brian Dean, 2005]

 

农场主约翰的n1 <= N <= 50,000)头牛站在一排鸣叫。每头牛都有不同的高度H,范围是1...2000000000纳米(FJ确实是个坚持细节的人)每头牛鸣叫的音量v的范围是1..10,000。鸣叫声会往左右两个方向传播(当然,在边上的牛除外)。有趣的是,鸣叫声只会被最近的,高度比鸣叫的牛高的那头牛听到(所以,每个鸣叫声可能会被0,1,或2头牛听见,这取决于左右两边是否存在比鸣叫的牛高的牛)。

 

一头牛听到的总音量是它能听到声音音量V的总和。有些牛(可能高一些),可能会听见非常大的声音。FJ想给听力受威胁最大的牛买耳塞。请计算被任何一只牛听见的最大音量。

 

问题名称:moooo

 

输入格式:

 

*第1行:一个单独的整数,N.

*第2..N+1行:第i+1行包含两个空格隔开的整数,h 和 v,这头牛站在第i个位置。

 

样例输入(moooo.in):

 

3

4 2

3 5

6 10

 

输入细节:

 

3头牛:第一头高度是4,鸣叫的音量是2,等等

 

输出格式:

 

*第一行:被任何一只牛听见的最大音量

 

样例输出:

 

 

输出细节:

 

第3只牛听到了第一只和第2只的叫声 2+5=7,尽管第三只牛音量是10,没人听见她。

 

【题目分析】

这题也是有两种解法,第一种是看每只牛能收到哪些牛的声音,第二种是看每只牛的声音能传到哪只牛。这里着重讲一下第二种。

第二种方法其实就是在两头加个高度很高的哨兵,然后每只牛进行一次check,找它左边比它高的第一只牛和右边比它高的第一只牛,把声音加在找到的牛上。

这种方法很简单,但由于数据量有点大,所以我们要采用优化,下面就讲一下单调队列的优化【test】2015.7.31测试解题报告(二) - 李kuandui - 神殇KD灬度阡陌

    如图,第一次1号通过1指向了比它高的哨兵,第二次2号通过2指向了比它高的1,第三次3号通过3指向了比它低的2,第四次3号指向了比它矮的1(其实这里应该把1画高),第五次3号指向了比它高的哨兵,后面大家无视吧!

经过一系列这样的做法后,如果n是一个很高的牛(比3号高)那么就会在搜索到3后直接指向哨兵,省了很多时间。

【例程】

#include<iostream>
#include<cstdio>
#include<cstring>

const int maxh=2000000001;

using namespace std;

int n,ans=0;

struct Tmoooo
{
int v,h,voice,next,next2;
};
Tmoooo cow[50002];

void listen(int k)
{
int i=cow[k].next;
while(cow[i].h<=cow[k].h)
i=cow[i].next;
cow[i].voice+=cow[k].v;
cow[k].next=i;
}
void listen2(int k)
{
int i=cow[k].next2;
while(cow[i].h<=cow[k].h)
i=cow[i].next2;
cow[i].voice+=cow[k].v;
cow[k].next2=i;
}

int main()
{
freopen("moooo.in","r",stdin);
freopen("moooo.out","w",stdout);

scanf("%d",&n);
memset(cow,0,sizeof(cow));
cow[0].h=maxh;cow[n+1].h=maxh;

for(int i=1;i<=n;++i)
{
scanf("%d%d",&cow[i].h,&cow[i].v);
cow[i].next=i-1;cow[i].next2=i+1;
}
for(int i=1;i<=n;++i)
listen(i);

for(int i=n;i>=1;--i)
listen2(i);

for(int i=1;i<=n;++i)
{
if(cow[i].voice>ans)
ans=cow[i].voice;
}
printf("%d\n",ans);
return 0;
}

七、discgolf

Problem XX: Disc Golf [RussCox, 2006]

奶牛们正在建立一个新的高尔夫课程.他们喜欢用一个关联B类似质数来标记他们的高尔夫洞,如果一个数在除完了所有B的因子后是质数,那么这个数就与B类似质数”, 1 不是质数,B的任何次方也不是

例如:

一些基数为2 类似质数:

       3,5, 6, 7, 10, 11, 12, 13, 14, 17, 19, 20

帮助那些牛,给出基数B (1 <= B <= 100) 和一个数字 N (1<= N <= 100), 计算出第N个以B为基数的类似质数

PROBLEMNAME: discgolf

 

INPUTFORMAT:

 

第一行,两个整数,用空格隔开: N B

 

SAMPLEINPUT (discgolf.in):

 

7 2

 

OUTPUTFORMAT:

 

一行: 一个整数, N个与B关联的类似质数

 

SAMPLEOUTPUT (discgolf.out):

 

12

 

OUTPUTDETAILS:

 

2关联的第七个类似整数 12  (题目中已说明)

 

  

【题目分析】

这道题目理解了不难,但问题是根本不理解啊……题目太逗比了,根本看不懂,最后在讨论下,分析出“类似质数”是指:设一个基数B,那么判断K是否是B的类似质数就是用K一直除以B(不能有余数),如果最后的数是质数,那么K就是B的类似质数。

编程很简单,需要注意的是要用if来判断是否是求1的类似质数,否则会死循环……

 

【例程】

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<cstring>

using namespace std;

bool s[100001];
int N,B,now=0;

int gcd(int a,int b)
{
if(b==0)return a;
return gcd(b,a%b);
}

int main()
{
freopen("discgolf.in","r",stdin);
freopen("discgolf.out","w",stdout);


memset(s,true,sizeof(s));
s[1]=false;
for(int i=4;i<=800;++i)
{
for(int j=2;j<=trunc(sqrt(i))+1;++j)
{
if(i%j==0)
{
s[i]=false;
break;
}
}
}

cin>>N>>B;
s[B]=false;

if(B==1)
{
for(int i=2;;++i)
{
if(s[i])
{
now++;
if(now==N)
{
cout<<i<<endl;
return 0;
}
}
}
}
else
for(int i=2;;++i)
{
int tmp=i;
while(tmp%B==0)
tmp/=B;
if(s[tmp])
{
now++;
//cout<<i<<" ";
if(now==N)
{
cout<<i<<endl;
return 0;
}
}
}

return 0;
}


八、noggle

ProblemXX: Noggle [Russ Cox, 2006]

 

奶牛们发明了一种新游戏叫Noggle

给你一本字典,里面有M(1 <= M <= 1000)个数,每个数的长度都是N(1 <= N <= 6)(没有前导零),要求你生成一个N*N的数字矩阵,使其每一横排,每一竖排,两斜排(分别从左上角和左下角开始)的组成的数字都在字典中,每个数可以重复出现。

PROBLEM NAME: noggle

 

INPUT FORMAT:

 

* Line 1: 两个整数:

 

* Lines 2..M+1: 每一行一个整数,表示长度为N的字典中的数

 

SAMPLE INPUT (file noggle.in):

 

2 8

15

16

17

67

56

75

76

32

 

INPUT DETAILS:

 

字典里有8个长度为2的整数数 2: 15, 16, 17, 67, 56, 75, 76, and 32.

 

OUTPUT FORMAT:

 

一个N*N的符合矩阵

SAMPLE OUTPUT (file noggle.out):

 

15

76

 

OUTPUT DETAILS:

 

横排 15 76.  竖排1756.  斜排是 16 75.

这些数都在字典中。

 【题目分析】

这题看起来好像很难啊!但经过仔细分析题目后,发现是要用深度搜索来做的。首先我们可以先随便拿出一个数放在左上到右下的斜线,然后拿一个数放在左下到右上的斜线(要判断能不能放)。

接着用深度搜索,一行一行放数,因为之前已经确定了两个斜线,所以每行就有两个数是可以确定的,然后扔合适的数进去,每行都填完就检查列是否存在字典中,如果不是就回溯继续。

当然斜线不一定合适,所以斜线也是要循环的

 

【例程】

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;

int n,m;
string num[1001];
int matrix[10][10];
int mo,di;
bool nin[1000000];
int row[10];
string st[10];

void dfs(int,int,int);
bool check();
void print();
int change(string);

int main()
{
freopen("noggle.in","r",stdin);
freopen("noggle.out","w",stdout);

memset(nin,false,sizeof(nin));
memset(matrix,-1,sizeof(matrix));
cin>>n>>m;
for(int i=0;i<m;++i)
{
cin>>num[i];
int _in=change(num[i]);
nin[_in]=true;
}
mo=n%2;di=n/2;


for(int i=0;i<m;++i)//循环左上到右下的斜线
{
for(int j=0;j<m;++j)//循环左下到右上的斜线
{
if( (mo==1 && num[j][di]!=num[i][di]) )
continue;

dfs(i,j,0);
//print();

}


}
return 0;
}

int change(string st)
{
int an=0;
for(int i=0;i<n;++i)
{
an*=10;
an+=st[i]-'0';
}
return an;
}

void dfs(int j,int k,int o)
{
if(o==n)
{
//exit(0);
if(check())
{
print();
exit(0);
}
return;
}

for(int i=0;i<m;++i)
{
if( (num[i][o]!=num[j][o]) || (num[i][n-o-1]!=num[k][n-o-1]) )
continue;

row[o]=i;


dfs(j,k,o+1);
}
}

bool check()
{
for(int i=0;i<n;++i)
{
st[i]=num[row[i]];
//cout<<st[i]<<"!"<<i<<endl;
}
for(int i=0;i<n;++i)
{
int an=0;
for(int j=0;j<n;++j)
{
an*=10;
an+=st[j][i]-'0';
}
//cout<<an<<endl;
if(!nin[an])
return false;
}
return true;
}

void print()
{
//cout<<endl;
for(int i=0;i<n;++i)
cout<<num[row[i]]<<endl;
}



九、counfr

PROBLEMNAME counfr

每年, FarmerJohn 喜欢去关注县展览会.展览会有N个货摊,(1<=n<=400) 而且每个货摊i会给一份特殊的奖品在一个特定的时间P(i),(0<=P(i)<=1,000,000,000) . Farmer John听说了这些,并想尽可能地收集多的奖品与牛一起分享.给出T(i,j),摊位i到达摊位j的时间,T(i,j)T(j,i)可能不相等,并且从摊位i到摊位j的时候不会经过中间点(即使那条路径较短)开始时Farmer John在摊位1,在时间点0;

Problem name counfr

输入:

 1:一个整数N

 2..1+N,i+1行包括一个整数p(i);

  2+N..1+N+N^2 ,每行包括一个整数T(I,j);

输出:

 最多能拿到多少个奖品

样例输入:

 4

13

9

19

3

0

10

20

3

4

0

11

2

1

15

0

12

5

5

13

0

样例解释:

4个摊位,摊位1发奖品的时间是时间13,摊位2发奖品的时间是9,摊位3发奖品的时间是19,摊位4发奖品的时间是3

样例输出:

3

样例解释:

Farmer John先走到摊位4,在时间3 到达,就在这个时候拿奖品,然后在去摊位2(始终直接走过去,不走中间点),在时间点8到达,然后等待1个单位的时间,拿到奖品.最后,他返回摊位1

在时间点13到达,然后收集他第三个奖品.


【题目分析】

这题看上去似乎和动态规划有几分相似,但仔细看却又没有动态规划的特点。所以说后来又想到了,它既然给出了到每个点的距离,就是可以用搜索来做的。John走到每个点的时间是不一定的,其已经得到的礼物数也不一定,所以可以用迭代法来解题。即类似于宽搜又有点不同。

其难点在于怎么处理自己走到自己这个可能导致死循环的节点。其实也很简单,我的程序中就是用一个if语句来写的。

 

【例程】

#include<iostream>
#include<cstdio>
using namespace std;

int n,ans=0;
int way[401][401];
int H,T,xx,timm,giff;

struct Tcount
{
int x,tim,gif;
};
Tcount d[1000000];

struct Tgift
{
int gift,time;
};
Tgift booth[401];

int main()
{
freopen("counfr.in","r",stdin);
freopen("counfr.out","w",stdout);

scanf("%d",&n);
for(int i=0;i<n;++i)
scanf("%d",&booth[i].time);

for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
scanf("%d",&way[i][j]);

H=0;T=0;
d[0].x=0;d[0].tim=0;d[0].gif=0;
while(H<=T)
{
xx=d[H].x;
timm=d[H].tim;
giff=d[H].gif;

if(ans<giff)
ans=giff;

for(int i=0;i<n;++i)
{
int ntime=timm+way[xx][i];


//cout<<ntime<<" "<<booth[i].time<<" "<<timm<<" "<<way[xx][i]<<endl;

if(ntime<=booth[i].time)
{
if(ntime==timm&&ntime==booth[i].time)
continue;

if(booth[i].gift>=giff+1)
continue;
++T;
d[T].gif=giff+1;
d[T].x=i;
d[T].tim=booth[i].time;
booth[i].gift=giff+1;

//cout<<ntime<<" "<<booth[i].time<<" "<<timm<<endl;
}
}
++H;
//cout<<H<<" "<<T<<endl;
}

printf("%d",ans);
return 0;
}


0 0