数学 |
组合数学,polya定理,置换群 |
+poj2369,poj1026,poj3270,poj2409,poj1286 |
高斯消元法 |
poj2947, poj2065, poj1487,poj1166,poj1222 |
|
概率问题 |
poj3071,poj3440 |
|
GCD、扩展的欧几里德 |
poj1061,(发现一道好题)whu 1338, poj2891,poj3101, poj2115 |
|
计算方法(矩阵、三分等) |
poj2976,poj3150, poj3070, poj3301 |
|
随机化算法 |
poj3318, poj2454 |
|
杂题 |
poj1870,poj3296,poj3286,poj1095 |
组合数学,polya定理,置换群
poj 2369
理解置换的概念,理解合并过程。
题目是求一个置换f^k使得得到的置换是一个恒等置换。
思路是求每个独立子置换的循环节长度,然后求所有长度的最小公倍数。。
poj 1026
题意:给一个序列,a0,a1,a2...an-1。再给一个字符串,s0, s1, s2,...,sn-1(长度不够的用空格补上)。s[i]在a[i]位置输出得到一个新的串,重复这个过程k次,求最后的串。
思路:开始思路是先求最少m步到达恒等置换。这样算是一次循环,然后模拟剩下的k%m次可惜这样写TLE。。
后来看到网上的思路。说是对每个ai找循环节,算出其对应的位置。这个黑书248页有讲解。。。
因为读数据时把格式弄错了。。。然后偶wa了仨小时。。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <map> #include <set> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) typedef long long LL; using namespace std; const int N = 210; char str[N]; char ans[N]; int a[N]; int vis[N]; int n, k; void solve() { int i, tmp; CL(vis, 0); for(i = 0; i < n; ++i) { if(!vis[a[i]]) { tmp = a[i]; vis[a[i]] ++; while(tmp != i) { vis[a[i]] ++; tmp = a[tmp]; } } } int pos; for(i = 0; i < n; ++i) { tmp = k%vis[a[i]]; pos = a[i]; while(tmp --) pos = a[pos]; ans[pos] = str[i]; } } int main() { //freopen("data.in", "r", stdin); int i, l, x; while(scanf("%d", &n), n) { CL(a, 0); for(i = 0; i < n; ++i) { scanf("%d", &x); a[i] = x-1; } while(scanf("%d", &k), k) { getchar(); gets(str); k--; l = strlen(str); if(l < n) { for(i = l; i < n; ++i) str[i] = ' '; } solve(); for(i = 0; i < n; ++i) { printf("%c", ans[i]); } putchar('\n'); } putchar('\n'); } return 0; }
poj 3270
思路黑书上说的很详细,对每一个循环有两种移动方案。1、对一个循环,让在循环里的最小值ti与其他值各交换一次。2、在循环外找一个比ti更小的m,用m替代ti与循环里的其他值各交换一次。取两种方案最小。
话说,这题的grumpniss值与N半毛钱的关系没有,所以置换要重新构造。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <map> #include <set> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) typedef long long LL; using namespace std; const int N = 100010; int a[N], b[N], p[N]; bool vis[N]; int sum; int m, n; int solve() { int res = 0; int i, j, x, pos, ti; CL(vis, 0); for(j = 1; j <= n; ++j) { i = p[j]; if(!vis[a[i]]) { x = 1; pos = a[i]; vis[a[i]] = true; ti = Min(a[i], i); while(pos != i) { x++; vis[a[pos]] = true; pos = a[pos]; ti = Min(ti, pos); } res += Min((x-2)*ti, (x + 1)*m + ti); } } return res; } int main() { //freopen("data.in", "r", stdin); scanf("%d", &n); m = ~0u>>2; sum = 0; for(int i = 1; i <= n; ++i) { scanf("%d", &b[i]); m = Min(m, b[i]); p[i] = b[i]; sum += b[i]; } sort(p + 1, p + n + 1); for(int i = 1; i <= n; ++i) { a[p[i]] = b[i]; } int res = solve(); printf("%d\n", sum + res); return 0; }
poj 2409
题意,给一个环,上边有s个珠子,编号为1-s,有c种颜色,求可以染出多少种不同的环;
思路:不得不说polya计数定理。假设有n种置换,每种置换含有ni个循环,则ans = sum(Pow(c, ni))/n;
这里有旋转和翻转两种情况,共s*2种置换
旋转:
相当于每次循环右移i个数,得到的循环数为gcd(s, i),送有s种;
翻转:
当s为奇数:以一个珠子和一条边的中心为轴翻转,共有s种置换,每种置换得到的循环数为[s/2] + 1;
当s为偶数:1、以两个珠子为轴翻转,共s/2种置换,每种置换得到循环s/2个;
2、以两条对称边的中心为轴翻转,共s/2种置换,每种置换得到(s-2)/2 + 2个循环。
这样结果就显而易见了;
poj 1286 :
2409的简化版
高斯消元法
好蛋疼的高斯消元。。。线代学的都忘了。。。过程跟代码实现上,矩阵快把我搞疯了。
poj 2947
高斯消元模板。蛋疼的看了一下午,各种wa,re。。。偶终于AC咧!!!
贴模板:
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <map> #include <set> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) typedef long long LL; using namespace std; const int N = 500; int mat[N][N]; int ans[N]; int n, m; string s1, s2; string st[7] = {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"}; int get_num(string s) { for(int i = 0; i < 7; ++i) { if(s == st[i]) return i + 1; } return 0; } inline int gcd(int a, int b) { int t; while(b != 0) { t = a%b; a = b; b = t; } return a; } inline int lcm(int a, int b) { return a/gcd(a, b)*b; } inline int iabs(int x) { return x < 0 ? -x : x; } int solve() { int k, col, i, j, tmp; int max_k, L, ta, tb; for(k = col = 0; k < m && col < n; ++k, ++col) { max_k = k; for(i = k + 1; i < m; ++i) { if(iabs(mat[i][col]) > iabs(mat[k][col])) max_k = i; } if(max_k != k) { for(i = col; i <= n; ++i) swap(mat[k][i], mat[max_k][i]); } if(mat[k][col] == 0) {--k; continue;} for(i = k + 1; i < m; ++i) { if(mat[i][col]) { L = lcm(iabs(mat[i][col]), iabs(mat[k][col])); ta = L/iabs(mat[i][col]); tb = L/iabs(mat[k][col]); if(mat[i][col]*mat[k][col] < 0) tb *= -1; for(j = col; j <= n; ++j) { mat[i][j] = ((mat[i][j]*ta - mat[k][j]*tb)%7 + 7)%7; } } } } for(i = k; i < m; ++i) if(mat[i][col] != 0) return -1; if(k < n) return 0; for(i = n - 1; i >= 0; --i) { tmp = mat[i][n]; for(j = i + 1; j < n; ++j) { tmp = ((tmp - mat[i][j]*ans[j])%7 + 7)%7; } while(tmp % mat[i][i] != 0) tmp += 7; ans[i] = tmp/mat[i][i]; while(ans[i] < 3) ans[i] += 7; while(ans[i] > 9) ans[i] -= 7; } return 1; } int main() { //freopen("data.in", "r", stdin); int i, k; int a, b, d; int x, flag; while(~scanf("%d%d", &n, &m)) { if(n + m == 0) break; CL(mat, 0); CL(ans, 0); for(i = 0; i < m; ++i) { cin >> k >> s1 >> s2; a = get_num(s1); b = get_num(s2); d = ((b - a + 1)%7 + 7)%7; while(k--) { scanf("%d", &x); mat[i][x-1]++; mat[i][x-1] %= 7; } mat[i][n] = d; } flag = solve(); if(flag == -1) puts("Inconsistent data."); else if(flag == 0) puts("Multiple solutions."); else { for(i = 0; i < n-1; ++i) { printf("%d ", ans[i]); } printf("%d\n", ans[n-1]); } } return 0; }
poj 2065
题意:f (k) = ∑0<=i<=n-1aiki (mod p);给出p和n
构成矩阵
(a0*k^0 + a1*k^1 + a2*k^2.... )%p = (str[i] - 'a' + 1)%p (当然,str[i] = '*'的时候特殊)
解这个矩阵a0, a1, a2...
貌似有唯一解
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <map> #include <set> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) typedef long long LL; using namespace std; const int N = 110; LL mat[N][N]; LL ans[N]; char str[N]; int n, m, p; inline int iabs(LL x) { return x < 0 ? -x : x; } inline LL gcd(LL a, LL b) { LL t; while(b) { t = a%b; a = b; b = t; } return a; } inline LL lcm(LL a, LL b) { return a/gcd(a, b) * b; } inline LL Pow(LL k, int j) { LL res = 1; while(j--) { res = (res*k)%p; } return res%p; } int solve() { int k, col, i, j; int max_k; LL L, ta, tb, tmp; for(k = col = 0; k < n && col < n; ++k, ++col) { max_k = k; for(i = k + 1; i < n; ++i) { if(iabs(mat[i][col]) > iabs(mat[k][col])) max_k = i; } if(max_k != k) { for(i = col; i <= n; ++i) swap(mat[i][j], mat[k][j]); } if(mat[k][col] == 0) {--k; continue;} for(i = k + 1; i < n; ++i) { if(mat[i][col]) { L = lcm(iabs(mat[i][col]), iabs(mat[k][col])); ta = L/iabs(mat[i][col]); tb = L/iabs(mat[k][col]); if(mat[i][col]*mat[k][col] < 0) tb = -tb; for(j = col; j <= n; ++j) { mat[i][j] = (mat[i][j]*ta - mat[k][j]*tb)%p; } } } } /*for(i = 0; i < n; ++i) { for(j = 0; j < n; ++j) printf("%-3d ", mat[i][j]); printf("%-3d\n", mat[i][j]); }*/ for(i = k; i < n; ++i) { if(mat[k][col] != 0) return -1; } if(k < n) return -2; for(i = n-1; i >= 0; --i) { tmp = mat[i][n]; for(j = i + 1; j < n; ++j) { tmp -= mat[i][j]*ans[j]; } while(tmp % mat[i][i] != 0) tmp += p; ans[i] = tmp/mat[i][i]; ans[i] = (ans[i]%p + p)%p; } return 1; } int main() { //freopen("data.in", "r", stdin); int t, i, j, k; scanf("%d", &t); while(t--) { CL(mat, 0); CL(ans, 0); scanf("%d%s", &p, str); n = strlen(str); for(i = 0; i < n; ++i) { k = i + 1; for(j = 0; j < n; ++j) { mat[i][j] = Pow(k, j); } if(str[i] == '*') mat[i][n] = 0; else mat[i][n] = str[i] - 'a' + 1; } solve(); for(i = 0; i < n; ++i) { if(i == n-1) printf("%lld\n", ans[i]); else printf("%lld ", ans[i]); } } return 0; }
poj 1116
高斯消元不会,直接dfs爆搞的。
从第1种移动方案枚举到第9种,每种可以用0, 1, 2, 3次,cnt[i]记录第i种方案用了多少次。
poj 1222
错了一下午。。老是不出结果。。。郁闷!建数学模型时很巧妙,都怪我数学不好 T_T。发现网上各种解题报告如出一则。
只有这个把证明说清楚了。Orz
概率问题
poj 3071
想不明白,这种问题跟概率有什么关系?无非就是换了个环境,归根结底还是dp。。。不知到这样归类有什么寓意。
看得discuss,f[i][j]表示第i论j号胜出的概率
f[i][j] = f[i-1][j]*(f[i-1][x]*p[j][x] + f[i-1][x + 1]*p[j][x+1] + ... + f[i-1][x + (1<<(i-1))-1]*p[j][x+ (1<<(i-1))-1]);
其中x有一个很让人蛋疼的公式!!x = (j>>(i-1)^1)<<(i-1);我也不知到怎么证明的!!!
poj 3440
算是这两天做题以来过得比较顺利的一道题。因为写成pi = acos(-1), CE了一次,其他就没什么了。按面积求概率,画画图推公式就ok了。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) typedef long long LL; using namespace std; const double pi = acos(-1.0); int main() { //freopen("data.in", "r", stdin); int T, cas = 0; double n, m, t, c, r; double s1, s2, s3, s4, sum; cin >> T; while(T--) { scanf("%lf%lf%lf%lf", &n, &m, &t, &c); sum = n*m*t*t; r = c/2; if(m != 1 && n != 1) { s1 = (t-r)*(t-r)*4 + (t-2*r)*(t-r)*(2*(m-2)+2*(n-2)) + (m-2)*(n-2)*(t-2*r)*(t-2*r); //s2 = (t-r)*(r+r)*(2*(n-1) + 2*(m-1)) + (t-r-r)*(r+r)*(m-2)*(n-2); s3 = (n-1)*(m-1)*(4*r*r - pi*r*r); s4 = (n-1)*(m-1)*pi*r*r; s2 = sum - s1 - s3 - s4; } else if(m == 1 && n != 1) { s1 = (t-r)*t*2 + (t-r-r)*t*(n-2); s2 = t*2*r*(n-1); s3 = 0; s4 = 0; } else if(n == 1 && m != 1) { s1 = (t-r)*t*2 + (t-r-r)*t*(m-2); s2 = t*2*r*(m-1); s3 = s4 = 0; } else { s1 = sum; s2 = 0; s3 = 0; s4 = 0; } printf("Case %d:\n", ++cas); printf("Probability of covering 1 tile = %.4f%%\n", s1/sum*100); printf("Probability of covering 2 tiles = %.4f%%\n", s2/sum*100); printf("Probability of covering 3 tiles = %.4f%%\n", s3/sum*100); printf("Probability of covering 4 tiles = %.4f%%\n\n", s4/sum*100); } return 0; }
whu 1338
详见: http://www.cnblogs.com/vongang/archive/2012/06/13/2548121.html
poj 2891
详见:http://www.cnblogs.com/vongang/archive/2012/06/16/2551644.html
poj 2115
貌似以前做过,很简单的一道题,不过注意移位的时候 1LL<<k
a + c*x = b (mod 2^k) 变形得
c*x = (b-a) (mod 2^k);
然后扩展欧几里德;
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) typedef long long LL; using namespace std; LL ext_gcd(LL a, LL b, LL& x, LL& y) { if(b == 0) { x = 1; y = 0; return a; } LL p = ext_gcd(b, a%b, x, y); LL tmp = x; x = y; y = tmp - (a/b)*y; return p; } int main() { //freopen("data.in", "r", stdin); LL a, b, c, k; LL x, y; while(~scanf("%lld%lld%lld%lld", &a, &b, &c, &k)) { if(!a && !b && !c && !k) break; LL n = 1LL<<k; b = ((b - a)%n + n)%n; LL d = ext_gcd(c, n, x, y); if(b%d) {puts("FOREVER"); continue;} n /= d; LL e = (x*(b/d)%n + n)%n; printf("%lld\n", e); } return 0; }
计算方法(矩阵、三分等)
poj 2976
官方题解:
Drop ---- This problem was intended to be the hardest problem in the set, and indeed, nobody solved it. When choosing to drop tests, there is a trade-off between tests with very low percentage scores and tests with mediocre percentage scores but with a large number of questions. Which one of these is better can depend on the other tests you are keeping. Figuring out how to balance these requirements is the heart of this problem. The first thing you have to realize is that a simple greedy algorithm is not going to be correct. For example, it seems reasonable to drop tests one at a time, always choosing to drop the test that will improve your cumulative average by as much as possible. However, it turns out this is wrong. For example, consider dropping 2 tests from a group of 100/100, 14/50, 14/50, 100/200, and 100/200. The greedy approach would first drop a 14/50 test and then a 100/200 test to get a score of 214/350 = 61%, but the optimal strategy is to drop both 100/200 tests for a score of 128/200 = 64%. If you have done a lot of other programming competitions, you might also think of the dynamic programming approach (see the stones write-up). By tracking the number of questions and the number of tests, you can use this to solve the problem in (number of questions)*(number of tests) time. Unfortunately, the maximum number of questions over all the tests is a trillion, so that is no good either. What do you do then? It turns out that the problem can be solved with a binary search. We ask the following question: "Can you drop k tests to make your cumulative average at least x?". It turns out that fixing x makes the problem substantially easier because this is enough to determine which tests are better than others. If we fix x, we need to choose tests so that (sum a_i) / (sum b_i) >= x <=> sum a_i >= sum (x*b_i) <=> sum (a_i - x*b_i) >= 0. Thus, we compute c_i = a_i - x*b_i for each i. We now need to drop k of those values so that their sum is at least 0. This is a much easier problem! Just sort the c_i's and drop the k smallest values. This reduces everything to a standard binary search problem. For each x, we can test whether we can get an average of at least x, and we need to find the maximum average that can be made. C++ code is shown bleow. double lb = 0, ub = 1; for (i = 0; i < 100; i++) { double x = (lb+ub)/2; for (j = 0; j < tests; j++) scores[j] = num[j] - x*den[j]; sort(scores, scores+tests); double total = 0; for (j = k; j < tests; j++) total += scores[j]; if (total >= 0) lb = x; else ub = x; } cout << int(100*lb + 0.5) << endl;
poj 3150
题意:给一个环,没进行一次d-step就是将环上和b[i]左右相邻距离不超过d的几个数求和(包括它自身),然后模m,得到一个新的b[i]。求k个d-step以后的环是个什么样的。
分析:比如a[] = {1 2 2 1 2}当d等于1时,得到的新b[]为:
(a0 + a1 + a4), (a1 + a0 + a2), (a2 + a1 + a3), (a3 + a2 + a4), (a4 + a3 + a0)
换成矩阵相乘的形式应该是这样:
c[][] = {
1 1 0 0 1
1 1 1 0 0
0 1 1 1 0
0 0 1 1 1
1 0 0 1 1
}
b[]*c[][]得到k等于1的解。
到这里很显然就是矩阵乘法问题了。不过。。。这里n = 500,如果用普通的矩阵快速幂的话复杂度为O(n*n*n*logk);
这里还可以优化,观察c[][]矩阵可以发现c[0][]中所有的元素循环右移一位可以得到c[1][]的值,这样在做矩阵乘法的时候就好做多了,可以将O(n^3)降到O(n^2);
看别人的解题报告没看懂。。。最后还是自己推的,T_T 矩阵相乘过程如下:
void mul(LL a[], LL b[]) { int i, j, x; CL(c, 0); REP(i, n) { c[i] = 0; x = (n - i)%n; REP(j, n) { c[i] += a[x]*b[j]; x = (x + 1)%n; } } REP(i, n) b[i] = c[i]%m; }
然后就是矩阵的k次幂,参考传统方法里的矩阵快速幂方法。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) typedef long long LL; const double eps = 1e-8; using namespace std; const int N = 1024; LL c[N]; int n, m, k, d; void mul(LL b[], LL a[]) { int i, j, x; CL(c, 0); REP(i, n) { c[i] = 0; x = (n - i)%n; REP(j, n) { c[i] += a[x]*b[j]; x = (x + 1)%n; } } REP(i, n) b[i] = c[i]%m; } int main() { freopen("data.in", "r", stdin); LL b[N], a[N]; int i; scanf("%d%d%d%d", &n, &m, &d, &k); REP(i, n) scanf("%lld", &b[i]); CL(a, 0); for(i = 1; i <= d; ++i) a[i] = a[n-i] = 1; a[0] = 1; while(k) { if(k&1) mul(b, a); mul(a, a); k >>= 1; } REP(i, n) { if(i == 0) printf("%lld", b[i]%m); else printf(" %lld", b[i]%m); } cout << endl; return 0; }
poj 3070
很裸的矩阵乘法,* ^重载一下,0ms水掉
随机化算法
poj 3318
昨晚写了个O(n^3),莫名其妙的wa掉好几次。。。无语!今天开始随机写,开始50次wa,后来100次,wa,后来5000次wa,再后来50000wa两次后AC,随机化算法就是拼人品啊。。。同样的代码有时候wa有时候AC。。。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <ctime> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) typedef long long LL; using namespace std; const int N = 550; int A[N][N]; int B[N][N]; int C[N][N]; bool vis[N][N]; int n; int main() { //freopen("data.in", "r", stdin); int n, i, j, k, m, t; bool f; while(~scanf("%d", &n)) { REP(i, n) REP(j, n) scanf("%d", &A[i][j]); REP(i, n) REP(j, n) scanf("%d", &B[i][j]); REP(i, n) REP(j, n) scanf("%d", &C[i][j]); srand((unsigned)time(NULL)); m = 50000; f = true; CL(vis, false); while(m--) { i = rand()%n; j = rand()%n; if(vis[i][j]) continue; vis[i][j] = true; //printf("%d %d\n", i, j); t = 0; REP(k, n) t += A[i][k]*B[k][j]; if(C[i][j] != t) {f = false; break;} } if(f) puts("YES"); else puts("NO"); } return 0; }
poj 2454
题意:三种牛进行竞选,一共有3*K个城市,每个城市都有1000头牛,给出每个城市中J牛的个数,问怎样把所有城市分成三个选区,使得J牛至少赢得两个选区(J牛数目大于选区一半才能获胜),题目保证有解。
思路:贪心的思想,按J牛数从大到小排序。最小的k个作为一个城市的牛,剩下前边的[0, 2k)头牛可以任意组合,只要满足[0, k)和[k, 2k)的票数都大于k*500就可以了,随机交换两个区间里的元素,知道满足条件。。。rand次数又少了,wa掉好几次。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <ctime> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) typedef long long LL; using namespace std; const int N = 200; struct node { int num; int i; } p[N]; bool cmp(node a, node b) { return a.num > b.num; } int main() { //freopen("data.in", "r", stdin); int k, n, i, j, m, t1, t2; while(~scanf("%d", &k)) { n = k*3; REP(i, n) {scanf("%d", &p[i].num); p[i].i = i+1;} sort(p, p + n, cmp); srand((unsigned)time(NULL)); m = 10000; while(m--) { i = rand()%k; j = rand()%k + k; swap(p[i], p[j]); t1 = t2 = 0; REP(i, k) t1 += p[i].num; for(i = k; i < 2*k; ++i) t2 += p[i].num; if(t1 > k*500 && t2 > k*500) break; } REP(i, n) printf("%d\n", p[i].i); } return 0; }
杂题
poj 3286
题意读错了,以为是求后缀为0的个数。。。折腾了大半个小时发现错了。
要求的是:从m到n的所有数中,含有0的数的个数。
思路是对每一位进行单独处理。详见代码:
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <ctime> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) typedef long long LL; using namespace std; LL bit[13] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000LL, 1000000000LL, 10000000000LL, 100000000000LL, 1000000000000LL}; LL solve(LL n) { if(n == 0) return 0; if(n < 0) return -1; int i; LL l, t, sum = 0; for(i = 1; i < 13; ++i) { l = n/bit[i] - 1; sum += l*bit[i-1]; //置bit[i]位为0的情况数 t = (n%bit[i] - n%bit[i-1])/bit[i-1]; //取bit[i]位的数 if(t == 0) sum += n%bit[i-1] + 1; //这个数是0,则它后边的数可以任取共n%b[i-1] + 1种, +1是因为包含全是0的情况 else sum += bit[i-1]; if(n < bit[i]) break; } return sum; } int main() { //freopen("data.in", "r", stdin); LL a, b; while(~scanf("%lld%lld", &a, &b)) { if(a == -1 && b == -1) break; printf("%lld\n", solve(b) - solve(a-1)); } return 0; }