NOIP 2001 数的划分 解题报告
我直接模拟的,第i个数字必定大于或等于第i-1个数字,我是按照这种思想模拟的,那么每种情况就只会考虑一次,然后需要一个重大剪枝:
当i=k-1的时候,就不去枚举了,直接得到答案,用n-sum,我还有一个小剪枝,因为我的第i个数一定大于或等于第i-1个数,那么如果第i个数加到第k个数就大于n的话,就没必要继续枚举了。
2011年08月29日:
刚刚发现,上次的代码有问题,数据太弱,所以过了,但是2 15 151,2 151 15的答案不一样,思索了好久,最后想出了正确的算法。
就是枚举两个字符串,如果相同就继续枚举,不同就继续枚举。。。。。(没听懂的看下面第二段代码,第一段只能AC不是正确。。)
代码:
#include <stdio.h> #include <stdlib.h> int n, k; int ans; void srch(int deep, int now, int sum) { int i; if(deep == k){ if(sum == n){ ans++; } return; } if(deep == k - 1){ srch(deep + 1, n - sum, n); return; } for(i = now; i <= n - sum; i++){ if(sum + (k - deep) * i > n){ return; } srch(deep + 1, i, sum + i); } } int main(int argc, char **argv) { int i; scanf("%d%d", &n, &k); for(i = 1; i <= n; i++){ if(k * i <= n){ srch(1, i, i); } } printf("%d\n", ans); return 0; }
#include <stdio.h> #include <string.h> #include <stdlib.h> char str[20][10001]; int gcd(int a, int b) { int t; while(b != 0){ t = b; b = a % b; a = t; } return a; } int com(const void *a, const void *b) { char *s1 = (char *)a, *s2 = (char *)b; int t, s; int l1 = strlen(s1), l2 = strlen(s2); s = l1 / gcd(l1, l2) * l2; for(t = 0; t < s; t++){ if(s1[t % l1] != s2[t % l2]){ return s2[t % l2] - s1[t % l1]; } } return 0; } int main(int argc, char **argv) { int i; int n; scanf("%d", &n); for(i = 0; i < n; i++){ scanf("%s", str[i]); } qsort(str, n, sizeof(char) * 10001, com); for(i = 0; i < n; i++){ printf("%s", str[i]); } printf("\n"); return 0; }