题目链接:http://codeforces.com/problemset/problem/459/C
题目意思:有 n 个 students,k 辆 buses。问是否能对 n 个students安排每一天搭乘的buses,使得没有两个student 在 d 天搭乘相同的buses,buses 的 容量没有限制,也就是它可以搭无限多的人。
做这条题的时候,我是得不出无解的条件的,看了 tutorial 之后一下子明白了,就是 k^d > n。很容易理解,因为每一天某个student可以选择的 buses 都有 k 种选择嘛~~~而且又因为要输出 d 行 n 列 那么多的数,所以 k ^ d > n 表示至少有两列数会使得某两个student 成为 close friend!
知道这个之后就是如何构造答案了,其实就是所有排列情况,不过我是不会做啦~~~看了作者的代码自己重新写,非常惊叹他的智慧呀~~~
拿这组数据来说吧,20 3 5
结合代码中注释为transfer
ans[i][j] = ans[i-1][j]; 表示从左边那一列复制到下一列,那么为了不使得两个student成为close friend 就势必要使得他们有一点不同,这时就用到代码中的 update 操作了
ans[i][j] = (ans[i][j] + 1) % k;
这行代码用得相当巧妙,由于循环是从 d-1 ——> 0 的,也就是对于当前处理的那一列,从下往上更改(如果遇到 % k == 0 的情况),否则(% k != 0)就在上一列的对应行 + 1。
最后还有一个地方,在判断 k^d > n 的时候,如果可以提早发现有answer,要提早 break 出来,从 test7 可以知道!考虑数据范围:1 ≤ n, d ≤ 1000; 1 ≤ k ≤ 10^9 ,因为乘的时候有可能很大,超出long long 范围 !!
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 using namespace std; 6 7 typedef long long LL; 8 const int maxn = 1000 + 5; 9 10 int ans[maxn][maxn]; 11 12 int main() 13 { 14 #ifndef ONLINE_JUDGE 15 freopen("in.txt", "r", stdin); 16 #endif 17 18 int n, k, d; 19 while (scanf("%d%d%d", &n, &k, &d) != EOF) 20 { 21 bool flag = false; 22 LL product = 1; 23 for (int i = 0; i < d; i++) 24 { 25 product *= (LL)k; // one select has k choice 26 if (product >= n) // mean has answer 27 { 28 flag = true; 29 break; 30 } 31 } 32 33 if (!flag) // repeat, no answer 34 printf("-1 "); 35 else // construct the answer 36 { 37 memset(ans, 0, sizeof(ans)); 38 for (int i = 1; i < n; i++) 39 { 40 for (int j = 0; j < d; j++) 41 { 42 ans[i][j] = ans[i-1][j]; // right transfer 43 } 44 45 for (int j = d-1; j >= 0; j--) // update 46 { 47 ans[i][j] = (ans[i][j] + 1) % k; 48 if (ans[i][j]) 49 break; 50 } 51 } 52 for (int i = 0; i < d; i++) 53 { 54 for (int j = 0; j < n; j++) 55 printf("%d ", ans[j][i]+1); 56 printf(" "); 57 } 58 } 59 } 60 return 0; 61 }