2016 0510 百度之星测试赛
大搬家
Problem Description
近期B厂组织了一次大搬家,所有人都要按照指示换到指定的座位上。指示的内容是坐在位置ii上的人要搬到位置jj上。现在B厂有NN个人,一对一到NN个位置上。搬家之后也是一一对应的,改变的只有位次。
在第一次搬家后,度度熊由于疏忽,又要求大家按照原指示进行了一次搬家。于是,机智的它想到:再按这个指示搬一次家不就可以恢复第一次搬家的样子了。于是,B厂史无前例的进行了连续三次搬家。
虽然我们都知道度度熊的“机智”常常令人堪忧,但是不可思议的是,这回真的应验了。第三次搬家后的结果和第一次的结果完全相同。
那么,有多少种指示会让这种事情发生呢?如果两种指示中至少有一个人的目标位置不同,就认为这两种指示是不相同的。
Input
第一行一个整数TT,表示T组数据。
每组数据包含一个整数N(1 \leq N \leq 1 000 000)N(1≤N≤1000000)。
Output
对于每组数据,先输出一行 Case #i: 然后输出结果,对10000000071000000007取模。
Sample Input
2 1 3
Sample Output
Case #1: 1 Case #2: 4 思路:直接想的可能是怎么才能搬家三次的结果和搬家一次的结果相同,但是实际上可以简化为搬家两次的结果和搬家之前相同。要出现这样的情况,那第一次搬家i-j必须满足i==j或者i-j&&j-i(i!=j).当给定为N个人搬家时有ans[N]种满足条件的可能,假设第一个人是1-1,也就是位置不变,那么剩下的人可能的情况就是ans[N-1]种。当第一个人是1-j(j!=1)时,那么必定有j-1。所以还剩下N-2个人,所以就是ans[N-2],又因为此时j有N-1(2-N)种可能。可得出dp公式 ans[N] = ans[N-1] + (N-1)*ans[N-2];初始值ans[1] = 1;ans[2] = 2;利用递归或者dp即可解决,但是递归会超时,dp才是正道。
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); while (sc.hasNext()) { int t = sc.nextInt(); long[] ans = new long[1000001]; long mod = 1000000007l; ans[1] = 1; ans[2] = 2; int m = 3; for (int i = 1; i <= t; i++) { int n = sc.nextInt(); while (m <= n) { ans[m] = mod(ans[m-1] + (m-1)*ans[m-2]); //用mod函数会稍微快点,但是不影响结果 m++; } System.out.println("Case #"+i+":"); System.out.println(ans[n]); // System.out.println("Case #"+i+":\n"+ans[n]);//这种形式会报格式错误 } } } public static long mod(long i) { return i%1000000007; } } /**TLE 递归影响时间,改成dp public static int find(int n) { if (n == 1) return 1; if (n == 2) return 2; else return mod(find(n-1))+mod((n-1)*find(n-2)); } */
代码中的斜体部分应该放到for循环外,这样就可以保存ans[]数组的结果,在下一个测试用例时就可以直接利用了,如果放在for循环内,就会超时。
ps: 最后的打印换成代码中的另一种形式就会格式错误Presentation Error,不知道为什么。
时间: 2024-10-11 13:13:23