【选拔队员】解题报告

               Problem 1      选拔队员选拔队员 (seat.pas/c/cpp) 
                              选拔队员选拔队员 

背景背景 
背景背景 

  随着WZOI 的老一辈人员的离开,WZOI 的人数越来越少了。CJH 教练于是想选拔一些人 
进入团队。。。。。。 

问题问题描述描述 
问题问题描述描述 

  这一天,许多的学生齐聚在机房的门口,等待这CJH 教练的出现。。。 
  CJH  教练过了不久就来了,他看见那么多人来参加。虽然十分高兴,但是机房的位置十 
分有限,于是他要淘汰一部分人。 
  CJH 教练说:“各位同学,十分高兴你们能来到这个机房。但是机房内的电脑的数目十分 
有限,现在如果你们能答出下面这个问题,那么你们就能成为团队的一份子。注意听,问题 
是这样子的:‘机房内总共有N             (这个值CJH 教练会告诉你)个位置,排列成一条直线,从 
左往右编号为1 到N 。现在你们中的N 个人要坐到这N 个位置上去,问总共有多少种安排 
的方法。” 
  所有同学大呼太难了,于是CJH 教练决定简化问题:从同学中选出若干个男生和若干多 
个女生 (即男女生的数目随便定即男女生的数目随便定)安排到机房内的N  个位置上去,要求任意两位女生不能 
        即男女生的数目随便定即男女生的数目随便定 
相邻 (即任意两个女生之间必须有至少一个男生即任意两个女生之间必须有至少一个男生),问总共有多少种方法,你们姑且可以认 
      即任意两个女生之间必须有至少一个男生即任意两个女生之间必须有至少一个男生 
为所有男生是等价所有男生是等价的,所有女生是等价所有女生是等价的。 
  所有男生是等价所有男生是等价  所有女生是等价所有女生是等价 
  CJH 为了再次降低难度,他只要求你将方案种数mod M 即可。 
  当然,由于这个问题简化之后太简单了,于是CJH 会用不同的N 提问多次,这样他就可 
以淘汰许多没能力的人了。 
  为了能顺利进入WZOI,许多同学向WZOI 的朋友求救。显然你就是他们的救星了,现在 
将CJH 教练的问题告诉你,要求你输出正确答案。 

输入格式输入格式 
输入格式输入格式 

  输入数据第一行包含两个整数T,M ,分别表示测试数据的组数和要将结果mod M; 
  接下来T 行,每行有一个整数N,表示机房里总共有N 个位置。 

输出格式输出格式 
输出格式输出格式 

  输出数据共T 行,每行一个整数S,表示总的方案数mod M 之后的那个数。 

样例输入输出样例输入输出 
样例输入输出样例输入输出 

Sample #1 
seat.in                                 seat.out 
2 3                                     2 
1                                       2 
3 

Sample #2 
seat.in                                 seat.out 
2 5                                     4 
9                                       3 
5 

数据规模数据规模 
数据规模数据规模 

对于10%的数据,N≤100,T≤10; 
对于30%的数据,N≤1000,T≤100; 
对于50%的数据,N≤1000000,T≤1000; 
对于100%的数据,N≤1000000000,T≤10000; 
对于100%的数据,M≤10。 

时间限制时间限制 
时间限制时间限制 
1s 

这道题跟前两天那一道如出一辙,不过我还是花了很长时间才看出来模型。

这是一个斐波拉契数列。可以通过三种方式证明出来:

1、我的方法。考虑递推,f[i][0]表示i位置处为女时前i个位置方案总数。f[i][1]表示i位置为男时前i个位置的方案总数。

则f[i][0]=f[i-1][1]。f[i][1]=f[i-1][0]+f[i-1][1]。不过到这时候我还没有看出来,硬是试了几个数据之后才看出来。

2、孙川的方法。同样是递推,f[i]表示前i个位置,不管i是男还是女的方案总数。

分类讨论:若i位置是男的,则f[i]=f[i-1](i-1任意放男女)若i位置是女的,则f[i] =f[i-2](i-1位置只能放男的)

根据加法原理:f[i]=f[i-1]+f[i-2]。推出来了。


具体见前两天Number那道题。


#include 

long a[3][3];
long c[3][3];
long b[3][3];
long t[3][3];

void multi(long p[3][3],long q[3][3],long n)
{
	for (long i=1;i<3;i++)
		for (long j=1;j<3;j++)
			t[i][j]=(p[i][1]*q[1][j]%n+p[i][2]*q[2][j]%n)%n;
	for (long i=1;i<3;i++)
		for (long j=1;j<3;j++)
			p[i][j]=t[i][j];
}

void set(long p[3][3],long q[3][3])
{
	for (long i=1;i<3;i++)
		for (long j=1;j<3;j++)
			p[i][j]=q[i][j];
}

long kysumi(long m,long n)
{
	set(b,a);
	while (m>0)
	{
		if (m&1==1) multi(c,a,n);
		multi(a,a,n);
		m>>=1;
	}
}

long n;long m;long tt;

int main()
{
	freopen("seat.in","r",stdin);
	freopen("seat.out","w",stdout);
	scanf("%ld%ld%ld",&tt,&m,&n);
	for (long i=1;i


循环节的方法。比较神奇(标程),还没看懂

program seat;
const
T:array[2..10] of longint=(3,8,6,20,24,16,12,24,60);
var
f:array[1..61] of longint;
n,i,j,tot,m:Longint;

procedure openf;
begin
  assign(input,'seat.in');reset(input);
  assign(output,'seat.out');rewrite(output);
end;

procedure closef;
begin
  close(input);close(output);
end;

procedure main;
begin
  readln(tot,m);
  for i:=1 to tot do
  begin
    readln(n);
    f[1]:=2 mod m;  f[2]:=3 mod m;
    for j:=3 to T[m] do f[j]:=(f[j-1]+f[j-2]) mod m;
    writeln(f[(n-1) mod T[m]+1]);
  end;
end;

begin
  openf;
  main;
  closef;
end.


你可能感兴趣的:(NOIP)