网教19. 微微一笑呵呵呵

来源:互联网 发布:安卓版iphone查找软件 编辑:程序博客网 时间:2024/04/28 21:04

题目描述

       众所周知,计算机系搬到中关村校区的学姐们贼好看了,这就导致每天看学姐的人超多,进而导致每天食堂打饭的人数暴涨,所以一到饭点食堂就会出现一个超长的打饭队列,考虑到三个女人一台戏以及一个男生前后都是女生会让他害羞的情况,我们称没有这两种情况的打饭队列为呵呵列。有一天数学系的一个学长去食堂吃饭,饭后无聊突然想知道n个人能够形成多少呵呵列,机智的他O(瞬)就知道了结果,还将结果模了个666告诉你,而你是计算机系的,能不懂嘛,快拿出电脑解决这个问题吧

输入

第一行一整数T表示用例组数,每组用例占一行输入一个整数n表示打饭的人数

输出

对于每组用例,输出一个整数占一行表示呵呵列的数量,结果模666

数据范围

1<=T<=1000,n<=1000000

样例输入

1

3

样例输出

6

样例解释

男男男 男男女 女男男 女女男 男女男 男女女

题解:

解法一:煮夫教给我的简单解法

状态转移方程是dp[i]=dp[i-1]+dp[i-3]+dp[i-4]。因为dp[i]的来源就是dp[i-1]加个男 dp[i-3]加个男男女 dp[i-4]加个男男女女。

首先,易知给i-1加男肯定可以加,所以有一个dp[i-1],如果最后一个是女的话,最后三个只能是男女女和男男女。如果是男男女,那直接加dp[i-3]即可(dp[i-2]要减去一部分,减去之后就是dp[i-3],因为dp[i-3]的排列不影响男男女,所以dp[i-3]不多也不少);如果是男女女,那么倒数第四个必须是男男女女,根据上一种推理方法,得知dp[i-4]即是。所以dp[i]=dp[i-1]+dp[i-3]+dp[i-4]


解法二:自己推了一个小时推出来的

状态转移方程是dp[i]=2*dp[i-1]-2*dp[i-5]-dp[i-6](后被煮夫证明和上面式子是一样的)

首先我一个一个算得出dp[1]=2,dp[2]=4,dp[3]=6,dp[4]=9,dp[5]=15,dp[6]=25,在算的过程中我发现凡是男都能加,是女就要考虑一下,所以我就开始找不符合情况的,找出不符合的公式之后直接用2倍dp[i-1]减即可。

最后一个不能加女的,dp[i-1]的结尾必是女男/女女。

如果dp[i-1]的结尾可以是女女的话那么dp[i-3]结尾两个不能是女男、男女、女女,即只能是男男。如果dp[i-3]的结尾是男男,那么数量就和dp[i-5]一样,理由跟解法一相同。

如果dp[i-1]的结尾可以是女男,那么dp[i-3]的结尾只能是男男、男女。男男和上面一样,数量是dp[i-5],结尾是男女的话,dp[i-5]的结尾不能是女,即只有dp[i-5]结尾是男的部分。而结尾是男的部分就等于dp[i-6](因为男是可以随便加,只有男生的部分就是减一),所以这一部分是dp[i-5]+dp[i-6]

所以要减去的部分就是2*dp[i-5]+dp[i-6],最终就是dp[i]=2*dp[i-1]-2*dp[i-5]-dp[i-6]。

然而这个公式要注意的一点是,因为结果模了666,所以dp[i-1]是很有可能比2*dp[i-5]+dp[i-6]小的,所以在得结果之前先判断一下有没有变成负数。如果变负的话就加一个666.

AC代码:

#include<stdio.h>  #include<string.h>  int max(int a, int b)  {      return a > b ? a : b;  }  int dp[1000005];  int main()  {  //  freopen("F:in.txt", "r", stdin);  //  freopen("F:out.txt", "w", stdout);      dp[0] = 1;      dp[1] = 2;      dp[2] = 4;      dp[3] = 6;      dp[4] = 9;      dp[5] = 15;      dp[6] = 25;      for (int i = 6; i <= 1000001; i++)      {          int a, b, c;          a = dp[i];          b = dp[i - 4];          c = dp[i - 5];          while (a * 2 - 2 * b - c < 0)              a += 666;          dp[i + 1] = (2 * a - 2 * b - c)%666;      }      int t;      scanf("%d", &t);      while (t--)      {          int a;          scanf("%d", &a);          printf("%d\n", dp[a]%666);      }      return 0;  }  

解法一公式的代码应该不需要了吧……

0 0
原创粉丝点击