├── .gitignore ├── README.md └── src ├── aoj0005.cpp ├── aoj0009.cpp ├── aoj0033.cpp ├── aoj0118.cpp ├── aoj0121.cpp ├── aoj0189.cpp ├── aoj0525.cpp ├── aoj0531.cpp ├── aoj0558.cpp ├── aoj1070.cpp ├── aoj1312.cpp ├── aoj2164.cpp ├── aoj2170.cpp ├── aoj2200.cpp ├── aoj2201.cpp ├── aoj2212.cpp ├── aoj2214.cpp ├── aoj2224.cpp ├── aoj2230.cpp ├── aoj2249.cpp ├── aoj2251.cpp ├── aoj2266.cpp ├── aoj2292.cpp ├── cf123d.cpp ├── cf138d.cpp ├── cf25e.cpp ├── cf86c.cpp ├── cf97b.cpp ├── gcj2009b.cpp ├── gcj2011b.cpp ├── poj1011.cpp ├── poj1017.cpp ├── poj1065.cpp ├── poj1082.cpp ├── poj1150.cpp ├── poj1180.cpp ├── poj1201.cpp ├── poj1222.cpp ├── poj1236.cpp ├── poj1258.cpp ├── poj1274.cpp ├── poj1284.cpp ├── poj1286.cpp ├── poj1328.cpp ├── poj1418.cpp ├── poj1466.cpp ├── poj1486.cpp ├── poj1509.cpp ├── poj1631.cpp ├── poj1703.cpp ├── poj1740.cpp ├── poj1742.cpp ├── poj1759.cpp ├── poj1795.cpp ├── poj1854.cpp ├── poj1862.cpp ├── poj1930.cpp ├── poj1979.cpp ├── poj1981.cpp ├── poj1986.cpp ├── poj1990.cpp ├── poj1995.cpp ├── poj2010.cpp ├── poj2032.cpp ├── poj2046.cpp ├── poj2068.cpp ├── poj2082.cpp ├── poj2100.cpp ├── poj2112.cpp ├── poj2114.cpp ├── poj2115.cpp ├── poj2139.cpp ├── poj2155.cpp ├── poj2184.cpp ├── poj2195.cpp ├── poj2226.cpp ├── poj2229.cpp ├── poj2236.cpp ├── poj2315.cpp ├── poj2345.cpp ├── poj2376.cpp ├── poj2377.cpp ├── poj2385.cpp ├── poj2392.cpp ├── poj2393.cpp ├── poj2395.cpp ├── poj2407.cpp ├── poj2409.cpp ├── poj2429.cpp ├── poj2441.cpp ├── poj2482.cpp ├── poj2549.cpp ├── poj2566.cpp ├── poj2674.cpp ├── poj2718.cpp ├── poj2720.cpp ├── poj2723.cpp ├── poj2724.cpp ├── poj2739.cpp ├── poj2749.cpp ├── poj2823.cpp ├── poj2836.cpp ├── poj2886.cpp ├── poj2914.cpp ├── poj2975.cpp ├── poj2976.cpp ├── poj2987.cpp ├── poj3009.cpp ├── poj3040.cpp ├── poj3045.cpp ├── poj3046.cpp ├── poj3050.cpp ├── poj3068.cpp ├── poj3104.cpp ├── poj3109.cpp ├── poj3111.cpp ├── poj3126.cpp ├── poj3134.cpp ├── poj3155.cpp ├── poj3168.cpp ├── poj3171.cpp ├── poj3176.cpp ├── poj3180.cpp ├── poj3181.cpp ├── poj3185.cpp ├── poj3187.cpp ├── poj3190.cpp ├── poj3250.cpp ├── poj3254.cpp ├── poj3258.cpp ├── poj3259.cpp ├── poj3260.cpp ├── poj3262.cpp ├── poj3264.cpp ├── poj3268.cpp ├── poj3273.cpp ├── poj3280.cpp ├── poj3292.cpp ├── poj3293.cpp ├── poj3368.cpp ├── poj3411.cpp ├── poj3415.cpp ├── poj3420.cpp ├── poj3421.cpp ├── poj3422.cpp ├── poj3470.cpp ├── poj3484.cpp ├── poj3494.cpp ├── poj3523.cpp ├── poj3526.cpp ├── poj3532.cpp ├── poj3537.cpp ├── poj3579.cpp ├── poj3614.cpp ├── poj3616.cpp ├── poj3641.cpp ├── poj3662.cpp ├── poj3666.cpp ├── poj3669.cpp ├── poj3678.cpp ├── poj3685.cpp ├── poj3688.cpp ├── poj3692.cpp ├── poj3708.cpp ├── poj3713.cpp ├── poj3728.cpp ├── poj3729.cpp ├── poj3735.cpp ├── poj3977.cpp ├── spoj2939.cpp ├── uva10181.cpp ├── uva11990.cpp └── uva12161.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | cmake-build-debug/ 3 | CMakeLists.txt 4 | *.in 5 | *.out 6 | src/test.cpp 7 | -------------------------------------------------------------------------------- /src/aoj0005.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 0005: GCD and LCM 3 | * 题意:求两数最大公约数和最小公倍数。 4 | * 类型:辗转相除法 5 | * 算法:gcd(a,b)=gcd(b,a%b),lcm(a,b)=a*b/gcd(a,b)。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int gcd(int a, int b) { 14 | for(int t; t = a % b; a = b, b = t); 15 | return b; 16 | } 17 | 18 | int main() { 19 | int a, b, g; 20 | long long l; 21 | while(scanf("%d%d", &a, &b) != EOF) { 22 | g = gcd(a, b); 23 | l = 1ll * a * b / g; 24 | printf("%d %lld\n", g, l); 25 | } 26 | return 0; 27 | } -------------------------------------------------------------------------------- /src/aoj0009.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 0009: Prime Number 3 | * 题意:给出n,求不大于n的素数有多少个。 4 | * 类型:素数 5 | * 算法:先用线性时间复杂度的筛法打素数表,对于每个输入统计不超过的素数个数。 6 | */ 7 | 8 | 9 | #include 10 | 11 | typedef long long LL; 12 | 13 | int p[100010]; 14 | bool np[1000010]; 15 | int cntp; 16 | 17 | void SievePrime(int n) { 18 | LL t; 19 | for(int i = 2; i <= n; ++i) { 20 | if(!np[i]) p[cntp++] = i; 21 | for(int j = 0; j < cntp && (t = 1ll * i * p[j]) <= n; ++j) { 22 | np[t] = true; 23 | if(i % p[j] == 0) break; 24 | } 25 | } 26 | } 27 | 28 | int main() { 29 | SievePrime(1000000); 30 | int n; 31 | while(scanf("%d", &n) != EOF) { 32 | int ans = 0; 33 | for(int i = 2; i <= n; ++i) { 34 | if(!np[i]) ++ans; 35 | } 36 | printf("%d\n", ans); 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /src/aoj0033.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 0033: Ball 3 | * 题意:序号为1-10的10个球,按一定排列顺序进入2个队列之一,最终每队入队球的序号都为增序的方案是否存在。 4 | * 类型:贪心 5 | * 算法:对于每个球,若大于队列顶端元素,则可以记录该情况并继续递归。每次优先加入左边,可保证保证左边的顶端元素大于右边。 6 | */ 7 | 8 | #include 9 | 10 | int a[10]; 11 | 12 | 13 | int main() { 14 | int T; 15 | scanf("%d", &T); 16 | while (T--) { 17 | bool ans = true; 18 | for (int i = 0; i < 10; ++i) { 19 | scanf("%d", &a[i]); 20 | } 21 | int l, r; 22 | l = r = 0; 23 | for (int i = 0; i < 10; ++i) { 24 | if (a[i] > l) { 25 | l = a[i]; 26 | } else if (a[i] > r) { 27 | r = a[i]; 28 | } else { 29 | ans = false; 30 | break; 31 | } 32 | } 33 | printf("%s\n", ans ? "YES" : "NO"); 34 | } 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/aoj0118.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 0118: Property Distribution 3 | * 题意:m*n矩阵中,共3种植物。相邻的同种植物块可合并,问合并后共多少块区域。 4 | * 类型:DFS+记忆化搜索(/BFS/并查集) 5 | * 算法:从某点出发,向上下左右4个方向查询,若为同种植物则继续递归,经过的点需要记忆化。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | char mat[102][102]; 14 | int dx[4] = {0, 1, 0, -1}; 15 | int dy[4] = {1, 0, -1, 0}; 16 | int m, n; 17 | int ans; 18 | 19 | void dfs(int x, int y) { 20 | char t = mat[x][y]; 21 | mat[x][y] = '.'; 22 | for (int i = 0; i < 4; ++i) { 23 | int xx = x + dx[i]; 24 | int yy = y + dy[i]; 25 | if (xx >= 0 && xx < m && yy >= 0 && yy < n && mat[xx][yy] == t) { 26 | dfs(xx, yy); 27 | } 28 | } 29 | } 30 | 31 | void solve() { 32 | ans = 0; 33 | for (int i = 0; i < m; ++i) { 34 | cin >> mat[i]; 35 | } 36 | for (int i = 0; i < m; ++i) { 37 | for (int j = 0; j < n; ++j) { 38 | if (mat[i][j] != '.') { 39 | ++ans; 40 | dfs(i, j); 41 | } 42 | } 43 | } 44 | } 45 | 46 | int main() { 47 | while (cin >> m >> n && n > 0 && m > 0) { 48 | solve(); 49 | cout << ans << endl; 50 | } 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /src/aoj0121.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 0121: Seven Puzzle 3 | * 题意:2行4列的矩阵,标号为0~7,每次可以将0和其相邻格交换,问达到增序局面的最少移动步数。 4 | * 类型:BFS+Map 5 | * 算法:用String表示局面,用Map建立局面与最短路的映射。用最终有序态初始化队列,每次从队列中取出一个局面,搜索可移动且未出现过的局面再加入队列,直到局面为增序或队列空。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | int a[8]; 18 | int d[4] = {-1, 1, -4, 4}; 19 | 20 | map mymap; 21 | 22 | void bfs() { 23 | queue q; 24 | q.push("01234567"); 25 | mymap["01234567"] = 0; 26 | while (!q.empty()) { 27 | string cur = q.front(); 28 | string nxt; 29 | q.pop(); 30 | int p = (int) cur.find("0"); 31 | for (int i = 0; i < 4; ++i) { 32 | int np = p + d[i]; 33 | if (np >= 0 && np < 8 && (p != 3 || d[i] != 1) && (p != 4 || d[i] != -1)) { 34 | nxt = cur; 35 | nxt[np] = '0'; 36 | nxt[p] = cur[np]; 37 | if (mymap.find(nxt) == mymap.end()) { 38 | mymap[nxt] = mymap[cur] + 1; 39 | q.push(nxt); 40 | } 41 | } 42 | 43 | } 44 | } 45 | } 46 | 47 | int main() { 48 | bfs(); 49 | while (cin >> a[0]) { 50 | for (int i = 1; i < 8; ++i) { 51 | cin >> a[i]; 52 | } 53 | string s = ""; 54 | for (int i = 0; i < 8; ++i) { 55 | s += a[i] + '0'; 56 | } 57 | if (mymap.find(s) == mymap.end()) 58 | cout << -1 << endl; 59 | else 60 | cout << mymap[s] << endl; 61 | } 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /src/aoj0189.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 0189: Convenient Location 3 | * 题意:多个地点,多条双向边,每条边有时间花费。求到所有地点的时间的和最小的点。 4 | * 类型:最短路 5 | * 算法:用Floyd求到两两之间最短路,枚举总和最小的点。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | const int INF = 0x3f3f3f3f; 15 | 16 | int d[10][10]; 17 | int m; 18 | 19 | void floyd() { 20 | for (int k = 0; k < m; ++k) { 21 | for (int i = 0; i < m; ++i) { 22 | for (int j = 0; j < m; ++j) { 23 | d[i][j] = min(d[i][j], d[i][k] + d[k][j]); 24 | } 25 | } 26 | } 27 | } 28 | 29 | 30 | int main() { 31 | int i, j, a, b, c, n; 32 | while (scanf("%d", &n) != EOF && n) { 33 | memset(d, 0x3f, sizeof(d)); 34 | m = 0; 35 | while (n--) { 36 | scanf("%d%d%d", &a, &b, &c); 37 | d[a][b] = d[b][a] = c; 38 | m = max(m, max(a + 1, b + 1)); 39 | } 40 | floyd(); 41 | int ans, p, tmp; 42 | p = 0; 43 | ans = INF; 44 | for (i = 0; i < m; ++i) { 45 | tmp = 0; 46 | for (j = 0; j < m; ++j) { 47 | if (i == j) continue; 48 | tmp += d[i][j]; 49 | if (tmp >= INF) break; 50 | } 51 | if (tmp < ans) { 52 | ans = tmp; 53 | p = i; 54 | } 55 | } 56 | printf("%d %d\n", p, ans); 57 | } 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /src/aoj0525.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 0525: Osenbei 3 | * 题意:R行C列的矩阵,点为0或1。每次可对整行或整列的点进行翻转,求最多可能出现多少个0。 4 | * 类型:穷竭搜索+位运算 5 | * 算法:最多10行,可对行的翻转情况用全排列遍历,同时修改每列1的个数。列翻转可等价于将0或1的个数用于求和。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | int m, n; 17 | int mat[11][10001]; 18 | int one[10001], _one[10001]; 19 | int ans; 20 | 21 | void solve() { 22 | ans = 0; 23 | memset(one, 0, sizeof(one)); 24 | for (int i = 0; i < m; ++i) { 25 | for (int j = 0; j < n; ++j) { 26 | cin >> mat[i][j]; 27 | one[j] += mat[i][j]; 28 | } 29 | } 30 | for (int no = (1 << m) - 1; no >= 0; --no) { 31 | int _no = no; 32 | for (int i = 0; i < n; ++i) { 33 | _one[i] = one[i]; 34 | } 35 | for (int i = 0; i < m; ++i) { 36 | if (_no & 1) { 37 | for (int j = 0; j < n; ++j) { 38 | _one[j] += mat[i][j] ? -1 : 1; 39 | } 40 | } 41 | _no >>= 1; 42 | } 43 | int tmp = 0; 44 | for (int i = 0; i < n; ++i) { 45 | tmp += max(_one[i], m - _one[i]); 46 | } 47 | ans = max(ans, tmp); 48 | } 49 | 50 | } 51 | 52 | int main() { 53 | while (cin >> m >> n && m > 0 && n > 0) { 54 | solve(); 55 | cout << ans << endl; 56 | } 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /src/aoj0558.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 0558: Cheese 3 | * 题意:m*n矩阵内,给出起点、1~N表示N个工厂、障碍、空格。求按顺序遍历1~N的最短路。 4 | * 类型:BFS+Queue(/Dijkstra) 5 | * 算法:从S顺序通过1~N的最短路,可以用BFS求N次相邻序号间最短路的和。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef pair pii; 16 | 17 | int m, n, N; 18 | char mat[1002][1002]; 19 | int d[1002][1002]; 20 | int sx[10], sy[10]; 21 | int dx[4] = {-1, 0, 1, 0}; 22 | int dy[4] = {0, 1, 0, -1}; 23 | int ans; 24 | 25 | int bfs(int sx, int sy, int tx, int ty) { 26 | memset(d, -1, sizeof(d)); 27 | d[sx][sy] = 0; 28 | queue q; 29 | q.push(make_pair(sx, sy)); 30 | int x, y, xx, yy; 31 | while (!q.empty()) { 32 | pii cur = q.front(); 33 | q.pop(); 34 | x = cur.first; 35 | y = cur.second; 36 | for (int i = 0; i < 4; ++i) { 37 | xx = x + dx[i]; 38 | yy = y + dy[i]; 39 | if (xx >= 0 && xx < m && yy >= 0 && yy < n && mat[xx][yy] != 'X' && d[xx][yy] == -1) { 40 | d[xx][yy] = d[x][y] + 1; 41 | if (xx == tx && yy == ty) { 42 | return d[xx][yy]; 43 | } 44 | q.push(make_pair(xx, yy)); 45 | } 46 | } 47 | } 48 | 49 | } 50 | 51 | void solve() { 52 | ans = 0; 53 | for (int i = 0; i < m; ++i) { 54 | cin >> mat[i]; 55 | for (int j = 0; j < n; ++j) { 56 | if (mat[i][j] == 'S') { 57 | sx[0] = i; 58 | sy[0] = j; 59 | } else if (mat[i][j] >= '1' && mat[i][j] <= '9') { 60 | int t = mat[i][j] - '0'; 61 | sx[t] = i; 62 | sy[t] = j; 63 | } 64 | } 65 | } 66 | for (int i = 1; i <= N; ++i) { 67 | int tmp = bfs(sx[i - 1], sy[i - 1], sx[i], sy[i]); 68 | ans += tmp; 69 | } 70 | } 71 | 72 | int main() { 73 | cin >> m >> n >> N; 74 | solve(); 75 | cout << ans << endl; 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /src/aoj2164.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 2164: Revenge of the Round Table 3 | * 题意:来自两国的n个人围着圆桌坐下,要求相同国家坐在一起的不超过k个,问多少种方案(旋转后国籍序列重合视为一种)。 4 | * 类型:Pólya计数+DP 5 | * 算法:旋转i的循环节个数为gcd(n,i),关键在于求长度为循环节个数i的不同串d[i],然后代入公式L=|G|*(d[c(p1)]+d[c(p2)]+...+d[c(pk)])。t[0/1][i][j]表示长i且结尾j个相同字符、开头与结尾相同或不同的串数。d[i]表示长度为i且字符不全相同且不超过k个连续相同的数。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef long long LL; 16 | 17 | const LL MOD = 1000003ll; 18 | LL t[2][1010][1010], s[2][1010][1010], d[1010]; 19 | 20 | void Dp(LL n, LL k) { 21 | memset(t, 0, sizeof(t)); 22 | memset(s, 0, sizeof(s)); 23 | memset(d, 0, sizeof(d)); 24 | 25 | 26 | t[0][1][1] = 1; 27 | s[0][1][1] = 1; 28 | 29 | for (LL i = 2; i <= n; ++i) { 30 | for (int c = 0; c < 2; ++c) { 31 | t[c][i][1] = s[c][i][1] = s[1 - c][i - 1][min(k, i - 1)]; 32 | } 33 | for (LL j = 2; j <= min(i, k); ++j) { 34 | for (int c = 0; c < 2; ++c) { 35 | t[c][i][j] = t[c][i - 1][j - 1]; 36 | s[c][i][j] = (s[c][i][j - 1] + t[c][i][j]) % MOD; 37 | } 38 | } 39 | for (LL j = min(i, k) + 1; j <= k; ++j) { 40 | for (int c = 0; c < 2; ++c) { 41 | s[c][i][j] = s[c][i][j - 1]; 42 | } 43 | } 44 | } 45 | 46 | for (LL i = 1; i <= n; ++i) { 47 | d[i] = s[1][i][min(i, k)]; 48 | for (LL p = 1; p <= min(k - 1, i - 2); ++p) { 49 | d[i] = (d[i] + s[1][i - p][min(k - p, i - 1 - p)]) % MOD; 50 | } 51 | } 52 | } 53 | 54 | LL Inverse(LL a, LL p) { 55 | if (a == 1) return 1; 56 | return ((-p / a * Inverse(p % a, p)) % p + p) % p; 57 | } 58 | 59 | LL Gcd(LL a, LL b) { 60 | for (LL t; t = b;) { 61 | b = a % b; 62 | a = t; 63 | } 64 | return a; 65 | } 66 | 67 | int main() { 68 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 69 | LL n, k; 70 | while (scanf("%lld%lld", &n, &k) != EOF && n + k > 0) { 71 | if (n < k) k = n; 72 | LL ans = 0; 73 | Dp(n, k); 74 | for (LL i = 0; i < n; ++i) { 75 | ans = (ans + d[Gcd(n, i)]) % MOD; 76 | } 77 | ans = (ans * 2 * Inverse(n, MOD)) % MOD; 78 | if (k >= n) ans+=2; // 字符全部相同 79 | printf("%lld\n", ans); 80 | } 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /src/aoj2170.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 2170: Marked Ancestor 3 | * 题意:给出一棵树,两种操作,将某点染色,或查询某个点的最近的已染色祖先。初始只有根染色了,对于每次询问输出最近染色祖先编号。 4 | * 类型:并查集+dfs+栈(/线段树+dfs) 5 | * 算法:所有的染色和询问请求放入栈内,先染好所有点,dfs得到每点的最近祖先,相同祖先相当于在并查集的同一集合里。再倒着把染色一一变暗,去染色时将该点与它父亲所在集合合并。(/线段树法:dfs得到树的中序遍历,每标记一个点,找到该子树对应的中序区间,线段树懒惰标记。) 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | typedef pair pci; 17 | 18 | stack s; 19 | 20 | int fa[100010]; 21 | int p[100010]; 22 | int vis[100010]; 23 | 24 | vector e[100010]; 25 | 26 | int n; 27 | 28 | void dfs(int i, int f = 1) { 29 | if(vis[i]) { 30 | f = i; 31 | } 32 | fa[i] = f; 33 | vector &ei = e[i]; 34 | for(vector::iterator it = ei.begin(); it != ei.end(); ++it) { 35 | dfs(*it, f); 36 | } 37 | } 38 | 39 | int find(int x) { 40 | if(x == fa[x]) return x; 41 | return fa[x] = find(fa[x]); 42 | } 43 | 44 | int main() { 45 | int i, j, q; 46 | long long ans; 47 | char op[3]; 48 | while(scanf("%d%d", &n, &q) != EOF && n > 0) { 49 | memset(vis, 0, sizeof(vis)); 50 | for(i = 1; i <= n; ++i) { 51 | e[i].clear(); 52 | } 53 | ans = 0; 54 | 55 | vis[1] = 1; 56 | for(i = 2; i <= n; ++i) { 57 | scanf("%d", &j); 58 | e[j].push_back(i); 59 | p[i] = j; 60 | } 61 | for(i = 0; i < q; ++i) { 62 | scanf("%s%d", op, &j); 63 | if(op[0] == 'M') { 64 | ++vis[j]; 65 | } 66 | s.push(make_pair(op[0], j)); 67 | } 68 | dfs(1); 69 | 70 | while(!s.empty()) { 71 | i = s.top().second; 72 | if(s.top().first == 'M') { 73 | if(--vis[i] == 0) { 74 | fa[i] = find(p[i]); 75 | } 76 | } else { 77 | ans += find(i); 78 | } 79 | s.pop(); 80 | } 81 | 82 | printf("%lld\n", ans); 83 | 84 | } 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /src/aoj2200.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 2200: Mr. Rito Post Office 3 | * 题意:给出岛之间的若干水路和陆路,水路转为陆路时船就停在那,之后要陆路转水路还得从那开始。求按给出的可重复序列通过多个岛的最短时间。 4 | * 类型:最短路+DP 5 | * 算法:先用Floyd预处理出单独走水路s或陆路l的两两之间的最短路。d[i][j]表示到序列第i点时船停在j。状态转移:人从a到b,船从c到d,若船动加上l[a,c]+s[c,d]+l[d,b],若船不动则只要加上l[a][b]。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | int s[210][210]; 16 | int l[210][210]; 17 | int d[1010][210]; 18 | int b[1010]; 19 | 20 | const int INF = 0x3f3f3f3f; 21 | 22 | void Floyd(int n) { 23 | for (int k = 1; k <= n; ++k) { 24 | for (int i = 1; i <= n; ++i) { 25 | for (int j = 1; j <= n; ++j) { 26 | s[i][j] = min(s[i][j], s[i][k] + s[k][j]); 27 | l[i][j] = min(l[i][j], l[i][k] + l[k][j]); 28 | } 29 | } 30 | } 31 | } 32 | 33 | int main() { 34 | int n, m, r; 35 | int u, v, c; 36 | char tp[3]; 37 | 38 | while (scanf("%d%d", &n, &m) != EOF && n) { 39 | memset(s, 0x3f, sizeof(s)); 40 | memset(l, 0x3f, sizeof(l)); 41 | memset(d, 0x3f, sizeof(d)); 42 | 43 | while (m--) { 44 | scanf("%d%d%d%s", &u, &v, &c, tp); 45 | if (tp[0] == 'L') { 46 | l[u][v] = min(l[u][v], c); 47 | l[v][u] = min(l[v][u], c); 48 | } else { 49 | s[u][v] = min(s[u][v], c); 50 | s[v][u] = min(s[v][u], c); 51 | } 52 | } 53 | 54 | for (int i = 1; i <= n; ++i) { 55 | l[i][i] = 0; 56 | s[i][i] = 0; 57 | } 58 | 59 | scanf("%d", &r); 60 | 61 | for (int i = 1; i <= r; ++i) { 62 | scanf("%d", &b[i]); 63 | } 64 | 65 | Floyd(n); 66 | 67 | for (int i = 1; i <= n; ++i) { 68 | d[1][i] = min(d[1][i], s[b[1]][i] + l[i][b[1]]); 69 | } 70 | 71 | for (int i = 1; i <= r; ++i) { 72 | for (int j = 1; j <= n; ++j) { 73 | if (l[j][b[i]] >= INF) continue; 74 | for (int k = 1; k <= n; ++k) { 75 | if (d[i - 1][k] >= INF) continue; 76 | if (j == k) { 77 | if (l[b[i - 1]][b[i]] < INF) { 78 | d[i][j] = min(d[i][j], d[i - 1][k] + l[b[i - 1]][b[i]]); 79 | } 80 | } else { 81 | if (l[b[i - 1]][k] < INF && s[k][j] < INF && l[j][b[i]] < INF) { 82 | d[i][j] = min(d[i][j], d[i - 1][k] + l[b[i - 1]][k] + s[k][j] + l[j][b[i]]); 83 | } 84 | } 85 | } 86 | } 87 | } 88 | 89 | int ans = INF; 90 | for (int j = 1; j <= n; ++j) { 91 | ans = min(ans, d[r][j]); 92 | } 93 | printf("%d\n", ans); 94 | } 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /src/aoj2214.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 2214: Warp Hall 3 | * 题意:从(1,1)要到终点(m,n)。每次向右或向上走,但一旦遇到虫洞起点,会直接到达右上方的虫洞终点。问有多少种路线。 4 | * 类型:计数DP 5 | * 算法:对于虫洞i(ai,bi)到(ci,di),(1,1)到(ai,bi)的路线数为di,则对于以虫洞构成的矩形为中心,向上和向右发散的L区,都要去掉di。将虫洞排序,DP求到达到每个虫洞入口的方案数。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef long long LL; 16 | 17 | const LL MOD = 1000000007ll; 18 | 19 | inline LL add(LL a, LL b) { return (a + b) % MOD; } 20 | 21 | inline LL sub(LL a, LL b) { return (a - b + MOD) % MOD; } 22 | 23 | inline LL mul(LL a, LL b) { return a * b % MOD; } 24 | 25 | LL f[200010]; 26 | 27 | LL Inverse(LL a, LL p = MOD) { 28 | if (a == 1) return 1; 29 | return sub(0, mul(p / a, Inverse(p % a, p))); 30 | } 31 | 32 | LL C(LL a, LL b) { 33 | return mul(mul(f[a], Inverse(f[b])), Inverse(f[a - b])); 34 | } 35 | 36 | struct Warp { 37 | int sx, sy, tx, ty; 38 | 39 | bool operator<(const Warp &w) const { 40 | if (sx != w.sx) return sx < w.sx; 41 | return sy < w.sy; 42 | } 43 | } w[1010]; 44 | 45 | LL d[1010]; 46 | int m, n, k; 47 | 48 | LL Gao(LL sx, LL sy, LL tx, LL ty) { 49 | if (sx > tx || sy > ty) return 0; 50 | return C(tx - sx + ty - sy, tx - sx); 51 | } 52 | 53 | int main() { 54 | freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 55 | f[0] = 1; 56 | for (LL i = 1; i <= 200000; ++i) { 57 | f[i] = mul(f[i - 1], i); 58 | } 59 | while (scanf("%d%d%d", &m, &n, &k) != EOF && m + n + k > 0) { 60 | for (int i = 0; i < k; ++i) { 61 | scanf("%d%d%d%d", &w[i].sx, &w[i].sy, &w[i].tx, &w[i].ty); 62 | --w[i].sx; 63 | --w[i].sy; 64 | --w[i].tx; 65 | --w[i].ty; 66 | } 67 | memset(d, 0, sizeof(d)); 68 | sort(w, w + k); 69 | w[k].sx = m - 1; 70 | w[k].sy = n - 1; 71 | for (int i = 0; i <= k; ++i) { 72 | d[i] = C(w[i].sx + w[i].sy, w[i].sx); 73 | for (int j = 0; j < i; ++j) { 74 | d[i] = add(d[i], 75 | mul(d[j], 76 | sub(Gao(w[j].tx, w[j].ty, w[i].sx, w[i].sy), 77 | Gao(w[j].sx, w[j].sy, w[i].sx, w[i].sy)))); 78 | } 79 | } 80 | printf("%lld\n", d[k]); 81 | } 82 | 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /src/aoj2224.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 2224: Save Your Cats 3 | * 题意:给出一个图,去除每条边的花费为边的长度,求用最少的花费去除部分边使得图中无圈。 4 | * 类型:最小生成树 5 | * 算法:要求去除的边总长最短,则留下的森林的边长和应最大。最大生成森林问题可将Kruskal算法变形为每次取最大边,再用并查集判断连节。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | struct E{ 16 | E() {} 17 | E(int uu, int vv, double cc): u(uu), v(vv), c(cc) {} 18 | bool operator > (const E& e) const { 19 | return c < e.c; 20 | } 21 | int u, v; 22 | double c; 23 | }; 24 | 25 | int fa[10010]; 26 | priority_queue, greater > pq; 27 | 28 | int find(int x) { 29 | if(x == fa[x]) return x; 30 | return fa[x] = find(fa[x]); 31 | } 32 | 33 | double Kruskal(int n) { 34 | for(int i = 1; i <= n; ++i) { 35 | fa[i] = i; 36 | } 37 | int cnt = 1; 38 | double ans = 0; 39 | 40 | while(cnt < n && !pq.empty()) { 41 | const E& e = pq.top(); 42 | int u, v; 43 | double c; 44 | u = e.u; 45 | v = e.v; 46 | c = e.c; 47 | pq.pop(); 48 | 49 | u = find(u); 50 | v = find(v); 51 | if(u == v) continue; 52 | fa[u] = v; 53 | ans += c; 54 | ++cnt; 55 | } 56 | return ans; 57 | } 58 | 59 | double x[10010], y[10010]; 60 | 61 | int main() { 62 | int n, m; 63 | double ans = 0; 64 | scanf("%d%d", &n, &m); 65 | for(int i = 1; i <= n; ++i) { 66 | scanf("%lf%lf", &x[i], &y[i]); 67 | } 68 | while(m--) { 69 | int u, v; 70 | double c; 71 | scanf("%d%d", &u, &v); 72 | c = sqrt((x[u]-x[v])*(x[u]-x[v]) + (y[u]-y[v])*(y[u]-y[v])); 73 | ans += c; 74 | pq.push(E(u, v ,c)); 75 | } 76 | ans -= Kruskal(n); 77 | printf("%.3f\n", ans); 78 | return 0; 79 | } -------------------------------------------------------------------------------- /src/aoj2249.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 2249: Road Construction 3 | * 算法:给出若干双向边,每条边有长度和花费。保证从0点到其他每个点的最短路不变,删除若干边。求保留边的总花费最小值。 4 | * 类型:最短路 5 | * 算法:最短路每个点只保留一个前继,计算前继边的策略是,从该边可得到更小最短路,或相等最短路但边花费更小。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef pair pii; 16 | 17 | priority_queue, greater > pq; 18 | 19 | int d[10010]; 20 | 21 | struct E{ 22 | E() {} 23 | E(int vv, int cc, int ww): v(vv), c(cc), w(ww) {} 24 | int v, c, w; 25 | }; 26 | 27 | vector e[10010]; 28 | int pre[10010]; 29 | 30 | void Dijkstra(int n, int s, int d[], vector e[]) { 31 | memset(d + 1, 0x3f, sizeof(int) * n); 32 | pq.push(make_pair(d[s]=0, s)); 33 | while(!pq.empty()) { 34 | int u, v, c, m; 35 | m = pq.top().first; 36 | u = pq.top().second; 37 | pq.pop(); 38 | if(m > d[u]) { 39 | continue; 40 | } 41 | for(vector::iterator it = e[u].begin(); it != e[u].end(); ++it){ 42 | const E &edge = *it; 43 | v = edge.v; 44 | c = edge.c; 45 | int t = d[u] + c; 46 | if(t < d[v]) { 47 | pq.push(make_pair(d[v]=t, v)); 48 | pre[v] = edge.w; 49 | } else if(t == d[v]) { 50 | pre[v] = min(pre[v], edge.w); 51 | } 52 | } 53 | } 54 | } 55 | 56 | int main() { 57 | int n, m, u, v, c, w; 58 | 59 | while(scanf("%d%d", &n, &m) != EOF && n) { 60 | for(u = 1; u <= n; ++u) { 61 | e[u].clear(); 62 | } 63 | while (m--) { 64 | scanf("%d%d%d%d", &u, &v, &c, &w); 65 | e[u].push_back(E(v, c, w)); 66 | e[v].push_back(E(u, c, w)); 67 | } 68 | Dijkstra(n, 1, d, e); 69 | 70 | int ans = 0; 71 | for (u = 2; u <= n; ++u) { 72 | ans += pre[u]; 73 | } 74 | printf("%d\n", ans); 75 | } 76 | return 0; 77 | } -------------------------------------------------------------------------------- /src/aoj2251.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * AOJ 2251: Merry Christmas 3 | * 题意:给出一个带权无向图,给出多个任务,每个任务指定了在何处何时发生。求最少需要多少人才能完成所有任务。 4 | * 类型:最短路+二分匹配 5 | * 算法:先用Floyd求两两之间最短路,若两个任务时间差不超过最短路,则可以分配给同一个人。以任务和任务的副本建二分图,任务数-最大匹配/2即为所求。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | const int INF = 0x3f3f3f3f; 15 | 16 | vector e[1010]; 17 | bool vis[1010]; 18 | int rec[1010]; 19 | int n1; 20 | 21 | int n, m; 22 | int d[110][110]; 23 | 24 | int p[1010], t[1010]; 25 | 26 | bool Dfs(int u) { 27 | for (vector::iterator it = e[u].begin(); it != e[u].end(); ++it) { 28 | int v = *it; 29 | if (!vis[v]) { 30 | vis[v] = true; 31 | if (rec[v] == -1 || Dfs(rec[v])) { 32 | rec[v] = u; 33 | return true; 34 | } 35 | } 36 | } 37 | return false; 38 | } 39 | 40 | int Hungary() { 41 | int ans = 0; 42 | memset(rec, -1, sizeof(rec)); 43 | for (int i = 0; i < n1; ++i) { 44 | memset(vis, 0, sizeof(vis)); 45 | if (Dfs(i)) ++ans; 46 | } 47 | return ans; 48 | } 49 | 50 | void Floyd() { 51 | for (int k = 0; k < n; ++k) { 52 | for (int i = 0; i < n; ++i) { 53 | for (int j = 0; j < n; ++j) { 54 | d[i][j] = min(d[i][j], d[i][k] + d[k][j]); 55 | } 56 | } 57 | } 58 | } 59 | 60 | int main() { 61 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 62 | while (scanf("%d%d%d", &n, &m, &n1) != EOF && n) { 63 | memset(d, 0x3f, sizeof(d)); 64 | for (int i = 0; i < n; ++i) d[i][i] = 0; 65 | for (int i = 0; i < m; ++i) { 66 | int u, v, c; 67 | scanf("%d%d%d", &u, &v, &c); 68 | d[u][v] = d[v][u] = c; 69 | } 70 | Floyd(); 71 | for (int i = 0; i < n1; ++i) { 72 | scanf("%d%d", &p[i], &t[i]); 73 | e[i].clear(); 74 | } 75 | for (int i = 0; i < n1; ++i) { 76 | for (int j = 0; j < n1; ++j) { 77 | if (i == j) continue; 78 | if (t[i] + d[p[i]][p[j]] <= t[j]) { 79 | e[i].push_back(j); 80 | } 81 | } 82 | } 83 | printf("%d\n", n1 - Hungary()); 84 | } 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /src/cf123d.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * CF 123D: String 3 | * 题意:给出一个字符串,枚举所有子串并按是否相同分组,若某组内个数为k,则答案累加上k(k+1)/2。求答案最终累加和。 4 | * 类型:后缀数组+栈 5 | * 算法:用'|'连接串和自己,求出后缀数组和高度数组。从正向和反向分别用栈得到每个点两侧最近的小于它的位置,则子串长度为它的串数为这段的数量。因为串重复了自己,所以除以2得到k。而固定开头后,子串可选长度为该点高度减去两侧比自己低的点中高的那个,由此避免重复计算。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | char s[200010]; 17 | int n, k; 18 | 19 | int sa[200010]; 20 | int ra[200010], tr[200010]; 21 | int lcp[200010]; 22 | 23 | int l[200010], r[200010]; 24 | stack ls, rs; 25 | set ss; 26 | 27 | bool CmpSa(int a, int b) { 28 | if (ra[a] != ra[b]) return ra[a] < ra[b]; 29 | int aa = a + k < n ? ra[a + k] : -1; 30 | int bb = b + k < n ? ra[b + k] : -1; 31 | return aa < bb; 32 | } 33 | 34 | void GaoSa() { 35 | for (int i = 0; i <= n; ++i) { 36 | sa[i] = i; 37 | ra[i] = i < n ? s[i] : -1; 38 | } 39 | for (k = 1; k <= n; k <<= 1) { 40 | sort(sa, sa + n + 1, CmpSa); 41 | tr[sa[0]] = 0; 42 | for (int i = 1; i <= n; ++i) { 43 | tr[sa[i]] = tr[sa[i - 1]] + CmpSa(sa[i - 1], sa[i]); 44 | } 45 | memcpy(ra, tr, sizeof(int) * (n + 1)); 46 | } 47 | } 48 | 49 | void GaoLcp() { 50 | int tmp = 0; 51 | for (int i = 0; i < n; ++i) { 52 | int rk = ra[i]; 53 | int j = sa[rk - 1]; 54 | if (tmp > 0) --tmp; 55 | while (i + tmp < n && j + tmp < n && s[i + tmp] == s[j + tmp]) { 56 | ++tmp; 57 | } 58 | lcp[rk - 1] = tmp; 59 | } 60 | } 61 | 62 | inline long long Hash(int b, int c) { 63 | return b * 1000000ll + c; 64 | } 65 | 66 | int main() { 67 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 68 | scanf("%s", s); 69 | n = strlen(s); 70 | s[n] = '|'; 71 | memcpy(s + n + 1, s, sizeof(char) * n); 72 | n = 2 * n + 1; 73 | GaoSa(); 74 | GaoLcp(); 75 | 76 | for (int i = 0; i <= n; ++i) { 77 | while (!rs.empty() && lcp[rs.top()] > lcp[i]) { 78 | r[rs.top()] = i; 79 | rs.pop(); 80 | } 81 | rs.push(i); 82 | } 83 | 84 | for (int i = n; i >= 0; --i) { 85 | while (!ls.empty() && lcp[ls.top()] > lcp[i]) { 86 | l[ls.top()] = i; 87 | ls.pop(); 88 | } 89 | ls.push(i); 90 | } 91 | 92 | long long ans = 0; 93 | for (int i = 1; i < n - 1; ++i) { 94 | if (lcp[i]) { 95 | if (ss.find(Hash(lcp[i], l[i])) != ss.end()) continue; 96 | long long tmp = (r[i] - l[i]) / 2; 97 | tmp = tmp * (tmp + 1) / 2; 98 | ans += tmp * (lcp[i] - max(lcp[l[i]], lcp[r[i]])); 99 | ss.insert(Hash(lcp[i], l[i])); 100 | } 101 | } 102 | cout << ans << endl; 103 | 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /src/cf138d.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * CF 138D: World of Darkraft 3 | * 题意:n行m列的图,图上字符L表示从该点向左下和右上发射光波,沿路毁坏点,直到撞到之前毁坏过的点。R向左上和右下,X向上述4个方向。两人轮流选点,问先手胜负。 4 | * 类型:Grundy博弈 5 | * 算法:横纵坐标相加为奇数和偶数的两个游戏独立。整个图顺时针旋转45度,这样每次L就是横向分割,R就是纵向分割,X分为四块。枚举范围内所有点,得到周围子游戏seg的xor,更新当前的seg值。全局seg为0必败否则必胜。 6 | */ 7 | 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | int sg[44][44][44][44][2]; 13 | char mat[22][22]; 14 | int m, n; 15 | 16 | int dp(int x1, int x2, int y1, int y2, int odd) { 17 | if (x2 - x1 < 1 || y2 - y1 < 1) return 0; 18 | if (sg[x1][x2][y1][y2][odd] != -1) return sg[x1][x2][y1][y2][odd]; 19 | bool vis[1700] = {0}; 20 | for (int i = 0; i < m; ++i) { 21 | for (int j = 0; j < n; ++j) { 22 | if ((i + j) % 2 != odd) continue; 23 | int x, y, t = 0; 24 | x = i + j; 25 | y = j - i + m - 1; 26 | if (x >= x1 && x < x2 && y >= y1 && y < y2) { 27 | char ch = mat[j][i]; 28 | if (ch == 'R') { 29 | t = dp(x1, x, y1, y2, odd) ^ dp(x + 1, x2, y1, y2, odd); 30 | } else if (ch == 'L') { 31 | t = dp(x1, x2, y1, y, odd) ^ dp(x1, x2, y + 1, y2, odd); 32 | } else if (ch == 'X') { 33 | t = dp(x1, x, y1, y, odd) ^ dp(x + 1, x2, y1, y, odd) ^ 34 | dp(x1, x, y + 1, y2, odd) ^ dp(x + 1, x2, y + 1, y2, odd); 35 | } 36 | vis[t] = 1; 37 | } 38 | } 39 | } 40 | int i = 0; 41 | while (vis[i]) ++i; 42 | return sg[x1][x2][y1][y2][odd] = i; 43 | } 44 | 45 | 46 | int main() { 47 | memset(sg, -1, sizeof(sg)); 48 | scanf("%d%d", &n, &m); 49 | for (int i = n - 1; i >= 0; --i) { 50 | scanf("%s", mat[i]); 51 | } 52 | int mn = m + n - 1; 53 | int ans = dp(0, mn, 0, mn, 0) ^ dp(0, mn, 0, mn, 1); 54 | printf("%s\n", ans > 0 ? "WIN" : "LOSE"); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /src/cf25e.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * CF 25E: Test 3 | * 题意:给出三个串,求包含它们的最短母串的长度。在母串中,子串可重叠且顺序任意。 4 | * 类型:字符串哈希 5 | * 算法:枚举三个子串开头出现的6种顺序,前两个先处理得到母串,再和第三个得到母串。最短母串的获得可通过hash值是否相同判断是否重叠部分可行,预处理出每个前缀的hash值。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef unsigned long long ULL; // 溢出相当于取模 16 | 17 | char s[5][300010]; 18 | ULL h[2][200010]; 19 | ULL bs[100010]; 20 | 21 | const ULL B = 100000007ull; 22 | 23 | void InitHash(char *s, int len, ULL *h) { 24 | h[0] = 0; 25 | for (int i = 1; i <= len; ++i) { 26 | h[i] = h[i - 1] * B + s[i - 1]; 27 | } 28 | } 29 | 30 | ULL Hash(ULL *h, int b, int len) { 31 | return h[b + len] - h[b] * bs[len]; 32 | } 33 | 34 | void Gao(char *s0, char *s1, char *s2) { 35 | int l0, l1, l2; 36 | l0 = (int)strlen(s0); 37 | l1 = (int)strlen(s1); 38 | InitHash(s0, l0, h[0]); 39 | InitHash(s1, l1, h[1]); 40 | int ol = 0; 41 | for (int i = 0; i < l0; ++i) { 42 | int to = min(l0 - i, l1); 43 | if (Hash(h[0], i, to) == Hash(h[1], 0, to)) { 44 | ol = to; 45 | break; 46 | } 47 | } 48 | l2 = 0; 49 | for (int i = 0; i < l0; ++i) { 50 | s2[l2++] = s0[i]; 51 | } 52 | for (int i = ol; i < l1; ++i) { 53 | s2[l2++] = s1[i]; 54 | } 55 | s2[l2] = 0; 56 | } 57 | 58 | int main() { 59 | int ans = 300000; 60 | bs[0] = 1; 61 | for (int i = 1; i <= 100000; ++i) { 62 | bs[i] = bs[i - 1] * B; 63 | } 64 | scanf("%s%s%s", s[0], s[1], s[2]); 65 | int order[] = {0, 1, 2}; 66 | do { 67 | Gao(s[order[0]], s[order[1]], s[3]); 68 | Gao(s[order[2]], s[3], s[4]); 69 | ans = min(ans, (int)strlen(s[4])); 70 | } while (next_permutation(order, order + 3)); 71 | printf("%d\n", ans); 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /src/cf86c.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * CF 86C: Genetic Engineering 3 | * 题意:给出若干基因串作为字典,求长度为n且可由字典中的串完全可重叠覆盖的母串有多少种。 4 | * 类型:DP(/AC自动机) 5 | * 算法:所有前缀作为状态,预处理出通过在状态i最后添加某个基因字符转移到的长度最长的状态j,同时预处理出每个状态的后缀可以覆盖的最长的完整字典串。d[i][j][k]表示生成长为i的串且当前后缀匹配的最长状态为j时,最后有k个无法匹配字符的不同的母串数。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | const int MOD = 1000000009; 18 | 19 | string rule[11]; 20 | string prefix[110]; 21 | int maxrule[110]; 22 | int t[110][4]; 23 | 24 | char dic[] = {'A', 'C', 'G', 'T'}; 25 | 26 | int n, m, np; 27 | 28 | int d[1010][110][11]; 29 | 30 | void GaoDic() { 31 | for (int i = 0; i < np; ++i) { 32 | for (int j = 0; j < m; ++j) { 33 | if (prefix[i].length() >= rule[j].length() && 34 | prefix[i].substr(prefix[i].length() - rule[j].length()) == rule[j]) { 35 | maxrule[i] = max(maxrule[i], (int) rule[j].length()); 36 | } 37 | } 38 | } 39 | } 40 | 41 | void GaoEdge() { 42 | for (int i = 0; i < np; ++i) { 43 | for (int k = 0; k < 4; ++k) { 44 | string ts = prefix[i] + dic[k]; 45 | for (int j = 0; j < np; ++j) { 46 | if (ts.length() >= prefix[j].length() && ts.substr(ts.length() - prefix[j].length()) == prefix[j] && 47 | prefix[j].length() > prefix[t[i][k]].length()) { 48 | t[i][k] = j; 49 | } 50 | } 51 | } 52 | } 53 | } 54 | 55 | void DP() { 56 | d[0][0][0] = 1; 57 | for (int i = 0; i < n; ++i) { 58 | for (int j = 0; j < np; ++j) { 59 | for (int k = 0; k <= prefix[j].length(); ++k) { 60 | if (!d[i][j][k]) continue; 61 | for (int c = 0; c < 4; ++c) { 62 | int nj = t[j][c]; 63 | if (maxrule[nj] >= k + 1) { 64 | d[i + 1][nj][0] = (d[i + 1][nj][0] + d[i][j][k]) % MOD; 65 | } else if (k + 1 <= prefix[nj].length()) { 66 | d[i + 1][nj][k + 1] = (d[i + 1][nj][k + 1] + d[i][j][k]) % MOD; 67 | } 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | int main() { 75 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 76 | prefix[np++] = ""; 77 | cin >> n >> m; 78 | for (int i = 0; i < m; ++i) { 79 | cin >> rule[i]; 80 | for (int j = 1; j <= rule[i].length(); ++j) { 81 | prefix[np++] = rule[i].substr(0, j); 82 | } 83 | } 84 | sort(prefix, prefix + np); 85 | np = unique(prefix, prefix + np) - prefix; 86 | 87 | GaoDic(); 88 | 89 | GaoEdge(); 90 | 91 | DP(); 92 | int ans = 0; 93 | for (int i = 0; i < np; ++i) { 94 | ans = (ans + d[n][i][0]) % MOD; 95 | } 96 | cout << ans << endl; 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /src/cf97b.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * CF 97B: Superset 3 | * 题意:给出平面上n个不同的点,求该点集的一个超集,使得集合内任意两点:同x,或同y,或构成的矩形包含其他点。(Special Judge不要求添加点最少) 4 | * 类型:平面分治 5 | * 算法:将点集按x排序,选取中间点划竖线,将所有点投影到该线上,并添加到答案set里。此时被线分开的左右两边的点互相可以满足条件2或3,接下来需要使它们内部也能互相满足,则问题分治到左右两侧平面的子问题。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef pair pii; 16 | 17 | pii a[10010]; 18 | set b; 19 | 20 | void divide(int l, int r) { 21 | if (l + 1 >= r) return; 22 | int m = (l + r) >> 1; 23 | int x = a[m].first; 24 | for (int i = l; i < r; ++i) { 25 | b.insert(make_pair(x, a[i].second)); 26 | } 27 | divide(l, m); 28 | divide(m + 1, r); 29 | } 30 | 31 | int main() { 32 | int n; 33 | scanf("%d", &n); 34 | for (int i = 0; i < n; ++i) { 35 | scanf("%d%d", &a[i].first, &a[i].second); 36 | b.insert(a[i]); 37 | } 38 | sort(a, a + n); 39 | divide(0, n); 40 | printf("%d\n", int(b.size())); 41 | for (auto &i: b) { 42 | printf("%d %d\n", i.first, i.second); 43 | } 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /src/gcj2011b.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * GCJ 2011 Final B: Bacterial Reproduction 3 | * 题意:x个细菌一小时后繁殖为x^x个,求A个细菌B小时后的数量模C。 4 | * 类型:数论 5 | * 算法:d(n,m)=(d(n-1)%m)^d(n-1),次幂对结果有循环节,所以先预处理出所有d(n,m)的循环节。如果次幂是否在循环头,则直接求;否则次幂为d(n-1,loop)。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | typedef long long LL; 15 | 16 | int a[1010]; 17 | int d[1010][1010]; 18 | int h[1010][1010]; 19 | int l[1010][1010]; 20 | int vis[1010]; 21 | 22 | int A, B, C; 23 | 24 | void InitLoop() { 25 | for (int i = 1; i <= 1000; ++i) { 26 | for (int j = 1; j <= 1000; ++j) { 27 | memset(vis, -1, sizeof(vis)); 28 | int a = 1; 29 | int step = 0; 30 | while (1) { 31 | a = a * i % j; 32 | if (vis[a] != -1) { 33 | h[i][j] = vis[a]; 34 | l[i][j] = step - vis[a]; 35 | break; 36 | } 37 | vis[a] = step++; 38 | } 39 | } 40 | } 41 | } 42 | 43 | int Power(int a, int b) { 44 | if (b == 0) return 1; 45 | int ans = 1; 46 | while (b) { 47 | if (b & 1) { 48 | ans = min(1111, ans * a); 49 | } 50 | a = min(1111, a * a); 51 | b >>= 1; 52 | } 53 | return ans; 54 | } 55 | 56 | int Power(int a, int b, int mod) { 57 | if (b == 0) return 1; 58 | if (mod == 1) return 0; 59 | int ans = 1; 60 | while (b) { 61 | if (b & 1) { 62 | ans = ans * a % mod; 63 | } 64 | a = a * a % mod; 65 | b >>= 1; 66 | } 67 | return ans; 68 | } 69 | 70 | void InitTable() { 71 | a[0] = A; 72 | for (int i = 1; i <= B; ++i) { 73 | a[i] = Power(a[i - 1], a[i - 1]); 74 | } 75 | } 76 | 77 | int Gao(int A, int B, int C) { 78 | if (B == 0) return A % C; 79 | if (C == 1) return 0; 80 | if (d[B][C] != -1) { 81 | return d[B][C]; 82 | } 83 | int x = Gao(A, B - 1, C); 84 | if (a[B - 1] <= 1000) { 85 | return d[B][C] = Power(x, a[B - 1], C); 86 | } 87 | int y = Gao(A, B - 1, l[x][C]); 88 | y = ((y - (h[x][C] + 1)) % l[x][C] + l[x][C]) % l[x][C] + h[x][C] + 1; 89 | return d[B][C] = Power(x, y, C); 90 | } 91 | 92 | int main() { 93 | int T; 94 | InitLoop(); 95 | scanf("%d", &T); 96 | for (int tc = 1; tc <= T; ++tc) { 97 | memset(d, -1, sizeof(d)); 98 | scanf("%d%d%d", &A, &B, &C); 99 | InitTable(); 100 | printf("Case #%d: %d\n", tc, Gao(A, B, C)); 101 | } 102 | return 0; 103 | } -------------------------------------------------------------------------------- /src/poj1011.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1011: Sticks 3 | * 题意:若干长度相同的棍子剪成若干节,给出剪完的结果,求原本完整棍子的最小长度。 4 | * 类型:DFS 5 | * 算法:候选长度一定大于等于最大的木棍节,并且为所有木棍长度和的约数。依次枚举待选解,DFS判断是否可行。DFS时将木棍从长到短排列,每次第一个没取的必须取。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | using namespace std; 14 | 15 | int a[70]; 16 | int len; 17 | int n; 18 | int m; 19 | bool vis[70]; 20 | 21 | bool dfs(int b, int cur, int cnt) { 22 | if (cur == len) { 23 | ++cnt; 24 | if (cnt == m) { 25 | return 1; 26 | } else { 27 | for (int i = 0; i < n; ++i) { 28 | if (!vis[i]) { 29 | vis[i] = 1; 30 | if (dfs(i + 1, a[i], cnt)) { 31 | return 1; 32 | } else { 33 | vis[i] = 0; 34 | return 0; 35 | } 36 | } 37 | } 38 | } 39 | } else { 40 | 41 | for (int i = b; i < n; ++i) { 42 | if (vis[i] || cur + a[i] > len || (i && !vis[i - 1] && a[i] == a[i - 1])) continue; // 重要剪枝:和前一个相同,前一个使用无效,则当前也会无效 43 | vis[i] = 1; 44 | 45 | if (dfs(i + 1, cur + a[i], cnt)) { 46 | return 1; 47 | } 48 | vis[i] = 0; 49 | } 50 | } 51 | return 0; 52 | } 53 | 54 | int main() { 55 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 56 | int s; 57 | while (scanf("%d", &n) != EOF && n) { 58 | s = 0; 59 | for (int i = 0; i < n; ++i) { 60 | scanf("%d", &a[i]); 61 | s += a[i]; 62 | } 63 | sort(a, a + n); 64 | reverse(a, a + n); 65 | 66 | int ans = s; 67 | for (len = a[0]; len < s; ++len) { 68 | if (s % len) continue; 69 | memset(vis, 0, sizeof(vis)); 70 | m = s / len; 71 | vis[0] = 1; 72 | if (dfs(1, a[0], 0)) { 73 | ans = len; 74 | break; 75 | } 76 | } 77 | printf("%d\n", ans); 78 | } 79 | return 0; 80 | } -------------------------------------------------------------------------------- /src/poj1017.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1017: Packets 3 | * 题意:给出边长为1~6的正方形若干,求用最少的边长为6的正常形装下他们。 4 | * 类型:贪心 5 | * 算法:先放边长为6~3的,计算之前边角可以放多少边长2的,放完边长为2的,用面积计算之前空余多少边长1的,最后放1。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int main() { 14 | int a, b, c, d, e, f; 15 | int t[] = {0, 5, 3, 1}; 16 | while(scanf("%d%d%d%d%d%d", &a, &b, &c, &d, &e, &f) != EOF) { 17 | if(!a && !b && !c && !d && !e && !f) break; 18 | int ans = f + e + d + (c + 3) / 4; 19 | int two = 5 * d + t[c % 4]; 20 | if(b > two) { 21 | ans += (b - two + 8) / 9; 22 | } 23 | int one = ans * 36 - f * 36 - e * 25 - d * 16 - c * 9 - b * 4; 24 | if(a > one) { 25 | ans += (a - one + 35) / 36; 26 | } 27 | printf("%d\n", ans); 28 | } 29 | return 0; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/poj1065.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1065: Wooden Sticks 3 | * 题意:已知一堆木棍的长宽,启动一般的木棍需要1分钟,若该木棍长宽都不小于某已启动木棍,则替换原木棍并不需时间。求启动所有木棍的最短时间。 4 | * 类型:DP+贪心 5 | * 算法:将长宽转化为二维向量的点,每段斜率都非负的折线需要1分钟。多段折线互不相交,且最高点依次下降,折线条数转化为最高点组成的最长降序。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef pair pii; 16 | pii s[5010]; 17 | int d[5010]; 18 | 19 | int main() { 20 | int T, n, i, j; 21 | scanf("%d", &T); 22 | while(T--) { 23 | scanf("%d", &n); 24 | for(i = 0; i < n; ++i) { 25 | scanf("%d%d", &s[i].first, &s[i].second); 26 | } 27 | sort(s, s + n); 28 | int ans = 0; 29 | for(i = 0; i < n; ++i) { 30 | d[i] = 1; 31 | for(j = 0; j < i; ++j) { 32 | if(s[i].second < s[j].second) { 33 | d[i] = max(d[i], d[j] + 1); 34 | } 35 | } 36 | ans = max(ans, d[i]); 37 | } 38 | printf("%d\n", ans); 39 | } 40 | return 0; 41 | } -------------------------------------------------------------------------------- /src/poj1082.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1082: Calendar Game 3 | * 题意:随机给出一个日期,它每次只能转移到下一天或下一个月的同一天(不存在则不转),最终达到比赛日期则为胜者。问先手的胜负。 4 | * 类型:NP博弈 5 | * 算法:比赛日期为必败态,倒着转移。从每个必败态出发,将上一天或上个月同一天(若存在)标记为必胜态。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int dp[37500]; 14 | 15 | int md[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 16 | int rmd[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 17 | int sum[13]; 18 | int rsum[13]; 19 | 20 | bool isrun(int y) { 21 | if (y % 400 == 0 || (y % 100 && y % 4 == 0)) return true; 22 | return false; 23 | } 24 | 25 | bool valid(int y, int m, int d) { 26 | if (y < 1900) return -1; 27 | if (isrun(y)) return d <= rmd[m]; 28 | return d <= md[m]; 29 | } 30 | 31 | int s2i(int y, int m, int d) { 32 | if (!valid(y, m, d)) { 33 | return -1; 34 | } 35 | int x = 0; 36 | if (y > 1900) { 37 | x += 365; 38 | x += (y - 1901) / 4 * 1461 + (y - 1901) % 4 * 365; 39 | } 40 | 41 | if (isrun(y)) { 42 | x += rsum[m - 1] + d; 43 | } else { 44 | x += sum[m - 1] + d; 45 | } 46 | return x; 47 | } 48 | 49 | 50 | void i2s(int x, int &y, int &m, int &d) { 51 | if (x <= 365) { 52 | y = 1900; 53 | } else { 54 | x -= 365; 55 | y = 1901 + 4 * (x / 1461); 56 | x %= 1461; 57 | } 58 | y += x / 365; 59 | x %= 365; 60 | if (x == 0) { 61 | --y; 62 | m = 12; 63 | d = 31; 64 | return; 65 | } 66 | 67 | if (isrun(y)) { 68 | m = int(lower_bound(rsum, rsum + 13, x) - rsum); 69 | d = x - rsum[m - 1]; 70 | } else { 71 | m = int(lower_bound(sum, sum + 12, x) - sum); 72 | d = x - sum[m - 1]; 73 | } 74 | } 75 | 76 | int pre_month(int x) { 77 | int y, m, d; 78 | i2s(x, y, m ,d); 79 | --m; 80 | if (m == 0) { 81 | m = 12; 82 | --y; 83 | } 84 | return s2i(y, m, d); 85 | } 86 | 87 | int main() { 88 | int T; 89 | scanf("%d", &T); 90 | int y, m, d; 91 | for (int i = 1; i <= 12; ++i) { 92 | sum[i] = sum[i - 1] + md[i]; 93 | rsum[i] = rsum[i - 1] + rmd[i]; 94 | } 95 | 96 | 97 | for (int i = s2i(2001, 11, 4); i >= 1; --i) { 98 | if (dp[i] == 0) { 99 | dp[i - 1] = 1; 100 | int x = pre_month(i); 101 | if (x > 0) dp[x] = 1; 102 | } 103 | } 104 | while (T--) { 105 | scanf("%d%d%d", &y, &m, &d); 106 | int x = s2i(y, m, d); 107 | if(dp[x] == 0) { 108 | printf("NO\n"); 109 | } else { 110 | printf("YES\n"); 111 | } 112 | } 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /src/poj1150.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1150: The Last Non-zero Digit 3 | * 题意:求排列数A(n,m)最后的非0位是什么数字。 4 | * 类型:数论 5 | * 算法:找到(n-m,n]的乘积里有多少2和5次幂,定义fn为n去除以其中所有的2和5因子。求f1*f2*...*fn中个位数各有多少个,其中偶数又可以通过除以2归结到奇数有多少个,所以关键在于求出3、7、9结尾的有多少个。而3、7、9结尾的奇数fn又可以通过除5归结到下一个阶段。 6 | */ 7 | 8 | 9 | #include 10 | 11 | int CountFactor(int n, int a) { 12 | int ans = 0; 13 | while (n) { 14 | ans += n / a; 15 | n /= a; 16 | } 17 | return ans; 18 | } 19 | 20 | int CountLastOdd(int n, int a) { 21 | if (!n) return 0; 22 | return n / 10 + (n % 10 >= a) + CountLastOdd(n / 5, a); 23 | } 24 | 25 | int CountLast(int n, int a) { 26 | if (!n) return 0; 27 | return CountLast(n / 2, a) + CountLastOdd(n, a); 28 | } 29 | 30 | int PowLast(int a, int b) { 31 | b %= 4; // 3,7,9,2的幂循环周期都为4或4的因子 32 | if (!b) b = 4; // 2的4次幂不等于0次幂 33 | int ans = 1; 34 | while (b--) ans *= a; 35 | return ans % 10; 36 | } 37 | 38 | int main() { 39 | int n, m; 40 | 41 | while (scanf("%d%d", &n, &m) != EOF) { 42 | int b = n - m; 43 | int two = CountFactor(n, 2) - CountFactor(b, 2); 44 | int five = CountFactor(n, 5) - CountFactor(b, 5); 45 | 46 | if (five > two) { 47 | printf("5\n"); 48 | continue; 49 | } 50 | 51 | int three = CountLast(n, 3) - CountLast(b, 3); 52 | int seven = CountLast(n, 7) - CountLast(b, 7); 53 | int nine = CountLast(n, 9) - CountLast(b, 9); 54 | 55 | int ans = 1; 56 | if (two > five) ans *= PowLast(2, two - five); 57 | ans *= PowLast(3, three); 58 | ans *= PowLast(7, seven); 59 | ans *= PowLast(9, nine); 60 | 61 | printf("%d\n", ans % 10); 62 | } 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /src/poj1180.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1180: Batch Scheduling 3 | * 题意:多个进程有各自的运行时间和等待代价系数,将其有序切分到多个处理器里,每个处理器依次处理,启动时间为s。一个进程的代价等于它的系数乘以它所在处理器完成其上所有任务闭的时间点。求最小代价。 4 | * 类型:斜率DP+双端队列 5 | * 算法:di表示从i到最后的最小花费,预处理从i到最后的累加时间和累加代价系数为ti和ci。di=min{(s+ti-tj)*ci+dj,i 9 | 10 | using namespace std; 11 | 12 | int t[10010], c[10010]; 13 | int d[10010]; 14 | 15 | struct Line { 16 | int a, b; 17 | Line() {} 18 | Line(int aa, int bb) : a(aa), b(bb) {} 19 | }; 20 | 21 | bool useless(const Line &l1, const Line &l2, const Line &l3) { 22 | return (l2.a - l1.a) * (l3.b - l2.b) >= (l3.a - l2.a) * (l2.b - l1.b); 23 | } 24 | 25 | Line q[10010]; // use array instead of deque, because we need 2 elements either from head or tail at the same time 26 | 27 | int foo(const Line& l, int x) { 28 | return l.a * x + l.b; 29 | } 30 | 31 | 32 | int main() { 33 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 34 | int n, s; 35 | int begin, end; 36 | begin = end = 0; 37 | scanf("%d%d", &n, &s); 38 | t[n] = c[n] = 0; 39 | for (int i = 0; i < n; ++i) { 40 | scanf("%d%d", &t[i], &c[i]); 41 | } 42 | for (int i = n - 1; i >= 0; --i) { 43 | t[i] += t[i + 1]; 44 | c[i] += c[i + 1]; 45 | } 46 | q[0] = Line(0, 0); 47 | ++end; 48 | for (int i = n - 1; i >= 0; --i) { 49 | while (end - begin > 1 && foo(q[begin], c[i]) >= foo(q[begin + 1], c[i])) { 50 | ++begin; 51 | } 52 | d[i] = (s + t[i]) * c[i] + foo(q[begin], c[i]); 53 | // printf("%d : %d %d %d\n", i, d[i], (s + t[i]) * c[i], foo(q[begin], c[i])); 54 | while (end - begin > 1 && useless(q[end - 2], q[end - 1], Line(-t[i], d[i]))) { 55 | --end; 56 | } 57 | q[end++] = Line(-t[i], d[i]); 58 | } 59 | printf("%d\n", d[0]); 60 | return 0; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/poj1201.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1201: Intervals 3 | * 题意:给出n个区间,每个区间对应一个个数阈值ci。构造集合,使得它与每个区间的交集不小于ci个。求集合的最小有多少个元素。 4 | * 类型:贪心+线段树+二分(/差分约束) 5 | * 算法:区间按右端点排序。利用线段树懒惰标记,将段内已选数的个数更新或求和。根据贪心每次应从右端点向左添加一段前缀。遍历区间时,二分线段树求到的和以得到左端点,再将后缀放入线段树更新。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | const int MAXN = 50010; 15 | const int MAXM = 1 << 17; 16 | 17 | #define lchild rt << 1, l, m, ql, qr 18 | #define rchild rt << 1 | 1, m + 1, r, ql, qr 19 | 20 | int sum[MAXM], lazy[MAXM]; 21 | 22 | void down(int rt, int l, int r, int m) { 23 | if (lazy[rt]) { 24 | lazy[rt << 1] = 1; 25 | lazy[rt << 1 | 1] = 1; 26 | sum[rt << 1] = m - l + 1; 27 | sum[rt << 1 | 1] = r - m; 28 | lazy[rt] = 0; 29 | } 30 | } 31 | 32 | void up(int rt) { 33 | sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; 34 | } 35 | 36 | void update(int rt, int l, int r, int ql, int qr) { 37 | if (ql <= l && r <= qr) { 38 | lazy[rt] = 1; 39 | sum[rt] = r - l + 1; 40 | return; 41 | } 42 | int m = (l + r) >> 1; 43 | down(rt, l, r, m); 44 | if (ql <= m) { 45 | update(lchild); 46 | } 47 | if (qr > m) { 48 | update(rchild); 49 | } 50 | up(rt); 51 | } 52 | 53 | int query(int rt, int l, int r, int ql, int qr) { 54 | if (ql <= l && r <= qr) { 55 | return sum[rt]; 56 | } 57 | int ans = 0; 58 | int m = (l + r) >> 1; 59 | down(rt, l, r, m); 60 | if (ql <= m) { 61 | ans += query(lchild); 62 | } 63 | if (qr > m) { 64 | ans += query(rchild); 65 | } 66 | return ans; 67 | } 68 | 69 | struct Seg { 70 | int a, b, c; 71 | 72 | bool operator<(const Seg &s) const { 73 | return b < s.b; 74 | } 75 | } seg[MAXN]; 76 | 77 | int main() { 78 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 79 | int n; 80 | scanf("%d", &n); 81 | for (int i = 0; i < n; ++i) { 82 | scanf("%d%d%d", &seg[i].a, &seg[i].b, &seg[i].c); 83 | } 84 | sort(seg, seg + n); 85 | int ans = 0; 86 | for (int i = 0; i < n; ++i) { 87 | int &a = seg[i].a; 88 | int &b = seg[i].b; 89 | int &c = seg[i].c; 90 | int need = c - query(1, 0, 50000, a, b); 91 | if (need > 0) { 92 | ans += need; 93 | int l, r, m, t; 94 | l = a; 95 | r = b + 1; 96 | while (l + 1 < r) { 97 | m = (l + r) >> 1; 98 | t = b - m + 1 - query(1, 0, 50000, m, b); 99 | if (t >= need) { 100 | l = m; 101 | } else { 102 | r = m; 103 | } 104 | } 105 | update(1, 0, 50000, l, b); 106 | } 107 | } 108 | printf("%d\n", ans); 109 | return 0; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /src/poj1222.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1222: EXTENDED LIGHTS OUT 3 | * 题意:5x6的01矩阵,反转一个数会将上下左右也同时反转。求 4 | * 类型:位运算+贪心(/高斯消元) 5 | * 算法:枚举首列反转动作的二进制表示,当某行及之前的反转动作确定后,当前灯的状态只能由下一列对应行的动作改变,故可推导出之后所有列的动作。 6 | */ 7 | 8 | #include 9 | 10 | int a[6][7], b[7][8]; 11 | 12 | int main() { 13 | int T, tc = 0; 14 | scanf("%d", &T); 15 | while (T--) { 16 | for (int i = 1; i <= 5; ++i) 17 | for (int j = 1; j <= 6; ++j) 18 | scanf("%d", &a[i][j]); 19 | for (int k = (1 << 5) - 1; k >= 0; --k) { 20 | int t = k; 21 | for (int i = 1; i <= 5; ++i) { 22 | b[i][1] = t & 1; 23 | t >>= 1; 24 | } 25 | for (int j = 2; j <= 7; ++j) 26 | for (int i = 1; i <= 5; ++i) 27 | b[i][j] = a[i][j - 1] ^ b[i][j - 1] ^ b[i - 1][j - 1] ^ b[i + 1][j - 1] ^ b[i][j - 2]; 28 | 29 | bool ok = true; 30 | for (int i = 1; i <= 5; ++i) { 31 | if (b[i][7]) { 32 | ok = false; 33 | break; 34 | } 35 | } 36 | if (ok) break; 37 | } 38 | 39 | printf("PUZZLE #%d\n", ++tc); 40 | for (int i = 1; i <= 5; ++i) { 41 | for (int j = 1; j < 6; ++j) { 42 | printf("%d ", b[i][j]); 43 | } 44 | printf("%d\n", b[i][6]); 45 | } 46 | } 47 | return 0; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/poj1236.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1236: Network of Schools 3 | * 题意:给n个可连通的学校装软件,每个学校有自己的传输下继。求最少给多少个学校发送首批软件,经过若干次传输拷贝后所有学校最终都可以得到。另外还要求当随机某点已有软件时,还需要在传输下继名单增加多少个学校。 4 | * 类型:强连通分量 5 | * 算法:用2次DFS进行强连通分量分解,缩点得到有向无环图。第1次DFS时选取任意未访问结点,回溯时顺序标号。第2次DFS时先将图中边反向,每次从未遍历的标号最大的点出发。得到DAG后,入度为0的点数为答案1。由于将入度为0的点和出度为0的点连接可使得DAG变为SCC,所以将出度和入度为0的点数的更大者为答案2。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | vector e[110]; 16 | vector re[110]; 17 | vector id; 18 | 19 | int tot; 20 | int tp[110]; 21 | 22 | bool vis[110]; 23 | bool mat[110][110]; 24 | 25 | int in[110], out[110]; 26 | 27 | 28 | void Dfs(int i) { 29 | vis[i] = 1; 30 | for (vector::iterator it = e[i].begin(); it != e[i].end(); ++it) { 31 | if (!vis[*it]) { 32 | Dfs(*it); 33 | } 34 | } 35 | id.push_back(i); 36 | } 37 | 38 | void RDfs(int i) { 39 | vis[i] = 1; 40 | tp[i] = tot; 41 | for (vector::iterator it = re[i].begin(); it != re[i].end(); ++it) { 42 | if (!vis[*it]) { 43 | RDfs(*it); 44 | } 45 | } 46 | } 47 | 48 | int main() { 49 | int n; 50 | scanf("%d", &n); 51 | for (int i = 1; i <= n; ++i) { 52 | int j; 53 | while (scanf("%d", &j) != EOF && j) { 54 | e[i].push_back(j); 55 | re[j].push_back(i); 56 | } 57 | } 58 | 59 | memset(vis, 0, sizeof(vis)); 60 | for (int i = 1; i <= n; ++i) { 61 | if (!vis[i]) Dfs(i); 62 | } 63 | 64 | memset(vis, 0, sizeof(vis)); 65 | for (vector::iterator it = id.end() - 1; it >= id.begin(); --it) { 66 | if (!vis[*it]) { 67 | RDfs(*it); 68 | ++tot; 69 | } 70 | } 71 | 72 | if (tot == 1) { 73 | printf("1\n0\n"); // 只有1个scc时特判 74 | return 0; 75 | } 76 | 77 | for (int i = 1; i <= n; ++i) { 78 | int t = tp[i]; 79 | for (vector::iterator it = e[i].begin(); it != e[i].end(); ++it) { 80 | int s = tp[*it]; 81 | if (t != s && !mat[t][s]) { 82 | ++out[t]; 83 | ++in[s]; 84 | mat[t][s] = 1; 85 | } 86 | } 87 | } 88 | 89 | int ans1, ans2; 90 | ans1 = ans2 = 0; 91 | for (int i = 0; i < tot; ++i) { 92 | if (in[i] == 0) { 93 | ++ans1; 94 | } 95 | if (out[i] == 0) { 96 | ++ans2; 97 | } 98 | } 99 | 100 | printf("%d\n%d\n", ans1, max(ans1, ans2)); 101 | 102 | return 0; 103 | } 104 | -------------------------------------------------------------------------------- /src/poj1258.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1258: Agri-Net 3 | * 题意:给出邻接矩阵,选出部分边,使得整个图连通。求边的最小总花费。 4 | * 类型:最小生成树 5 | * 算法:本题为稠密图,Prim算法求最小生成树更优,复杂度O(n^2)。(/Kruskal算法亦可) 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int mat[110][110]; 15 | bool vis[110]; 16 | int d[110]; 17 | 18 | int Prim(int n) { 19 | int ans = 0; 20 | int p = 0; 21 | vis[0] = 1; 22 | for(int j = 1; j < n; ++j) { 23 | d[j] = mat[p][j]; 24 | } 25 | for(int i = 1; i < n; ++i) { 26 | p = -1; 27 | for(int j = 1; j < n; ++j) { 28 | if(vis[j]) continue; 29 | if(p == -1 || d[j] < d[p]) { 30 | p = j; 31 | } 32 | } 33 | ans += d[p]; 34 | vis[p] = 1; 35 | for(int j = 1; j < n; ++j) { 36 | if(vis[j]) continue; 37 | d[j] = min(d[j], mat[p][j]); 38 | } 39 | } 40 | return ans; 41 | } 42 | 43 | int main() { 44 | int n, i, j; 45 | while(scanf("%d", &n) != EOF) { 46 | memset(vis, 0, sizeof(vis)); 47 | for(i = 0; i < n; ++i) { 48 | for(j = 0; j < n; ++j) { 49 | scanf("%d", &mat[i][j]); 50 | } 51 | } 52 | int ans = Prim(n); 53 | printf("%d\n", ans); 54 | } 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /src/poj1274.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1274: The Perfect Stall 3 | * 题意:每头牛有自己偏爱的牛栏列表,每个牛栏只能放一头牛。求可以被满足的牛的最大数量。 4 | * 类型:二分匹配 5 | * 算法:牛的点在左侧,牛栏的点在右侧,用偏爱关系建邻接矩阵。匈牙利算法递归求解最大二分匹配。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | bool e[210][210]; 14 | bool vis[210]; 15 | int rec[210]; 16 | int n1, n2; 17 | 18 | bool Dfs(int u) { 19 | for (int i = 1; i <= n2; ++i) { 20 | if (e[u][i] && !vis[i]) { 21 | vis[i] = 1; 22 | if (rec[i] == -1 || Dfs(rec[i])) { 23 | rec[i] = u; 24 | return true; 25 | } 26 | } 27 | } 28 | return false; 29 | } 30 | 31 | int Hungary() { 32 | int ans = 0; 33 | for (int i = 1; i <= n1; ++i) { 34 | memset(vis, 0, sizeof(vis)); 35 | if (Dfs(i)) ++ans; 36 | } 37 | return ans; 38 | } 39 | 40 | int main() { 41 | while (scanf("%d%d", &n1, &n2) != EOF) { 42 | memset(e, 0, sizeof(e)); 43 | memset(rec, -1, sizeof(rec)); 44 | for (int i = 1; i <= n1; ++i) { 45 | int t, j; 46 | scanf("%d", &t); 47 | while (t--) { 48 | scanf("%d", &j); 49 | e[i][j] = 1; 50 | } 51 | } 52 | printf("%d\n", Hungary()); 53 | } 54 | return 0; 55 | } -------------------------------------------------------------------------------- /src/poj1284.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1284: Primitive Roots 3 | * 题意:给出一个素数,求它的原根个数。 4 | * 类型:数论 5 | * 算法:原根定理,如果p有原根(形如2/4/p^x/2*p^x),则它恰有φ(φ(p))个不同的原根。因为p是素数,所以p的原根个数为φ(p-1)。用筛法预处理出所有欧拉函数的值。 6 | */ 7 | 8 | 9 | #include 10 | 11 | 12 | int p[20000]; 13 | bool np[65555]; 14 | int f[65555]; 15 | int cnt; 16 | 17 | void Sieve(int m = 65536) { 18 | for (int i = 2; i <= m; ++i) { 19 | if (!np[i]) { 20 | p[cnt++] = i; 21 | f[i] = i - 1; 22 | } 23 | long long t; 24 | for (int j = 0; j < cnt && (t = 1ll * i * p[j]) <= m; ++j) { 25 | np[t] = 1; 26 | if (i % p[j] == 0) { 27 | f[t] = f[i] * p[j]; 28 | break; 29 | } else { 30 | f[t] = f[i] * (p[j] - 1); 31 | } 32 | } 33 | } 34 | } 35 | 36 | 37 | int main() { 38 | Sieve(); 39 | int n; 40 | while (scanf("%d", &n) != EOF) { 41 | printf("%d\n", f[n - 1]); 42 | } 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /src/poj1286.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1286: Necklace of Beads 3 | * 题意:三种颜色的珠子串称一定长度的链子,翻转或旋转后重合的视为同一种,求共有多少种不同的。 4 | * 类型:Pólya计数 5 | * 算法:L=|1/G|*(m^c(p1)+m^c(p2)+...+m^c(pk))。G为置换群,m为颜色,c(pi)表示第i个置换的循环节数。同时考虑翻转和旋转,置换群大小为2n。旋转i的循环节个数为gcd(n,i)。翻转时按奇偶讨论,n为奇数时为1+(n-1)/2,共n条对称轴;偶数时对称轴分过不过珠子两种,各n/2种情况,循环节分别为(n-2)/2+2+1和n/2。 6 | */ 7 | 8 | 9 | #include 10 | 11 | typedef long long LL; 12 | 13 | LL Gcd(LL a, LL b) { 14 | for (LL t; t = b;) { 15 | b = a % b; 16 | a = t; 17 | } 18 | return a; 19 | } 20 | 21 | LL Pow(LL a, LL b) { 22 | LL ans = 1; 23 | while (b--) ans *= a; 24 | return ans; 25 | } 26 | 27 | int main() { 28 | LL n; 29 | while (scanf("%lld", &n) != EOF && n != -1) { 30 | if (n == 0) { 31 | printf("0\n"); 32 | continue; 33 | } 34 | 35 | LL ans = 0; 36 | 37 | // rotation 38 | for (LL i = 0; i < n; ++i) { 39 | ans += Pow(3, Gcd(n, i)); 40 | } 41 | 42 | // reflection 43 | if (n & 1) { 44 | ans += n * Pow(3, n / 2 + 1); 45 | } else { 46 | ans += n / 2 * (Pow(3, n / 2 + 1) + Pow(3, n / 2)); 47 | } 48 | 49 | ans /= 2 * n; 50 | printf("%lld\n", ans); 51 | } 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /src/poj1328.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1328: Radar Installation 3 | * 题意:给出海面上n个岛的坐标,在x轴上放置半径为d的雷达,使得所有岛被覆盖的雷达最少数量。 4 | * 类型:贪心 5 | * 算法:以每个岛为圆心,半径为画圆,得到与x轴相交形成的区间。将完全包含其他区间的大区间标记为删除,然后按左端点排序。遍历所有区间,每次取第1个并计数+1,标记删去所有与其相交的区间。判断浮点数大小关系要用EPS。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | const double EPS = 1e-6; 17 | 18 | pair pii[1010]; 19 | 20 | bool deleted[1010]; 21 | 22 | int main() { 23 | int n, d; 24 | bool ok; 25 | int tc = 0; 26 | while(scanf("%d%d", &n, &d) != EOF && n) { 27 | ok = true; 28 | for(int i = 0; i < n; ++i) { 29 | int x, y; 30 | scanf("%d%d", &x, &y); 31 | if(y > d || y < -d) { 32 | ok = false; 33 | continue; 34 | } 35 | pii[i].first = -sqrt(d * d - y * y) + x; 36 | pii[i].second = sqrt(d * d - y * y) + x; 37 | } 38 | 39 | printf("Case %d: ", ++tc); 40 | 41 | if(!ok) { 42 | printf("-1\n"); 43 | continue; 44 | } 45 | 46 | memset(deleted, 0, sizeof(deleted)); 47 | 48 | sort(pii, pii + n); 49 | for(int i = 0; i < n; ++i) { 50 | for(int j = i + 1; j < n; ++j) { 51 | if(pii[j].second < pii[i].second + EPS) { // <= 52 | deleted[i] = true; 53 | } 54 | } 55 | } 56 | 57 | int cnt = 0, i, j; 58 | for(i = 0; i < n; ) { 59 | while(deleted[i] && i < n){ 60 | ++i; 61 | } 62 | if(i == n) break; 63 | ++cnt; 64 | for(j = i + 1; j < n; ++j) { 65 | if(pii[j].first > pii[i].second + EPS) { // > 66 | break; 67 | } 68 | } 69 | i = j; 70 | } 71 | printf("%d\n", cnt); 72 | } 73 | return 0; 74 | } -------------------------------------------------------------------------------- /src/poj1418.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1418: Viva Confetti 3 | * 题意:在平面上顺序放置多个圆,给出圆心位置和大小。某圆被其上的若干圆完全覆盖则不可见,求最终肉眼可见的圆的数量。 4 | * 类型:计算几何 5 | * 算法:若圆与其他圆相交且某部分可见,则可见部分必为相交弧围成的部分。枚举某圆,求出其他圆与它的交点后,可将该圆的弧分段。对于每段取中点向内外各移动一小段距离,覆盖这些点的最顶层圆必为可见圆。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | const double PI = acos(-1.0); 16 | const double EPS = 1e-14; 17 | 18 | double sd[] = {-EPS, EPS}; 19 | double x[110], y[110], r[110]; 20 | 21 | bool up[110]; 22 | 23 | double a[210]; 24 | 25 | double GaoDistance(double x1, double y1, double x2, double y2) { 26 | return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); 27 | } 28 | 29 | int main() { 30 | int n; 31 | while (scanf("%d", &n) != EOF && n) { 32 | memset(up, 0, sizeof(up)); 33 | for (int i = 0; i < n; ++i) { 34 | scanf("%lf%lf%lf", &x[i], &y[i], &r[i]); 35 | } 36 | int ans = 0; 37 | for (int i = 0; i < n; ++i) { 38 | int cnt = 0; 39 | for (int j = i + 1; j < n; ++j) { 40 | double d = GaoDistance(x[i], y[i], x[j], y[j]); 41 | if (d >= r[i] + r[j]) continue; 42 | if (r[i] > r[j] && d <= r[i] - r[j]) continue; 43 | if (r[j] > r[i] && d <= r[j] - r[i]) { 44 | goto L; 45 | } 46 | double slope = atan2(y[j] - y[i], x[j] - x[i]); 47 | double rotate = acos((r[i] * r[i] + d * d - r[j] * r[j]) / 2.0 / d / r[i]); 48 | double start = slope - rotate; 49 | double end = slope + rotate; 50 | a[cnt++] = start < -PI ? start + 2 * PI : start; 51 | a[cnt++] = end > PI ? end - 2 * PI : end; 52 | } 53 | 54 | if (cnt == 0) { 55 | up[i] = 1; 56 | } else { 57 | a[cnt++] = -PI; 58 | a[cnt++] = PI; 59 | sort(a, a + cnt); 60 | for (int j = 1; j < cnt; ++j) { 61 | double angle = (a[j - 1] + a[j]) / 2; 62 | double xx, yy; 63 | xx = x[i] + cos(angle) * r[i]; 64 | yy = y[i] + sin(angle) * r[i]; 65 | for (int t = 0; t < 2; ++t) { 66 | double tx, ty; 67 | tx = xx + cos(angle) * sd[t]; 68 | ty = yy + sin(angle) * sd[t]; 69 | for (int k = n - 1; k >= 0; --k) { 70 | if (GaoDistance(tx, ty, x[k], y[k]) <= r[k]) { 71 | up[k] = 1; 72 | break; 73 | } 74 | } 75 | } 76 | } 77 | } 78 | L:; 79 | } 80 | for (int i = 0; i < n; ++i) { 81 | ans += up[i]; 82 | } 83 | printf("%d\n", ans); 84 | } 85 | return 0; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /src/poj1466.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1466: Girls and Boys 3 | * 题意:学生包括男女,某些男女间存在恋爱关系,求任意两人间无恋爱关系的最大的集合。 4 | * 类型:二分匹配 5 | * 算法:二分图中,最大匹配=最小顶点覆盖数。一般图中,最小顶点覆盖数+最大独立集=顶点总数。本题因为没有给出男女,可以让每个学生和自己的副本存在二分图左右两侧,最大匹配/2即为原二分图中的最大匹配。顶点数减去原最大匹配即为所求最大独立子集。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | bool e[510][510]; 14 | bool vis[510]; 15 | int rec[510]; 16 | int n1, n2; 17 | 18 | bool Dfs(int u) { 19 | for (int i = 0; i < n2; ++i) { 20 | if (e[u][i] && !vis[i]) { 21 | vis[i] = 1; 22 | if (rec[i] == -1 || Dfs(rec[i])) { 23 | rec[i] = u; 24 | return true; 25 | } 26 | } 27 | } 28 | return false; 29 | } 30 | 31 | int Hungary() { 32 | memset(rec, -1, sizeof(rec)); 33 | int ans = 0; 34 | for (int i = 0; i < n1; ++i) { 35 | memset(vis, 0, sizeof(vis)); 36 | if (Dfs(i)) { 37 | ++ans; 38 | } 39 | } 40 | return ans; 41 | } 42 | 43 | struct Slide { 44 | int x1, x2, y1, y2; 45 | } slide[30]; 46 | 47 | int main() { 48 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 49 | int n; 50 | while (scanf("%d", &n) != EOF && n) { 51 | n1 = n2 = n; 52 | memset(e, 0, sizeof(e)); 53 | int i, j, t; 54 | for (int k = 0; k < n; ++k) { 55 | scanf("%d: (%d)", &i, &t); 56 | while (t--) { 57 | scanf("%d", &j); 58 | e[i][j] = 1; 59 | } 60 | } 61 | printf("%d\n", n - Hungary() / 2); 62 | } 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /src/poj1486.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1486: Sorting Slides 3 | * 题意:每张幻灯片上某个不定位置会有它的唯一编号,给出多个幻灯片的坐标范围和每个编号的坐标。求每张幻灯片正确对应的编号,如果编号不能唯一确定输出none。 4 | * 类型:二分匹配 5 | * 算法:根据坐标两两比较得到每张幻灯片可选的编号列表。匈牙利算法求最大二分匹配,编号在左,幻灯片在右,dfs时得到每张幻灯片的编号。为确定是否匹配唯一,可枚举第每张幻灯的编号,在图中不考虑这两个点看是否存在多次满匹配的情况。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | bool e[30][30]; 15 | bool vis[30]; 16 | int rec[30]; 17 | int n1, n2; 18 | 19 | int s, t; 20 | int ans[30]; 21 | pair out[30]; 22 | 23 | bool Dfs(int u) { 24 | for (int i = 0; i < n2; ++i) { 25 | if (i == t) continue; 26 | if (e[u][i] && !vis[i]) { 27 | vis[i] = 1; 28 | if (rec[i] == -1 || Dfs(rec[i])) { 29 | rec[i] = u; 30 | return true; 31 | } 32 | } 33 | } 34 | return false; 35 | } 36 | 37 | bool Hungary() { 38 | memset(rec, -1, sizeof(rec)); 39 | int ans = 0; 40 | for (int i = 0; i < n1; ++i) { 41 | if (i == s) continue; 42 | memset(vis, 0, sizeof(vis)); 43 | if (!Dfs(i)) return false; 44 | } 45 | return true; 46 | } 47 | 48 | struct Slide { 49 | int x1, x2, y1, y2; 50 | } slide[30]; 51 | 52 | int main() { 53 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 54 | int n; 55 | int tc = 0; 56 | while (scanf("%d", &n) != EOF && n) { 57 | n1 = n2 = n; 58 | memset(e, 0, sizeof(e)); 59 | for (int i = 0; i < n; ++i) { 60 | scanf("%d%d%d%d", &slide[i].x1, &slide[i].x2, &slide[i].y1, &slide[i].y2); 61 | } 62 | for (int i = 0; i < n; ++i) { 63 | int x, y; 64 | scanf("%d%d", &x, &y); 65 | for (int j = 0; j < n; ++j) { 66 | if (x > slide[j].x1 && x < slide[j].x2 && y > slide[j].y1 && y < slide[j].y2) { 67 | e[i][j] = 1; 68 | } 69 | } 70 | } 71 | 72 | memset(ans, -1, sizeof(ans)); 73 | for (int i = 0; i < n; ++i) { 74 | for (int j = 0 ; j < n; ++j) { 75 | if (!e[j][i]) continue; 76 | s = j; 77 | t = i; 78 | if (Hungary()) { 79 | if (ans[i] != -1) { 80 | ans[i] = -1; 81 | break; 82 | } 83 | ans[i] = j; 84 | } 85 | } 86 | } 87 | 88 | int cnt = 0; 89 | for (int i = 0; i< n; ++i) { 90 | if (ans[i] != -1) 91 | out[cnt++] = make_pair(i, ans[i]); 92 | } 93 | 94 | 95 | printf("Heap %d\n", ++tc); 96 | if (!cnt) { 97 | printf("none\n\n"); 98 | } else { 99 | for (int i = 0; i < cnt; ++i) { 100 | printf("(%c,%d)%c", 'A' + out[i].first, out[i].second + 1, i < cnt - 1 ? ' ' : '\n'); 101 | } 102 | printf("\n"); 103 | } 104 | } 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /src/poj1509.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1509: Glass Beads 3 | * 题意:给出一个循环字符串s,求字典序最小的起点下标。 4 | * 类型:后缀数组 5 | * 算法:将s和s拼接,用倍增法求后缀数组,由前一阶段的2个相邻rank得到目前的rank,直到得到长为原s长的rank停止。字典序最小的起点答案必须在第1个s内,如果排名相同选择下标小的。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | char s[20010]; 15 | int n, k; 16 | 17 | int sa[20010]; 18 | int ra[20010], tr[20010]; 19 | 20 | bool CmpSa(int a, int b) { 21 | if (ra[a] != ra[b]) return ra[a] < ra[b]; 22 | int aa = a + k < n ? ra[a + k] : -1; 23 | int bb = b + k < n ? ra[b + k] : -1; 24 | return aa < bb; 25 | } 26 | 27 | void ConstructSa() { 28 | for (int i = 0; i < n; ++i) { 29 | sa[i] = i; 30 | ra[i] = s[i]; 31 | } 32 | for (k = 1; k <= n >> 2; k <<= 1) { 33 | sort(sa, sa + n, CmpSa); 34 | tr[sa[0]] = 0; 35 | for (int i = 1; i < n; ++i) { 36 | tr[sa[i]] = tr[sa[i - 1]] + CmpSa(sa[i - 1], sa[i]); 37 | } 38 | memcpy(ra, tr, sizeof(int) * n); 39 | } 40 | } 41 | 42 | int main() { 43 | int T; 44 | scanf("%d", &T); 45 | while (T--) { 46 | scanf("%s", s); 47 | n = strlen(s); 48 | memcpy(s + n, s, sizeof(char) * n); 49 | n <<= 1; 50 | ConstructSa(); 51 | int i, ans, rk; 52 | for (i = 0;; ++i) { 53 | if (sa[i] < n >> 1) { 54 | ans = sa[i]; 55 | rk = ra[sa[i]]; 56 | break; 57 | } 58 | } 59 | for (++i; i < n && ra[sa[i]] == rk; ++i) { 60 | ans = min(ans, sa[i]); 61 | } 62 | printf("%d\n", ans + 1); 63 | } 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /src/poj1631.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1631: Bridging signals 3 | * 题意:左右两套接口一对一连线,求最多有多少条线不相交。 4 | * 类型:DP+二分 5 | * 算法:d[i]表示当前已枚举的连线中保留i条不相交线时,右侧被连端口的最高点,d严格降序。每次二分查找d中第一个小于等于的右端口的位置并更新。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include // lower_bound() 12 | 13 | using namespace std; 14 | 15 | int d[40010]; 16 | 17 | int main() { 18 | int T, n, i, j, t; 19 | scanf("%d", &T); 20 | while(T--){ 21 | scanf("%d", &n); 22 | memset(d, -1, sizeof(d)); 23 | for(i = 0; i < n; ++i) { 24 | scanf("%d", &t); 25 | t = n - t; 26 | *lower_bound(d, d + n, t, greater()) = t; // d[] <= t 27 | } 28 | int ans = int(lower_bound(d, d + n, -1, greater()) - d); 29 | printf("%d\n", ans); 30 | } 31 | return 0; 32 | } -------------------------------------------------------------------------------- /src/poj1703.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1703: Find them, Catch them 3 | * 题意:一堆人属于2个帮派,给出敌对关系。询问任意两个人是否属于同一帮派。 4 | * 类型:并查集 5 | * 算法:每个点i拆为2个点,表示i属于A和i属于B。对给出的异帮关系,连接i属于A、j属于B,i属于B、j属于A。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int fa[200010]; 14 | 15 | int find(int a) { 16 | if(a == fa[a]) { 17 | return a; 18 | } 19 | return fa[a] = find(fa[a]); 20 | } 21 | 22 | void merge(int a, int b) { 23 | fa[find(a)] = find(b); 24 | } 25 | 26 | int main() { 27 | int T, n, m, a, b; 28 | scanf("%d", &T); 29 | while(T--) { 30 | scanf("%d%d", &n, &m); 31 | for(int i = 1; i <= (n<<1); ++i) { 32 | fa[i] = i; 33 | } 34 | while(m--) { 35 | char op[3]; 36 | scanf("%s%d%d", op, &a, &b); 37 | if(op[0] == 'A') { 38 | if(find(a) == find(b)) { 39 | printf("In the same gang.\n"); 40 | } else if(find(a) == find(b + n)) { 41 | printf("In different gangs.\n"); 42 | } else { 43 | printf("Not sure yet.\n"); 44 | } 45 | } else { 46 | merge(a, b + n); 47 | merge(b, a + n); 48 | } 49 | } 50 | } 51 | return 0; 52 | } -------------------------------------------------------------------------------- /src/poj1740.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1740: A New Stone Game 3 | * 题意:n堆石头,两人轮流选取一堆,先扔掉至少1个,再将剩下的选取任意个或不选,转移到任意其他一个或多个堆。问先手胜负。 4 | * 类型:NP博弈 5 | * 算法:若包含相同石头数的堆都为偶数堆,则该状态为必败态。因为此时游戏必然破坏该必败条件,但下一轮一定可以通过从对称的堆里进行相同的操作使必败条件满足。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int a[10]; 14 | 15 | int main() { 16 | int n; 17 | while (scanf("%d", &n) != EOF && n) { 18 | bool ans = 1; 19 | for (int i = 0; i < n; ++i) scanf("%d", &a[i]); 20 | if (n % 2 == 0) { 21 | sort(a, a + n); 22 | int i; 23 | for (i = 0; i < n; i += 2) { 24 | if (a[i] != a[i + 1]) break; 25 | } 26 | if (i == n) ans = 0; 27 | } 28 | printf("%d\n", ans); 29 | } 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/poj1742.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1742: Coins 3 | * 题意:给出多种硬币的面值和数量,求可以组成的金额种类。 4 | * 类型:DP+多重背包 5 | * 算法:d[i][j]表示使用前i种硬币组成总价j时,使用第i种硬币的最小数量。若d[i-1][j]合法,d[i][j]=0;否则若d[i][j-Ai] 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | int d[100010]; 17 | int A[110]; 18 | int C[110]; 19 | 20 | int main() { 21 | int n, m; 22 | while(scanf("%d%d", &n, &m) !=EOF && n > 0) { 23 | for(int i = 0; i < n; ++i) { 24 | scanf("%d", &A[i]); 25 | } 26 | for(int i = 0; i < n; ++i) { 27 | scanf("%d", &C[i]); 28 | } 29 | memset(d, -1, sizeof(d)); 30 | d[0] = 0; 31 | for(int i = 0; i < n; ++i) { 32 | for(int j = 0; j <= m; ++j) { 33 | if(d[j] > -1) { 34 | d[j] = 0; 35 | } else if(j >= A[i] && d[j - A[i]] > -1 && d[j - A[i]] < C[i]){ 36 | d[j] = d[j - A[i]] + 1; 37 | } 38 | } 39 | } 40 | int ans = 0; 41 | for(int i = 1; i <= m; ++i) { 42 | if(d[i] > -1) { 43 | ++ans; 44 | } 45 | } 46 | printf("%d\n", ans); 47 | } 48 | return 0; 49 | } -------------------------------------------------------------------------------- /src/poj1759.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1759: Garland 3 | * 题意:数列长为n,给出h(0)的值和数列关系式h(i)=(h(i-1)+h(i+1))/2-1。保证数列所有元素非负,求h(n-1)的最小值。 4 | * 类型:二分搜索 5 | * 算法:根据关系式得到h(i)=ih(1)-(i-1)h(0)+i(i-1),所以要找到最小的h(1)满足所有数非负,此时的h(n-1)即为最小值。 6 | */ 7 | 8 | #include 9 | 10 | const double EPS = 1e-7; 11 | 12 | double h[1010]; 13 | 14 | int main() { 15 | int n; 16 | double A; 17 | scanf("%d%lf", &n, &A); 18 | h[0] = A; 19 | double l, r, m; 20 | l = A / 2 - 1; 21 | r = A; 22 | while (r - l > EPS) { 23 | m = (l + r) / 2; 24 | h[1] = m; 25 | bool ok = true; 26 | for (int i = 2; i < n; ++i) { 27 | h[i] = 2 * (h[i - 1] + 1) - h[i - 2]; 28 | if (h[i] < -EPS) { 29 | ok = false; 30 | break; 31 | } 32 | } 33 | if (ok) { 34 | r = m; 35 | } else { 36 | l = m; 37 | } 38 | } 39 | if (h[n - 1] < 0) h[n - 1] = 0; // -0.00 40 | printf("%.2f\n", h[n - 1]); 41 | 42 | return 0; 43 | } -------------------------------------------------------------------------------- /src/poj1854.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1854: Evil Straw Warts Live 3 | * 题意:给出一个字符串,每次交换相邻字符,求使其变为回文的最少交换次数。 4 | * 类型:贪心 5 | * 算法:每次保证最左边被匹配(贪心可证明匹配最左和最右答案一样,且至少优于其他字符)。从右边对应位置向左搜索该字符,发现则移动到对应右侧。若未有匹配且该字符应该放在结果的中心,则将距离加入结果,然后忽略它继续匹配下一个字符。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | char s[8010]; 12 | int cnt; 13 | 14 | void move(int a, int b) { 15 | char t = s[a]; 16 | for (int i = a; i < b; ++i) s[i] = s[i + 1]; 17 | s[b] = t; 18 | } 19 | 20 | int main() { 21 | int T; 22 | scanf("%d", &T); 23 | while(T--) { 24 | cnt = 0; 25 | scanf("%s", s); 26 | int n = strlen(s); 27 | int i, j; 28 | bool mid = 0; 29 | int m = n - 1; 30 | 31 | for (i = 0; i < n / 2; ++i) { 32 | for (j = m; j > i; --j) { 33 | if (s[i] == s[j]) break; 34 | } 35 | if (i == j) { 36 | if (n % 2 == 0 || mid) { 37 | printf("Impossible\n"); 38 | goto L; 39 | } else { 40 | mid = true; 41 | cnt += n / 2 - i; 42 | } 43 | } else { 44 | move(j, m); 45 | cnt += m - j; 46 | --m; 47 | } 48 | } 49 | if (n & 1 && mid && s[n/2] != s[n/2+1]) { 50 | printf("Impossible\n"); 51 | goto L; 52 | } 53 | printf("%d\n", cnt); 54 | L:; 55 | } 56 | return 0; 57 | } -------------------------------------------------------------------------------- /src/poj1862.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1862: Stripies 3 | * 题意:n个细胞,质量为m1、m2的结合后会变成质量为2sqrt(m1*m2)的新细胞,求最后形成的终极细胞的最小质量。 4 | * 类型:贪心 5 | * 算法:由于越先参与的细胞取根号的次数越多,每次选取最大的两个细胞结合,使得越大的细胞能够越多见减少。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | priority_queue s; 16 | 17 | int main() { 18 | int i, n; 19 | scanf("%d", &n); 20 | for(i = 0; i < n; ++i) { 21 | double tmp; 22 | scanf("%lf", &tmp); 23 | s.push(tmp); 24 | } 25 | while(--n) { 26 | double a, b; 27 | a = s.top(); 28 | s.pop(); 29 | b = s.top(); 30 | s. pop(); 31 | s.push(2 * sqrt(a * b)); 32 | } 33 | printf("%.3f\n", s.top()); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/poj1930.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1930: Dead Fraction 3 | * 题意:给出小于1的无限循环小数的前几位,求可能相等的最简分数中分母最小的。 4 | * 类型:辗转相除法 5 | * 算法:枚举循环后缀长度,将小数点向后移动该长度,相减再相除,得到对应的分子分母,分别除以最大公约数得到最简分数。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef long long LL; 16 | 17 | LL Gcd(LL a, LL b) { 18 | LL t; 19 | while(b) { 20 | t = a % b; 21 | a = b; 22 | b = t; 23 | } 24 | return a; 25 | } 26 | 27 | LL _stoll(string s) { // c++11 std::stoll 28 | LL v = 0; 29 | for(int i = 0; i < s.length(); ++i) { 30 | v = v * 10 + s[i] - '0'; 31 | } 32 | return v; 33 | } 34 | 35 | int main() { 36 | string s, sa, sb; 37 | LL la, lb; 38 | LL num, den, g; 39 | LL ansd, ansn; 40 | while(cin >> s && s.length() > 1) { 41 | s = s.substr(2, s.length() - 5); 42 | int n = s.length(); 43 | ansd = 0; 44 | for(int i = 0; i < n; ++i) { 45 | int j = n - i; 46 | sa = s.substr(0, i); 47 | sb = s.substr(i); 48 | la = i ? _stoll(sa): 0; 49 | lb = _stoll(sb); 50 | num = la * (LL)pow(10, j) + lb - la; 51 | den = ((LL)pow(10, j) - 1) * (LL)pow(10, i); 52 | g = Gcd(num, den); 53 | num /= g; 54 | den /= g; 55 | if(!ansd || den < ansd) { 56 | ansd = den; 57 | ansn = num; 58 | } 59 | } 60 | printf("%lld/%lld\n", ansn, ansd); 61 | } 62 | return 0; 63 | } -------------------------------------------------------------------------------- /src/poj1979.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1979: Red and Black 3 | * 题意:m*n矩阵中,给出初始位置和每个点是否允许踩的状态,向上下左右4个方向移动,求多少点能到达。 4 | * 类型:DFS+记忆化搜索(/BFS/并查集) 5 | * 算法:从某点出发,若该点可踩且未标记,结果+1,将该点标记(记忆化),并向其4个方向的点继续递归搜索。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | char mat[100][100]; 14 | int dx[4] = {-1, 0, 0, 1}; 15 | int dy[4] = {0, 1, -1, 0}; 16 | int m, n, ans; 17 | 18 | void dfs(int x,int y) { 19 | if(mat[x][y] != '.') return; 20 | ++ans; 21 | mat[x][y] = 'x'; 22 | int xx, yy; 23 | for(int i = 0; i < 4; ++i) { 24 | xx = x + dx[i]; 25 | yy = y + dy[i]; 26 | if(xx >= 0 && xx < m && yy >= 0 && yy < n){ 27 | dfs(xx, yy); 28 | } 29 | } 30 | } 31 | 32 | void solve() { 33 | ans = 0; 34 | for(int i = 0; i < m; ++i) { 35 | cin >> mat[i]; 36 | } 37 | for(int i = 0; i < m; ++i) { 38 | for(int j = 0; j< n; ++j) { 39 | if(mat[i][j] == '@') { 40 | mat[i][j] = '.'; 41 | dfs(i, j); 42 | return; 43 | } 44 | } 45 | } 46 | } 47 | 48 | int main() { 49 | while(cin >> n >> m && m > 0 && n > 0) { 50 | solve(); 51 | cout << ans << endl; 52 | } 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /src/poj1981.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1981: Circle and Points 3 | * 题意:给出平面上多个点的坐标,求单位圆最多能覆盖多少个点。不存在距离为2的2点,也不存在同时处在某单位圆的3点。 4 | * 类型:计算几何 5 | * 算法:遍历点作为单位圆圆心,求其他所有点的单位圆与其相交弧。以弧上的点为圆心的答案圆可覆盖构成该段相交弧的圆的圆心。以圆心为极坐标记录交点后排序,然后逆时针单遍扫描,起点+1,终点-1,被覆盖的最多次数即为答案。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | double x[310], y[310]; 15 | 16 | struct Node { 17 | double angle; 18 | bool start; 19 | 20 | bool operator<(const Node &no) const { 21 | if (angle != no.angle) return angle < no.angle; 22 | return start > no.start; 23 | } 24 | } node[610]; 25 | 26 | double GaoDistance(double x1, double y1, double x2, double y2) { 27 | return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); 28 | } 29 | 30 | int main() { 31 | int n; 32 | while (scanf("%d", &n) != EOF && n) { 33 | for (int i = 0; i < n; ++i) { 34 | scanf("%lf%lf", &x[i], &y[i]); 35 | } 36 | int ans = 1; 37 | for (int i = 0; i < n; ++i) { 38 | int cnt = 0; 39 | for (int j = 0; j < n; ++j) { 40 | if (i == j) continue; 41 | double d = GaoDistance(x[i], y[i], x[j], y[j]); 42 | if (d > 2.0) continue; 43 | double slope = atan2(y[j] - y[i], x[j] - x[i]); 44 | double rotate = acos(d / 2.0); 45 | node[cnt].angle = slope - rotate; 46 | node[cnt++].start = 1; 47 | node[cnt].angle = slope + rotate; 48 | node[cnt++].start = 0; 49 | } 50 | sort(node, node + cnt); 51 | int cur = 1; 52 | for (int j = 0; j < cnt; ++j) { 53 | if (node[j].start) ++cur; 54 | else --cur; 55 | ans = max(cur, ans); 56 | } 57 | } 58 | printf("%d\n", ans); 59 | } 60 | return 0; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/poj1986.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1986: Distance Queries 3 | * 题意:给出一棵树和每边权重,求询问的某两点的距离。 4 | * 类型:LCA 5 | * 算法:得到每个结点离虚拟根0的深度和距离,倍增法得到每个结点深度差为2次幂的上游结点。询问时,通过二分找到最近公共祖先,两点距离为各自离根的距离相加再减去2倍lca离根的距离。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | 17 | typedef pair pii; 18 | 19 | vector e[40010]; 20 | 21 | int dep[40010]; 22 | int ans[40010][17]; 23 | int path[40010]; 24 | 25 | void InitLsa(int u, int p, int step, int len = 0) { 26 | path[u] = len; 27 | dep[u] = step; 28 | ans[u][0] = p; 29 | for (int k = 1; k < 17 && ans[u][k - 1]; ++k) { 30 | ans[u][k] = ans[ans[u][k - 1]][k - 1]; 31 | } 32 | for (vector::iterator it = e[u].begin(); it != e[u].end(); ++it) { 33 | int v = it->first; 34 | if (v == p) continue; 35 | InitLsa(v, u, step + 1, len + it->second); 36 | } 37 | } 38 | 39 | int GetLsa(int u, int v) { 40 | if (dep[u] > dep[v]) { 41 | int t = u; 42 | u = v; 43 | v = t; 44 | } 45 | for (int k = 0; k < 17 && dep[v] != dep[u]; ++k) { 46 | if (((dep[v] - dep[u]) >> k) & 1) { 47 | v = ans[v][k]; 48 | } 49 | } 50 | if (u == v) return u; 51 | 52 | for (int k = 16; k >= 0; --k) { 53 | if (ans[u][k] != ans[v][k]) { 54 | u = ans[u][k]; 55 | v = ans[v][k]; 56 | } 57 | } 58 | return ans[u][0]; 59 | } 60 | 61 | int GetDist(int u, int v) { 62 | int lca = GetLsa(u, v); 63 | return path[u] + path[v] - 2 * path[lca]; 64 | } 65 | 66 | int main() { 67 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 68 | int n, m; 69 | scanf("%d%d", &n, &m); 70 | 71 | while (m--) { 72 | int u, v, c; 73 | char op[5]; 74 | scanf("%d%d%d%s", &u, &v, &c, op); 75 | e[u].push_back(make_pair(v, c)); 76 | e[v].push_back(make_pair(u, c)); 77 | } 78 | 79 | InitLsa(1, 0, 1); 80 | 81 | int qq; 82 | scanf("%d", &qq); 83 | while (qq--) { 84 | int u, v; 85 | scanf("%d%d", &u, &v); 86 | printf("%d\n", GetDist(u, v)); 87 | } 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /src/poj1990.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1990: MooFest 3 | * 题意:n头奶牛站成一排,给出每个奶牛的坐标和听力上限。两头奶牛交流的声音为大的听力上限乘以距离。求C(n,2)对奶牛间交流的声音总和。 4 | * 类型:树状数组(/线段树) 5 | * 算法:奶牛按听力升序遍历。先从树状数组中它前面的奶牛数和坐标和,减法得到后面的值,依据坐标差正负计算所有牛与当前牛交流的声音总和。然后将该奶牛加入到对应坐标的树状数组里,更新个数和与坐标和。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | int low_bit(int x) { 16 | return x&-x; 17 | } 18 | 19 | long long dis[20010]; 20 | int cnt[20010]; 21 | int N = 20000; 22 | 23 | typedef pair pii; 24 | pii cows[20010]; 25 | 26 | void change(int x) { 27 | int d = x; 28 | while(x <= N) { 29 | dis[x] += d; 30 | cnt[x] += 1; 31 | x += low_bit(x); 32 | } 33 | } 34 | 35 | void query(int x, long long &d, int &c) { 36 | d = c = 0; 37 | while(x) { 38 | d += dis[x]; 39 | c += cnt[x]; 40 | x -= low_bit(x); 41 | } 42 | } 43 | 44 | int main() { 45 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 46 | int n; 47 | scanf("%d", &n); 48 | long long tot_dis = 0; 49 | int tot_cnt = 0; 50 | long long ans = 0; 51 | for (int i = 0; i < n; ++i) { 52 | scanf("%d%d", &cows[i].first, &cows[i].second); 53 | } 54 | sort(cows, cows + n); 55 | for (int i = 0; i < n; ++i) { 56 | long long before_dis, after_dis; 57 | int before_cnt, after_cnt; 58 | query(cows[i].second, before_dis, before_cnt); 59 | // printf("%d : %d %d\n", i, before_dis, before_cnt); 60 | after_dis = tot_dis - before_dis; 61 | after_cnt = tot_cnt - before_cnt; 62 | ans += cows[i].first * ((before_cnt * cows[i].second - before_dis) + (after_dis - after_cnt * cows[i].second)); 63 | change(cows[i].second); 64 | tot_dis += cows[i].second; 65 | tot_cnt += 1; 66 | } 67 | printf("%lld\n", ans); 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /src/poj1995.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 1995: Raising Modulo Numbers 3 | * 题意:求多个幂次方的和取模后的答案。 4 | * 类型:快速幂 5 | * 算法:对于每个幂次方,将幂指数的二进制形式表示,从右到左移位,每次底数自乘,循环内每步取模。 6 | */ 7 | 8 | #include 9 | 10 | typedef long long LL; 11 | 12 | LL Ksm(LL a, LL b, LL p) { 13 | LL ans = 1; 14 | while(b) { 15 | if(b & 1) { 16 | ans = (ans * a) % p; 17 | } 18 | a = (a * a) % p; 19 | b >>= 1; 20 | } 21 | return ans; 22 | } 23 | 24 | 25 | int main() { 26 | LL p, a, b; 27 | int T; 28 | int n; 29 | scanf("%d", &T); 30 | while(T--) { 31 | scanf("%lld%d", &p, &n); 32 | LL ans = 0; 33 | while(n--) { 34 | scanf("%lld%lld", &a, &b); 35 | ans = (ans + Ksm(a, b, p)) % p; 36 | } 37 | printf("%lld\n", ans); 38 | } 39 | return 0; 40 | } -------------------------------------------------------------------------------- /src/poj2010.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2010: Moo University - Financial Aid 3 | * 题意:从申请者里录取规定的n个,n为奇数,要求他们需要的开销和不超过预算,求被录取者的得分最大可能的中位数。 4 | * 类型:优先队列(/二分搜索) 5 | * 算法:按分数升序排序,把每个点作中位数看待,用最大堆得到每个点左侧及右侧,n/2个最小的开销的和。找到左右和相加不超过预算的最大中位数。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef pair pii; 16 | 17 | pii c[100010]; 18 | long long l[100010], r[100010]; 19 | priority_queue pq; 20 | 21 | int main() { 22 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 23 | int m, n, i, j; 24 | long long tmp; 25 | long long t; 26 | scanf("%d%d%lld\n", &m, &n, &t); 27 | for(i = 0; i < n; ++i) { 28 | scanf("%d%d", &c[i].first, &c[i].second); 29 | } 30 | sort(c, c + n); 31 | if(m == 1) { 32 | for(i = n - 1; i >= 0; --i) { 33 | if(c[i].second <= t) { 34 | printf("%d\n", c[i].first); 35 | break; 36 | } 37 | } 38 | printf("-1\n"); 39 | return 0; 40 | } 41 | 42 | tmp = 0; 43 | for(i = 0; i < m/2; ++i) { 44 | pq.push(c[i].second); 45 | tmp += c[i].second; 46 | } 47 | l[i] = tmp; 48 | for(++i; i <= n - m/2 - 1; ++i) { 49 | if(pq.top() <= c[i - 1].second) { 50 | l[i] = l[i - 1]; 51 | } else { 52 | l[i] = l[i - 1] - pq.top() + c[i - 1].second; 53 | pq.pop(); 54 | pq.push(c[i - 1].second); 55 | } 56 | } 57 | 58 | while(!pq.empty()) { 59 | pq.pop(); 60 | } 61 | tmp = 0; 62 | for(i = n - 1; i > n - m/2 -1; --i) { 63 | pq.push(c[i].second); 64 | tmp += c[i].second; 65 | } 66 | r[i] = tmp; 67 | for(--i; i >= m/2; --i) { 68 | if(pq.top() <= c[i + 1].second) { 69 | r[i] = r[i + 1]; 70 | } else { 71 | r[i] = r[i + 1] - pq.top() + c[i + 1].second; 72 | pq.pop(); 73 | pq.push(c[i + 1].second); 74 | } 75 | } 76 | 77 | int ans = -1; 78 | for(i = n - m/2 - 1; i >= m/2; --i) { 79 | if(l[i] + r[i] + c[i].second <= t) { 80 | ans = c[i].first; 81 | break; 82 | } 83 | } 84 | printf("%d\n", ans); 85 | return 0; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /src/poj2068.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3688: Cheat in the Game 3 | * 题意:m堆石头,2n个人轮流取,每个人单次取的上限。求先手胜负。 4 | * 类型:博弈DP 5 | * 算法:d[i][w]表示轮到第i个人还剩w个石头,它可由d[(i+1)%2n][w-k]转移得到,k为1到ai。记忆化dp,解为d[0][m]。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int d[1 << 13][20]; 14 | int m[20]; 15 | int n; 16 | 17 | int dp(int s, int u) { 18 | if (d[s][u] != -1) return d[s][u]; 19 | if (s == 1) return d[s][u] = 0; 20 | int v = (u + 1) % n; 21 | for (int i = 1; i <= m[u] && i < s; ++i) { 22 | if (dp(s - i, v) == 0) { 23 | return d[s][u] = 1; 24 | } 25 | } 26 | return d[s][u] = 0; 27 | } 28 | 29 | int main() { 30 | int s; 31 | while(scanf("%d", &n) != EOF && n) { 32 | n <<= 1; 33 | memset(d, -1, sizeof(d)); 34 | scanf("%d", &s); 35 | for (int i = 0; i < n; ++i) scanf("%d", &m[i]); 36 | printf("%d\n", dp(s, 0)); 37 | } 38 | return 0; 39 | } -------------------------------------------------------------------------------- /src/poj2082.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2082: Terrible Sets 3 | * 题意:一排相邻的矩形,给出各自的高度和宽度。求一个面积最大的矩形,被之前的矩形完全包含。 4 | * 类型:栈 5 | * 算法:用栈得到某个矩形靠它最近的比它矮的左边和右边,得到它对应的宽度,相乘为待选解。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int h[50010], w[50010]; 14 | int s[50010]; 15 | int l[50010], r[50010]; 16 | 17 | stack st; 18 | 19 | int main() { 20 | int n; 21 | while (scanf("%d", &n) != EOF && n != -1) { 22 | int ans = 0; 23 | s[0] = 0; 24 | for (int i = 1; i <= n; ++i) { 25 | scanf("%d%d", &w[i], &h[i]); 26 | s[i] = s[i - 1] + w[i]; 27 | } 28 | h[0] = h[n + 1] = -1; 29 | 30 | while (!st.empty()) st.pop(); 31 | for (int i = 1; i <= n + 1; ++i) { 32 | while (!st.empty()) { 33 | if (h[st.top()] > h[i]) { 34 | r[st.top()] = i; 35 | st.pop(); 36 | } else break; 37 | } 38 | st.push(i); 39 | } 40 | 41 | while (!st.empty()) st.pop(); 42 | for (int i = n; i >= 0; --i) { 43 | while (!st.empty()) { 44 | if (h[st.top()] > h[i]) { 45 | l[st.top()] = i; 46 | st.pop(); 47 | } else break; 48 | } 49 | st.push(i); 50 | } 51 | 52 | for (int i = 1; i <= n; ++i) { 53 | ans = max(ans, h[i] * (s[r[i] - 1] - s[l[i]])); 54 | } 55 | 56 | printf("%d\n", ans); 57 | } 58 | return 0; 59 | } -------------------------------------------------------------------------------- /src/poj2100.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2100: Graveyard Design 3 | * 题意:总面积一定,求边长连续的一些正方形,面积和正好等于给出总面积。 4 | * 类型:尺取法 5 | * 算法:尺取法控制左右端点向后移动,若累加和等于总面积输出答案同时左右端点移动,小于则右端点右移和增加对应部分,大于则左端点右移和减少。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | typedef long long LL; 15 | 16 | typedef pair pll; 17 | 18 | pll ans[67000]; 19 | int cnt; 20 | 21 | int main() { 22 | LL n; 23 | scanf("%lld", &n); 24 | LL l = 1, r = 1; 25 | LL ub = sqrt(n) + 1; 26 | LL tmp = 1; 27 | while(true) { 28 | if(tmp == n) { 29 | ans[cnt].first = l; 30 | ans[cnt++].second = r; 31 | if(l == r) break; 32 | ++r; 33 | tmp += r * r; 34 | tmp -= l * l + (l + 1) * (l + 1); 35 | l += 2; 36 | } else if(tmp > n) { 37 | if(l == r) break; 38 | tmp -= l * l; 39 | ++l; 40 | } else if(tmp < n){ 41 | ++r; 42 | tmp += r * r; 43 | } 44 | } 45 | printf("%d\n", cnt); 46 | for(int i = 0; i < cnt; ++i) { 47 | l = ans[i].first; 48 | r = ans[i].second; 49 | printf("%lld", r - l + 1); 50 | for(LL j = l; j <= r; ++j) printf(" %lld", j); 51 | printf("\n"); 52 | } 53 | return 0; 54 | } -------------------------------------------------------------------------------- /src/poj2112.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2112: Optimal Milking 3 | * 题意:给出多头牛和多个机器之间的直连边长,每台机器可以服务m头牛。所有牛的被满足的前提下,求牛到服务它的机器的最远距离的最小值。 4 | * 类型:最短路+二分+二分匹配(/最大流) 5 | * 算法:Floyd得到所有点之间的最短路,然后二分最远距离,不大于该距离的边可用于二分匹配。二分匹配时,将每台机器分割为m台。若此时最大匹配数为牛数则更新上届,否则下届。最终的上届即为最远距离的最小值。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | const int INF = 0x3f3f3f3f; 15 | 16 | bool e[210][460]; 17 | bool vis[460]; 18 | int rec[460]; 19 | int n1, n2; 20 | int K, C, M; 21 | int d[240][240]; 22 | 23 | bool Dfs(int u) { 24 | for (int i = 0; i < n2; ++i) { 25 | if (e[u][i] && !vis[i]) { 26 | vis[i] = 1; 27 | if (rec[i] == -1 || Dfs(rec[i])) { 28 | rec[i] = u; 29 | return true; 30 | } 31 | } 32 | } 33 | return false; 34 | } 35 | 36 | bool Hungary() { 37 | memset(rec, -1, sizeof(rec)); 38 | for (int i = 0; i < n1; ++i) { 39 | memset(vis, 0, sizeof(vis)); 40 | if (!Dfs(i)) return false; 41 | } 42 | return true; 43 | } 44 | 45 | void BuildGraph(int g) { 46 | memset(e, 0, sizeof(e)); 47 | for (int i = 0; i < C; ++i) { 48 | for (int j = 0; j < K; ++j) { 49 | if (d[K + i][j] <= g) { 50 | for (int k = M * j; k < M * (j + 1); ++k) { 51 | e[i][k] = 1; 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | void Floyd(int n) { 59 | for (int i = 0; i < n; ++i) { 60 | for (int j = 0; j < n; ++j) { 61 | scanf("%d", &d[i][j]); 62 | if (!d[i][j]) d[i][j] = INF; 63 | } 64 | } 65 | for (int k = 0; k < n; ++k) { 66 | for (int i = 0; i < n; ++i) { 67 | for (int j = 0; j < n; ++j) { 68 | d[i][j] = min(d[i][j], d[i][k] + d[k][j]); 69 | } 70 | } 71 | } 72 | } 73 | 74 | int main() { 75 | scanf("%d%d%d", &K, &C, &M); 76 | n1 = C; 77 | n2 = K * M; 78 | Floyd(K + C); 79 | int l, r, m; 80 | l = 0; 81 | r = (K + C) * 200; 82 | while (l + 1 < r) { 83 | m = (l + r) >> 1; 84 | BuildGraph(m); 85 | (Hungary() ? r : l) = m; 86 | } 87 | printf("%d\n", r); 88 | return 0; 89 | } -------------------------------------------------------------------------------- /src/poj2115.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2115: C Looooops 3 | * 题意:x初值为A,迭代式为x=(x+C)%(1< 10 | 11 | typedef long long LL; 12 | 13 | LL ExtGcd(LL a, LL b, LL &x, LL &y) { 14 | if (b == 0) { 15 | x = 1; 16 | y = 0; 17 | return a; 18 | } 19 | LL g = ExtGcd(b, a % b, y, x); 20 | y -= a / b * x; 21 | return g; 22 | } 23 | 24 | int main() { 25 | LL A, B, C, k, x, y, a, b, c; 26 | while (scanf("%lld%lld%lld%lld", &A, &B, &C, &k) != EOF && k) { 27 | a = C; 28 | b = 1ll << k; 29 | c = B - A; 30 | LL g = ExtGcd(a, b, x, y); 31 | if (c % g) { 32 | printf("FOREVER\n"); 33 | } else { 34 | LL u = b / g; 35 | x *= c / g; 36 | x = (x % u + u) % u; 37 | printf("%lld\n", x); 38 | } 39 | } 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /src/poj2139.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2139: Six Degrees of Cowvin Bacon 3 | * 题意:图中多条权为1的双向边,求到其他所有点的最短路的平均值最小的点。 4 | * 类型:最短路 5 | * 算法:用Floyd求到两两之间最短路,枚举和最小的点。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int d[310][310]; 15 | int tmp[310]; 16 | 17 | void floyd(int n) { 18 | for(int i = 1; i <= n; ++i) { 19 | for(int j = 1; j <= n; ++j) { 20 | for(int k = 1; k <= n; ++k) { 21 | d[i][j] = min(d[i][j], d[i][k] + d[k][j]); 22 | } 23 | } 24 | } 25 | } 26 | 27 | int main() { 28 | memset(d, 0x3f, sizeof(d)); 29 | int n, m; 30 | scanf("%d%d", &n, &m); 31 | while(m--) { 32 | int t; 33 | scanf("%d", &t); 34 | for(int i = 0; i < t; ++i){ 35 | scanf("%d", &tmp[i]); 36 | for(int j = 0; j < i; ++j) { 37 | d[tmp[i]][tmp[j]] = 1; 38 | d[tmp[j]][tmp[i]] = 1; 39 | } 40 | } 41 | floyd(n); 42 | } 43 | 44 | int ans, sum; 45 | ans = 0x7fffffff; 46 | for(int i = 1; i <= n; ++i) { 47 | sum = 0; 48 | for(int j = 1; j <= n; ++j) { 49 | if(i == j) continue; 50 | sum += d[i][j]; 51 | } 52 | 53 | ans = min(ans, sum); 54 | } 55 | printf("%d\n", ans * 100 / (n - 1)); 56 | return 0; 57 | } -------------------------------------------------------------------------------- /src/poj2155.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2155: Matrix 3 | * 题意:一个方阵初始化全为0,多次反转和查询操作。每次反转所给矩阵范围内所有的点,询问某个点的值。 4 | * 类型:树状数组(/线段树) 5 | * 算法:二维树状数组,第一维数组的每个节点对应一个第二维的树状数组。对于反转操作,将左端点上+1,右端点后-1。求值即为求从头开始的累加和。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int low_bit(int x) { 15 | return x&-x; 16 | } 17 | 18 | int bit[1010][1010]; 19 | int N; 20 | 21 | void change(int x, int y, int d) { 22 | while(y <= N) { 23 | bit[x][y] += d; 24 | y += low_bit(y); 25 | } 26 | } 27 | 28 | int sum(int x, int y) { 29 | int ans = 0; 30 | while(y) { 31 | ans += bit[x][y]; 32 | y -= low_bit(y); 33 | } 34 | return ans; 35 | } 36 | 37 | void change2(int x, int y, int d) { 38 | while(x <= N) { 39 | change(x, y, d); 40 | x += low_bit(x); 41 | } 42 | } 43 | 44 | int sum2(int x, int y) { 45 | int ans = 0; 46 | while(x) { 47 | ans += sum(x, y); 48 | x -= low_bit(x); 49 | } 50 | return ans; 51 | } 52 | 53 | int main() { 54 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 55 | int T, tc, k; 56 | scanf("%d", &T); 57 | for(tc = 0; tc < T; ++tc) { 58 | if(tc) { 59 | printf("\n"); 60 | } 61 | memset(bit, 0, sizeof(bit)); 62 | scanf("%d%d", &N, &k); 63 | while(k--) { 64 | char op[5]; 65 | scanf("%s", op); 66 | if(op[0] == 'Q') { 67 | int x, y; 68 | scanf("%d%d", &x, &y); 69 | int ans = sum2(x, y) & 1; 70 | printf("%d\n", ans); 71 | } else { 72 | int x1, y1, x2, y2; 73 | scanf("%d%d%d%d", &x1, &y1, &x2, &y2); 74 | change2(x1, y1, 1); 75 | change2(x1, y2 + 1, -1); 76 | change2(x2 + 1, y1, -1); 77 | change2(x2 + 1, y2 + 1, 1); 78 | } 79 | } 80 | } 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /src/poj2184.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2184: Cow Exhibition 3 | * 题意:一群奶牛,给出每头的IQ和EQ,范围是-1000到1000。选出一批奶牛,使得它们的IQ和、EQ和都非负。求IQ和加EQ和的最大值。 4 | * 类型:DP+01背包 5 | * 算法:d[i]表示IQ和为i时的EQ和最大值,由于和可为负数,用i加上一个大数作为数组下标。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | const int M = 100000; 14 | int d[200010]; 15 | 16 | int main() { 17 | int i, j, n, iq, eq; 18 | scanf("%d", &n); 19 | for(i = 0; i <= (M<<1); ++i) { 20 | d[i] = -M - 1; 21 | } 22 | d[M] = 0; 23 | for(i = 0; i < n; ++i) { 24 | scanf("%d%d", &iq, &eq); 25 | if(iq <= 0 && eq <= 0) { 26 | continue; 27 | } 28 | if(iq > 0) { 29 | for(j = (M<<1); j >= iq ; --j) { 30 | if(d[j - iq] >= -M) { 31 | d[j] = max(d[j], d[j - iq] + eq); 32 | } 33 | } 34 | } else { 35 | for(j = 0; j <= (M<<1) + iq ;++j) { 36 | if(d[j - iq] >= -M) { 37 | d[j] = max(d[j], d[j - iq] + eq); 38 | } 39 | } 40 | } 41 | } 42 | int ans = 0; 43 | for(i = M; i <= (M<<1); ++i) { 44 | if(d[i] >= 0) { 45 | ans = max(ans, i - M + d[i]); 46 | } 47 | } 48 | printf("%d\n", ans); 49 | return 0; 50 | } -------------------------------------------------------------------------------- /src/poj2226.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2226: Muddy Fields 3 | * 题意:给出一个矩阵,每个点是.或*。现在有一些宽为1长任意的木条,要用木条覆盖所有的*,但是保留所有的.。求最少使用的木条数量。 4 | * 类型:二分匹配 5 | * 算法:分为横竖考虑,将连续的*区域用一个木条表示,并编号。每个*都是一个横和一个竖交点。将横竖木条分列二分图两侧作为点,每个*作为边。则最小顶点覆盖数即为所求,二分图中其值等于最大匹配。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | vector e[1300]; 15 | bool vis[1300]; 16 | int rec[1300]; 17 | int n1, n2; 18 | 19 | bool Dfs(int u) { 20 | for (vector::iterator it = e[u].begin(); it != e[u].end(); ++it) { 21 | int v = *it; 22 | if (!vis[v]) { 23 | vis[v] = true; 24 | if (rec[v] == -1 || Dfs(rec[v])) { 25 | rec[v] = u; 26 | return true; 27 | } 28 | } 29 | } 30 | return false; 31 | } 32 | 33 | int Hungary() { 34 | int ans = 0; 35 | memset(rec, -1, sizeof(rec)); 36 | for (int i = 0; i < n1; ++i) { 37 | memset(vis, 0, sizeof(vis)); 38 | if (Dfs(i)) ++ans; 39 | } 40 | return ans; 41 | } 42 | 43 | struct Line { 44 | Line() {} 45 | 46 | Line(int _x1, int _x2, int _y) : x1(_x1), x2(_x2), y(_y) {} 47 | 48 | int x1, x2, y; 49 | } heng[1300], shu[1300]; 50 | 51 | char mat[55][55]; 52 | 53 | int main() { 54 | int r, c; 55 | scanf("%d%d", &r, &c); 56 | for (int i = 0; i < r; ++i) { 57 | scanf("%s", mat[i]); 58 | } 59 | 60 | n1 = n2 = 0; 61 | for (int i = 0; i < r; ++i) { 62 | int x1 = -1; 63 | for (int j = 0; j < c; ++j) { 64 | if (mat[i][j] == '.') { 65 | if (x1 != -1) { 66 | heng[n1++] = Line(x1, j - 1, i); 67 | x1 = -1; 68 | } 69 | } else { 70 | if (x1 == -1) { 71 | x1 = j; 72 | } 73 | } 74 | } 75 | if (x1 != -1) { 76 | heng[n1++] = Line(x1, c - 1, i); 77 | } 78 | } 79 | for (int i = 0; i < c; ++i) { 80 | int x1 = -1; 81 | for (int j = 0; j < r; ++j) { 82 | if (mat[j][i] == '.') { 83 | if (x1 != -1) { 84 | shu[n2++] = Line(x1, j - 1, i); 85 | x1 = -1; 86 | } 87 | } else { 88 | if (x1 == -1) { 89 | x1 = j; 90 | } 91 | } 92 | } 93 | if (x1 != -1) { 94 | shu[n2++] = Line(x1, r - 1, i); 95 | } 96 | } 97 | 98 | for (int i = 0; i < n1; ++i) { 99 | for (int j = 0; j < n2; ++j) { 100 | if (heng[i].y >= shu[j].x1 && heng[i].y <= shu[j].x2 && shu[j].y >= heng[i].x1 && shu[j].y <= heng[i].x2) { 101 | e[i].push_back(j); 102 | } 103 | } 104 | } 105 | 106 | printf("%d\n", Hungary()); 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /src/poj2229.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2229: Sumsets 3 | * 题意:将一个数n分解为2的次幂的和,求分解方案数。 4 | * 类型:DP 5 | * 算法:若n的分解式包含1,则在n-1的分解式最后添上1,s[n]+=s[n-1];若分解式都为偶数,则s[n]+=s[n>>1]。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | long long d[1000010]; 15 | 16 | int main() { 17 | int n; 18 | scanf("%d", &n); 19 | d[0] = 1; 20 | for(int i = 1; i <= n; ++i) { 21 | if(i & 1) { 22 | d[i] = d[i - 1]; 23 | } else{ 24 | d[i] = (d[i - 1] + d[i >> 1]) % 1000000000; 25 | } 26 | } 27 | printf("%lld\n", d[n]); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /src/poj2236.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2236: Wireless Network 3 | * 题意:给出多台损坏的电脑的坐标,任意两台修好且距离不超过d的电脑可以连线。给出修复某些电脑的指令,随时确认给出某两台之间是否有通路。 4 | * 类型:并查集 5 | * 算法:修复某台电脑时,将已修复的电脑中距离符合的和当前电脑所在的集合合并。判断是否有通路找到各自的集合代表元素看是否相同即可。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int x[1010], y[1010]; 14 | int fa[1010]; 15 | bool fxd[1010]; 16 | int n, d; 17 | 18 | bool close(int a, int b) { 19 | return d * d - (x[a] - x[b]) * (x[a] - x[b]) >= (y[a] - y[b]) * (y[a] - y[b]); 20 | } 21 | 22 | int find(int a) { 23 | if(fa[a] != a) { 24 | fa[a] = find(fa[a]); 25 | } 26 | return fa[a]; 27 | } 28 | 29 | void merge(int a, int b) { 30 | fa[find(a)] = find(b); 31 | } 32 | 33 | int main() { 34 | scanf("%d%d", &n, &d); 35 | for(int i = 1; i <= n; ++i) { 36 | scanf("%d%d", &x[i], &y[i]); 37 | fa[i] = i; 38 | } 39 | char op[5]; 40 | int a, b; 41 | while(scanf("%s", op) != EOF) { 42 | if(op[0] == 'O') { 43 | scanf("%d", &a); 44 | if(!fxd[a]) { 45 | fxd[a] = true; 46 | for(b = 1; b <= n; ++b) { 47 | if(!fxd[b]) continue; 48 | if(find(a) == find(b)) continue; 49 | if(close(a, b)) { 50 | merge(a, b); 51 | } 52 | } 53 | } 54 | } else { 55 | scanf("%d%d", &a, &b); 56 | if(find(a) == find(b)) { 57 | printf("SUCCESS\n"); 58 | } else { 59 | printf("FAIL\n"); 60 | } 61 | } 62 | } 63 | return 0; 64 | } -------------------------------------------------------------------------------- /src/poj2315.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2315: Football Game 3 | * 题意:n个球距离门框距离不同,每次选不超过m踢,踢出距离是周长的整数倍,单次最长不超过l。问先手必胜还是后手胜。 4 | * 类型:Nim博弈 5 | * 算法:将距离除以周长变为整数,则问题转化为Nim加强。n堆石头,每次最多取m堆,每堆最多取k个。首先每堆石头对k+1取模,接下来的每堆石头转为2进制数并进行模为m+1的xor(只加不进位),结果非0则必胜,否则必败。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | const double PI = acos(-1.0); 13 | 14 | int sg[28]; 15 | 16 | int main() { 17 | int n, m, l, r; 18 | int a; 19 | while (scanf("%d%d%d%d", &n, &m, &l, &r) != EOF) { 20 | l = (int)(l / (2 * PI * r)); 21 | memset(sg, 0, sizeof(sg)); 22 | for (int i = 0; i < n; ++i) { 23 | scanf("%d", &a); 24 | a = (int)(a / (2 * PI * r) + 1) % (l + 1); 25 | int j = 0; 26 | while (a) { 27 | sg[j++] += a & 1; 28 | a >>= 1; 29 | } 30 | } 31 | bool ok = false; 32 | for (int j = 0; j < 28; ++j) { 33 | if (sg[j] % (m + 1)) { 34 | ok = true; 35 | break; 36 | } 37 | } 38 | printf("%s\n", ok ? "Alice" : "Bob"); 39 | } 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /src/poj2345.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2345: Central heating 3 | * 题意:n个技工,n个炉子。每个技工负责若干个炉子,收到指令后会去反转炉子开关状,任何技工工作不会被其他组合替换。初始时全为关闭,问最少选择多少个技工可以使得炉子全开。 4 | * 类型:高斯消元 5 | * 算法:n个变量表示是否调用该技工,可得到n元1次模方程组,方程右边都是对2取模为1。由于题目规定任意技工都不能表示为其他的组合,所以矩阵的秩为n,可以高斯消元求解到唯一解,不会出现多解或无解。 6 | */ 7 | 8 | #include 9 | 10 | int b[255][255]; 11 | int n; 12 | 13 | void swap(int &x, int &y) { 14 | int t = x; 15 | x = y; 16 | y = t; 17 | } 18 | 19 | void Gauss() { 20 | for (int i = 0; i < n; ++i) { 21 | int j; 22 | for (j = i; j < n; ++j) { 23 | if (b[j][i]) break; 24 | } 25 | if (j > i) { 26 | for (int k = 0; k <= n; ++k) { 27 | swap(b[i][k], b[j][k]); 28 | } 29 | } 30 | for (j = 0; j < n; ++j) { 31 | if (j == i) continue; 32 | if (b[j][i]) { 33 | for (int k = 0; k <= n; ++k) { 34 | b[j][k] ^= b[i][k]; 35 | } 36 | } 37 | } 38 | // for (int ii = 0; ii < n; ++ii) { 39 | // for (int jj = 0; jj <= n; ++jj) { 40 | // printf("%d ", b[ii][jj]); 41 | // } 42 | // printf("\n"); 43 | // } 44 | } 45 | } 46 | 47 | int main() { 48 | scanf("%d", &n); 49 | for (int i = 0; i < n; ++i) { 50 | int j; 51 | while (scanf("%d", &j) != EOF && j != -1) { 52 | b[j - 1][i] = 1; 53 | } 54 | b[i][n] = 1; 55 | } 56 | 57 | Gauss(); 58 | 59 | bool first = true; 60 | for (int i = 0; i < n; ++i) { 61 | if (b[i][n]) { 62 | if (first) first = false; 63 | else printf(" "); 64 | printf("%d", i + 1); 65 | } 66 | } 67 | printf("\n"); 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /src/poj2376.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2376: Cleaning Shifts 3 | * 题意:有1~T连续的T份任务,有N头奶牛,每头牛可以完成某段连续时间的任务。求最少需要多少头牛,完成T个任务。 4 | * 类型:贪心 5 | * 算法:将N个区间按起点排序,若1~p已全覆盖,则从剩下的待选区间内找到所有起点不大于p,且终点最大的区间。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | pair cows[25010]; 15 | 16 | int main() { 17 | int T, N; 18 | scanf("%d%d", &N, &T); 19 | for(int i = 0; i < N; ++i) { 20 | scanf("%d%d", &cows[i].first, &cows[i].second); 21 | } 22 | sort(cows, cows + N); 23 | int p = 1; 24 | int cnt = 0; 25 | int i = 0; 26 | while(p <= T) { 27 | int np = -1; 28 | for(;i < N; ++i) { 29 | if(cows[i].first <= p) { 30 | np = max(np, cows[i].second); 31 | } else { 32 | break; 33 | } 34 | } 35 | if(np == -1) { 36 | printf("-1\n"); 37 | return 0; 38 | } else { 39 | p = np + 1; 40 | ++cnt; 41 | if(p > T) { 42 | printf("%d\n", cnt); 43 | return 0; 44 | } 45 | } 46 | } 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /src/poj2377.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2377: Bad Cowtractors 3 | * 题意:从待选的路里面选出若干构成一个无环连通图(树),求花费最大值。 4 | * 类型:最小生成树 5 | * 算法:最大生成树,Kruskal算法变形为每次用最大堆取出最大边,然后并查集判断是否两端已连通。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | struct E{ 15 | E() {} 16 | E(int uu, int vv, int cc): u(uu), v(vv), c(cc) {} 17 | bool operator > (const E& e) const { 18 | return c < e.c; 19 | } 20 | int u, v, c; 21 | }; 22 | 23 | int fa[1010]; 24 | priority_queue, greater > pq; 25 | 26 | int find(int x) { 27 | if(x == fa[x]) return x; 28 | return fa[x] = find(fa[x]); 29 | } 30 | 31 | int Kruskal(int n) { 32 | for(int i = 1; i <= n; ++i) { 33 | fa[i] = i; 34 | } 35 | int cnt = 1; 36 | int ans = 0; 37 | 38 | while(cnt < n && !pq.empty()) { 39 | const E& e = pq.top(); 40 | int u, v, c; 41 | u = e.u; 42 | v = e.v; 43 | c = e.c; 44 | pq.pop(); 45 | 46 | u = find(u); 47 | v = find(v); 48 | if(u == v) continue; 49 | fa[u] = v; 50 | ans += c; 51 | ++cnt; 52 | } 53 | if(cnt < n) { 54 | return -1; 55 | } else { 56 | return ans; 57 | } 58 | } 59 | 60 | int main() { 61 | int n, m; 62 | scanf("%d%d", &n, &m); 63 | while(m--) { 64 | int u, v, c; 65 | scanf("%d%d%d", &u, &v, &c); 66 | pq.push(E(u, v ,c)); 67 | } 68 | printf("%d\n", Kruskal(n)); 69 | return 0; 70 | } -------------------------------------------------------------------------------- /src/poj2385.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2385: Apple Catching 3 | * 题意:苹果每分钟从两棵树的其中一棵落下,在树1和树2间可以跳换给定次数,问最多可以接到多少苹果,初始在树1。 4 | * 类型:DP 5 | * 算法:d[i][j]表示到达i时刻,已换树j次,位于j%2+1号树下。转移d[i][j]=max(d[i-1][j],d[i-1][j-1])+((j&1)+1==a[i])。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int d[1010][33]; 15 | int a[1010]; 16 | 17 | int main() { 18 | int n, w, i, j, p; 19 | scanf("%d%d", &n, &w); 20 | for(i = 0; i < n; ++i) { 21 | scanf("%d", &a[i]); 22 | d[i][0] = (i? d[i - 1][0]: 0) + int(a[i] == 1); 23 | } 24 | for(i = 0; i <= w; ++i) { 25 | d[0][i] = ((i & 1) + 1 == a[0]); 26 | } 27 | for(i = 1; i < n; ++i) { 28 | for(j = 1; j <= w; ++j) { 29 | d[i][j] = max(d[i - 1][j - 1], d[i - 1][j]) + ((j & 1) + 1 == a[i]); 30 | } 31 | } 32 | int ans = 0; 33 | for(j = 0; j <= w; ++j) { 34 | ans = max(ans, d[n - 1][j]); 35 | } 36 | printf("%d\n", ans); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /src/poj2392.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2392: Space Elevator 3 | * 题意:给出多种砖,属性包含高度、数量、高度阈值。求可以垒出的最大高度。 4 | * 类型:DP+贪心 5 | * 算法:将砖块按阈值升序排序,d[i]表示达到高度i时当前砖块最多剩余数。若达到i可以不使用当前类砖,则值为当前砖总数,否则从剩余大于0的高度转移。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | int d[40010]; 16 | 17 | struct B{ 18 | int h, c, a; 19 | bool operator<(const B& b) const { 20 | return a < b.a; 21 | } 22 | }b[410]; 23 | 24 | int main() { 25 | int n, i, j, H = 0; 26 | scanf("%d", &n); 27 | for(i = 0; i < n; ++i) { 28 | scanf("%d%d%d", &b[i].h, &b[i].a, &b[i].c); 29 | H = max(H, b[i].a); 30 | } 31 | 32 | sort(b, b + n); 33 | 34 | memset(d, -1, sizeof(d)); 35 | d[0] = 0; 36 | for(i = 0; i < n; ++i) { 37 | for(j = 0; j <= b[i].a; ++j) { 38 | if(d[j] != -1) { 39 | d[j] = b[i].c; 40 | } else if(j >= b[i].h && d[j - b[i].h] > 0){ 41 | d[j] = d[j - b[i].h] - 1; 42 | } 43 | } 44 | } 45 | for(i = H; i >=0; --i) { 46 | if(d[i] != -1) { 47 | printf("%d\n", i); 48 | break; 49 | } 50 | } 51 | return 0; 52 | } -------------------------------------------------------------------------------- /src/poj2393.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2393: Yogurt factory 3 | * 题意:每个时段产奶单位成本不同,单位重量单位时间储奶花费为s常量。已知每个时段的牛奶需求量,求最小成本。 4 | * 类型:贪心 5 | * 算法:可以将第i时刻的单位成本减去s*i修正,第i时段需要的奶应该由前i个时段修正成本最小的产出,加入总成本时再每单位加s*i恢复并存储。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | 14 | int main() { 15 | int n, s; 16 | int c, y; 17 | double ans = 0, mm = 100000; 18 | int p = -1; 19 | scanf("%d%d", &n, &s); 20 | for(int i = 0; i < n; ++i) { 21 | scanf("%d%d", &c, &y); 22 | c -= i * s; 23 | if(c < mm) { 24 | mm = c; 25 | p = i; 26 | } 27 | ans += (mm + i * s) * y; 28 | } 29 | printf("%.0f\n", ans); 30 | return 0; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/poj2395.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2395: Out of Hay 3 | * 题意:从待选的路里面选出若干将所有点连通,求选出的边里最长边的最小值。 4 | * 类型:最小生成树 5 | * 算法:要使得树的最长边最小,那么每次确定的边都应是待选边里最小的,即最小生成树。对应Kruskal算法优先队列取最小值,再用并查集判断连接。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | struct E{ 15 | E() {} 16 | E(int uu, int vv, int cc): u(uu), v(vv), c(cc) {} 17 | bool operator > (const E& e) const { 18 | return c > e.c; 19 | } 20 | int u, v, c; 21 | }; 22 | 23 | int fa[2010]; 24 | priority_queue, greater > pq; 25 | 26 | int find(int x) { 27 | if(x == fa[x]) return x; 28 | return fa[x] = find(fa[x]); 29 | } 30 | 31 | int Kruskal(int n) { 32 | for(int i = 1; i <= n; ++i) { 33 | fa[i] = i; 34 | } 35 | int cnt = 1; 36 | int ans = 0; 37 | 38 | while(cnt < n && !pq.empty()) { 39 | const E& e = pq.top(); 40 | int u, v, c; 41 | u = e.u; 42 | v = e.v; 43 | c = e.c; 44 | pq.pop(); 45 | 46 | u = find(u); 47 | v = find(v); 48 | if(u == v) continue; 49 | fa[u] = v; 50 | ans = c; 51 | ++cnt; 52 | } 53 | if(cnt < n) { 54 | return -1; 55 | } else { 56 | return ans; 57 | } 58 | } 59 | 60 | int main() { 61 | int n, m; 62 | scanf("%d%d", &n, &m); 63 | while(m--) { 64 | int u, v, c; 65 | scanf("%d%d%d", &u, &v, &c); 66 | pq.push(E(u, v ,c)); 67 | } 68 | printf("%d\n", Kruskal(n)); 69 | return 0; 70 | } -------------------------------------------------------------------------------- /src/poj2407.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2407: Relatives 3 | * 题意:给出一个数,求比它小且与它互素的数个数。 4 | * 类型:数论 5 | * 算法:预处理筛法打素数表。分解质因数n=p1^a1*p2^a2...,则欧拉函数φ(n)=n/p1/p2/...*(p1-1)*(p2-1)*... 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | 12 | int prime[10010]; 13 | int cntp; 14 | bool np[31624]; 15 | 16 | void SievePrime(int n = 31623) { 17 | for (int i = 2; i <= n; ++i) { 18 | if (!np[i]) prime[cntp++] = i; 19 | int t; 20 | for (int j = 0; j < cntp && (t = i * prime[j]) <= n; ++j) { 21 | np[t] = 1; 22 | if (i % prime[j] == 0) break; 23 | } 24 | } 25 | } 26 | 27 | int main() { 28 | SievePrime(); 29 | int n; 30 | while (scanf("%d", &n) != EOF && n) { 31 | int ans = n; 32 | int m = 0; 33 | int p[33]; 34 | int a[33]; 35 | int up = (int)sqrt(n + 1); 36 | for (int i = 0; i < cntp && prime[i] <= up && n > 1; ++i) { 37 | if (n % prime[i] == 0) { 38 | p[m] = prime[i]; 39 | a[m++] = 0; 40 | } 41 | while (n % prime[i] == 0) { 42 | n /= prime[i]; 43 | ++a[m - 1]; 44 | } 45 | } 46 | if (n > 1) { 47 | p[m] = n; 48 | a[m++] = 1; 49 | } 50 | for (int i = 0; i < m; ++i) { 51 | ans /= p[i]; 52 | ans *= p[i] - 1; 53 | } 54 | printf("%d\n", ans); 55 | } 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /src/poj2409.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2409: Let it Bead 3 | * 题意:多种颜色的珠子串称一定长度的链子,翻转或旋转后重合的视为同一种,求共有多少种不同的。 4 | * 类型:Pólya计数 5 | * 算法:L=|1/G|*(m^c(p1)+m^c(p2)+...+m^c(pk))。G为置换群,m为颜色,c(pi)表示第i个置换的循环节数。同时考虑翻转和旋转,置换群大小为2n。旋转i的循环节个数为gcd(n,i)。翻转时按奇偶讨论,n为奇数时为1+(n-1)/2,共n条对称轴;偶数时对称轴分过不过珠子两种,各n/2种情况,循环节分别为(n-2)/2+2+1和n/2。 6 | */ 7 | 8 | 9 | #include 10 | 11 | typedef long long LL; 12 | 13 | LL Gcd(LL a, LL b) { 14 | for (LL t; t = b;) { 15 | b = a % b; 16 | a = t; 17 | } 18 | return a; 19 | } 20 | 21 | LL Pow(LL a, LL b) { 22 | LL ans = 1; 23 | while (b--) ans *= a; 24 | return ans; 25 | } 26 | 27 | int main() { 28 | LL c, n; 29 | while (scanf("%lld%lld", &c, &n) != EOF && c + n > 0) { 30 | if (!c || !n) { 31 | printf("0\n"); 32 | continue; 33 | } 34 | 35 | LL ans = 0; 36 | 37 | // rotation 38 | for (LL i = 0; i < n; ++i) { 39 | ans += Pow(c, Gcd(n, i)); 40 | } 41 | 42 | // reflection 43 | if (n & 1) { 44 | ans += n * Pow(c, n / 2 + 1); 45 | } else { 46 | ans += n / 2 * (Pow(c, n / 2 + 1) + Pow(c, n / 2)); 47 | } 48 | 49 | ans /= 2 * n; 50 | printf("%lld\n", ans); 51 | } 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /src/poj2441.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2441: Arrange the Bulls 3 | * 题意:共n个牛,m个棚,每个牛有几个可选的牛棚。求使得每头牛都在不同牛棚中的方案数。 4 | * 类型:状态DP 5 | * 算法:二进制表示当前牛棚被选状态,每头牛加入时,对应将1的个数为牛数的dp值更新,转移采用或运算。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int d[1 << 20]; 15 | vector s[20]; 16 | int b[20][20]; 17 | int c[20]; 18 | 19 | int main() { 20 | int n, m; 21 | scanf("%d%d", &n, &m); 22 | for (int i = 0; i < n; ++i) { 23 | scanf("%d", &c[i]); 24 | for (int j = 0; j < c[i]; ++j) { 25 | scanf("%d", &b[i][j]); 26 | --b[i][j]; 27 | } 28 | } 29 | if (n > m) { 30 | printf("0\n"); 31 | return 0; 32 | } 33 | 34 | for (int i = (1 << m) - 1; i > 0; --i) { 35 | int x = i; 36 | int cnt = 0; 37 | while (x) { 38 | ++cnt; 39 | x -= x & -x; 40 | } 41 | s[cnt - 1].push_back(i); 42 | } 43 | 44 | int ans = 0; 45 | 46 | d[0] = 1; 47 | for (int i = 0; i < n; ++i) { 48 | for (int j = int(s[i].size() - 1); j >= 0; --j) { 49 | for (int k = 0; k < c[i]; ++k) { 50 | int op = 1 << b[i][k]; 51 | if (s[i][j] & op) { 52 | d[s[i][j]] += d[s[i][j] ^ op]; 53 | } 54 | } 55 | if (i == n - 1) { 56 | ans += d[s[i][j]]; 57 | } 58 | } 59 | } 60 | 61 | printf("%d\n", ans); 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /src/poj2482.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2482: Stars in Your Window 3 | * 题意:平面中给出若干亮度不同的星星,求用一个特定大小的矩形最多能框住的星星亮度和的最大值。 4 | * 类型:扫描线+线段树 5 | * 算法:以每个星星为中心,得到可以罩住它的矩形的左下角的范围,这些范围内的点增加星星亮度,由于落在框上的点不算,框不一定要整数起点,可另左下落在框上算。求亮度和最大的点即可。离散化x坐标,将矩形的横线段按y升序排列。一根横线从下向上扫描,遇到矩形下边将对应x范围都加亮度,上边框减亮度。每次用线段树更新和求最大值。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | typedef long long LL; 15 | 16 | const int MAXN = 10010; 17 | 18 | struct Seg { 19 | Seg() {} 20 | 21 | Seg(LL _x1, LL _x2, LL _y, LL _t) : x1(_x1), x2(_x2), y(_y), t(_t) {} 22 | 23 | LL x1, x2, y, t; 24 | 25 | bool operator<(const Seg &s) const { 26 | return y < s.y; 27 | } 28 | } s[MAXN << 1]; 29 | 30 | LL x[MAXN << 1]; 31 | int nx, n; 32 | LL H, W; 33 | 34 | LL t[1 << 16], lz[1 << 16]; 35 | 36 | void Down(int rt) { 37 | if (lz[rt]) { 38 | lz[rt << 1] += lz[rt]; 39 | lz[rt << 1 | 1] += lz[rt]; 40 | t[rt << 1] += lz[rt]; 41 | t[rt << 1 | 1] += lz[rt]; 42 | lz[rt] = 0; 43 | } 44 | } 45 | 46 | void Update(int rt, int l, int r, int a, int b, int c) { 47 | if (a <= l && r <= b) { 48 | lz[rt] += c; 49 | t[rt] += c; 50 | return; 51 | } 52 | int m = (l + r) >> 1; 53 | Down(rt); 54 | if (a <= m) { 55 | Update(rt << 1, l, m, a, b, c); 56 | } 57 | if (b > m) { 58 | Update(rt << 1 | 1, m + 1, r, a, b, c); 59 | } 60 | t[rt] = max(t[rt << 1], t[rt << 1 | 1]); 61 | } 62 | 63 | int main() { 64 | while (scanf("%d%lld%lld", &n, &W, &H) != EOF && n) { 65 | for (int i = 0; i < n; ++i) { 66 | LL a, b, c; 67 | scanf("%lld%lld%lld", &a, &b, &c); 68 | s[i] = Seg(a - W + 1, a, b - H + 1, c); 69 | s[i + n] = Seg(a - W + 1, a, b + 1, -c); 70 | x[i] = a - W + 1; 71 | x[i + n] = a; 72 | } 73 | sort(x, x + n * 2); 74 | nx = unique(x, x + n * 2) - x; 75 | 76 | for (int i = 0; i < n; ++i) { 77 | s[i].x1 = s[i + n].x1 = lower_bound(x, x + nx, s[i].x1) - x; 78 | s[i].x2 = s[i + n].x2 = lower_bound(x, x + nx, s[i].x2) - x; 79 | } 80 | sort(s, s + n * 2); 81 | 82 | LL ans = 0; 83 | memset(t, 0, sizeof(t)); 84 | memset(lz, 0, sizeof(lz)); 85 | LL line = -10000000; 86 | for (int i = 0; i < n << 1; ++i) { 87 | if (s[i].y != line) { 88 | ans = max(ans, t[1]); 89 | line = s[i].y; 90 | } 91 | Update(1, 0, nx - 1, s[i].x1, s[i].x2, s[i].t); 92 | } 93 | ans = max(ans, t[1]); 94 | printf("%lld\n", ans); 95 | } 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /src/poj2549.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2549: Sumsets 3 | * 题意:给出有正有负的序列,选取4个数,使a+b+c=d。求d可能的最大值。 4 | * 类型:双向搜索 5 | * 算法:序列预处理排序;一层循环从大到小枚举d,二层枚举c;a、b初始化指向首和尾,若a+b+c-d=0则找到d,大于0则尾退,小于0则首进。O(n^3),数据弱,AC。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int x[1010]; 14 | 15 | int main() { 16 | int n; 17 | while (scanf("%d", &n) != EOF && n) { 18 | for (int i = 0; i < n; ++i) scanf("%d", &x[i]); 19 | if (n < 4) { 20 | printf("no solution\n"); 21 | continue; 22 | } 23 | sort(x, x + n); 24 | int a, b, c, d, s, t; 25 | bool ok = false; 26 | for (d = n - 1; d >= 0; --d) { 27 | for (c = 0; c < n; ++c) { 28 | if (c == d) continue; 29 | a = 0; 30 | b = n - 1; 31 | t = x[c] - x[d]; 32 | while (a < b) { 33 | if (a == c || a == d) ++a; 34 | if (b == c || b == d) --b; 35 | if (a >= b) break; 36 | s = t + x[a] + x[b]; 37 | if (s == 0) { 38 | ok = true; 39 | break; 40 | } else if (s > 0) { 41 | --b; 42 | } else if (s < 0) { 43 | ++a; 44 | } 45 | } 46 | if(ok) break; 47 | } 48 | if(ok) break; 49 | } 50 | if (ok) { 51 | printf("%d\n", x[d]); 52 | } else { 53 | printf("no solution\n"); 54 | } 55 | } 56 | return 0; 57 | } -------------------------------------------------------------------------------- /src/poj2566.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2566: Bound Found 3 | * 题意:给出一个可正可负的系列和一个非负目标值,求一段和的绝对值最接近目标值的子序列。 4 | * 类型:尺取法 5 | * 算法:求累加和后排序,尺取法控制递增的左右端点,使得累加和相减最接近目标值。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | typedef pair pii; 15 | 16 | pii s[100010]; 17 | 18 | inline int ABS(int x) { 19 | if (x >= 0) return x; 20 | return -x; 21 | } 22 | 23 | int main() { 24 | int n, k, a; 25 | while (scanf("%d%d", &n, &k) != EOF && n) { 26 | s[0].first = 0; 27 | s[0].second = 0; 28 | for (int i = 1; i <= n; ++i) { 29 | scanf("%d", &a); 30 | s[i].first = s[i - 1].first + a; 31 | s[i].second = i; 32 | } 33 | sort(s, s + n + 1); 34 | while (k--) { 35 | int t, tmp; 36 | int ans, p, q; 37 | ans = 2000000001; 38 | scanf("%d", &t); 39 | 40 | int i = 0, j = 1; 41 | while (i < j && j <= n) { 42 | tmp = s[j].first - s[i].first; 43 | if (ABS(tmp - t) < ABS(ans - t)) { 44 | ans = tmp; 45 | p = i; 46 | q = j; 47 | } 48 | 49 | if (tmp == t) { // two pointers 50 | break; 51 | } else if (tmp > t) { 52 | ++i; 53 | if (i == j) ++j; 54 | } else if (tmp < t) { 55 | ++j; 56 | } 57 | } 58 | p = s[p].second; 59 | q = s[q].second; 60 | printf("%d %d %d\n", ans, min(p, q) + 1, max(p, q)); 61 | } 62 | } 63 | return 0; 64 | } -------------------------------------------------------------------------------- /src/poj2674.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2674: Linear world 3 | * 题意:L长的平台上有n个人匀速移动,给出初始位置和移动方向。相遇的两个人会立刻掉头。求最后一个走出平台的人及所花时间。 4 | * 类型:智力题 5 | * 算法:两个人相遇后掉头可以看作是两个人都沿原来的方向继续前进,不影响时间,遍历可得最长时间。同时可知走出平台的方向和初始方向人数对应。n个人的相对顺序永远不变,若最后一个人的方向向左,共a个人从左边消失,则第a人就是最后消失的人;反向同理。 6 | */ 7 | 8 | #include 9 | 10 | char name[32010][260]; 11 | char op[3]; 12 | 13 | int main() { 14 | double l, v; 15 | double ans; 16 | bool left; 17 | int n, a; 18 | while (scanf("%d", &n) != EOF && n) { 19 | a = 0; 20 | scanf("%lf%lf", &l, &v); 21 | ans = 0; 22 | for (int i = 0; i < n; ++i) { 23 | double pos; 24 | scanf("%s%lf", op, &pos); 25 | scanf("%s", name[i]); 26 | if (op[0] == 'p' || op[0] == 'P') { 27 | pos = l - pos; 28 | if (pos > ans) { 29 | ans = pos; 30 | left = false; 31 | } 32 | } else { 33 | ++a; 34 | if (pos > ans) { 35 | ans = pos; 36 | left = true; 37 | } 38 | } 39 | } 40 | 41 | long long time = (long long) (ans / v * 100); 42 | ans = time / 100.0; 43 | printf("%13.2f %s\n", ans, name[a - left]); 44 | } 45 | 46 | return 0; 47 | } -------------------------------------------------------------------------------- /src/poj2718.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2718: Smallest Difference 3 | * 题意:给出不重复升序单数字,将其分为两组打乱顺序后组成整数,求两个整数的最小差值。 4 | * 类型:穷竭搜索+全排列 5 | * 算法:将序列全排列,按长度均分成两组,计算每个排列下的差值。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | const int INF = 1000000000; 17 | 18 | int n, a[10], ans, d[2]; 19 | 20 | int array2int(int s, int t) { 21 | int x = 0; 22 | if(a[s] == 0 && s + 1 < t){ 23 | return -1; 24 | } 25 | for(int i = s; i < t; ++i) { 26 | x = x * 10 + a[i]; 27 | } 28 | return x; 29 | } 30 | 31 | void solve() { 32 | ans = INF; 33 | d[0] = n / 2; 34 | d[1] = (n + 1) /2; 35 | int x, y; 36 | do{ 37 | for(int i = 0; i < 2; ++i) { 38 | if(i == 1 && d[1] == d[0]){ 39 | continue; 40 | } 41 | x = array2int(0, d[i]); 42 | y = array2int(d[i], n); 43 | if(x != -1 && y != -1){ 44 | ans = min(ans, abs(x - y)); 45 | } 46 | } 47 | }while(next_permutation(a, a + n)); 48 | } 49 | 50 | int main() { 51 | int Tcase; 52 | cin >> Tcase; 53 | cin.get(); 54 | while(Tcase--) { 55 | string str; 56 | getline(cin, str); 57 | stringstream ss(str); 58 | n = 0; 59 | while(ss >> a[n]){ 60 | ++n; 61 | }; 62 | solve(); 63 | cout << ans << endl; 64 | } 65 | return 0; 66 | } -------------------------------------------------------------------------------- /src/poj2723.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2723: Get Luffy Out 3 | * 题意:n对钥匙开m扇门,每扇门有2把锁,开任意一个门就可以打开。每对钥匙选其中一个就要丢弃另一个,顺序给出门上的锁对。问最多可以开多少扇门。 4 | * 类型:2-SAT+二分 5 | * 算法:一对钥匙ab等价a=>!b,b=>!a;开一扇锁为ab的门等价!a=>b,!b=>a。将钥匙的关系全部建边后,二分枚举开门数量并添加锁的边,每次强连通分量判定2-SAT即可。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | vector e[1 << 12]; 15 | vector re[1 << 12]; 16 | vector id; 17 | bool vis[1 << 12]; 18 | 19 | int tot; 20 | int tp[1 << 12]; 21 | 22 | 23 | void Dfs(int i) { 24 | vis[i] = 1; 25 | for (vector::iterator it = e[i].begin(); it != e[i].end(); ++it) { 26 | if (!vis[*it]) { 27 | Dfs(*it); 28 | } 29 | } 30 | id.push_back(i); 31 | } 32 | 33 | void RDfs(int i) { 34 | vis[i] = 1; 35 | tp[i] = tot; 36 | for (vector::iterator it = re[i].begin(); it != re[i].end(); ++it) { 37 | if (!vis[*it]) { 38 | RDfs(*it); 39 | } 40 | } 41 | } 42 | 43 | void AddEdge(int i, int j) { 44 | e[i].push_back(j); 45 | re[j].push_back(i); 46 | } 47 | 48 | bool Scc(int n) { 49 | id.clear(); 50 | memset(vis, 0, sizeof(vis)); 51 | for (int i = 0; i < n << 1; ++i) { 52 | if (!vis[i]) Dfs(i); 53 | } 54 | 55 | tot = 0; 56 | memset(vis, 0, sizeof(vis)); 57 | for (vector::iterator it = id.end() - 1; it >= id.begin(); --it) { 58 | if (!vis[*it]) { 59 | RDfs(*it); 60 | ++tot; 61 | } 62 | } 63 | 64 | bool ok = true; 65 | for (int i = 0; i < n; ++i) { 66 | if (tp[i] == tp[i + n]) { 67 | ok = false; 68 | break; 69 | } 70 | } 71 | return ok; 72 | } 73 | 74 | int key[1 << 10][2]; 75 | int lock[1 << 11][2]; 76 | 77 | void BuildGraph(int n, int m) { 78 | for (int i = (n << 2) - 1; i >= 0; --i) { 79 | e[i].clear(); 80 | re[i].clear(); 81 | } 82 | 83 | for (int i = 0; i < n; ++i) { 84 | AddEdge(key[i][0], key[i][1] + (n << 1)); 85 | AddEdge(key[i][1], key[i][0] + (n << 1)); 86 | } 87 | for (int i = 0; i < m; ++i) { 88 | AddEdge(lock[i][0] + (n << 1), lock[i][1]); 89 | AddEdge(lock[i][1] + (n << 1), lock[i][0]); 90 | } 91 | } 92 | 93 | int main() { 94 | int n, m; 95 | while (scanf("%d%d", &n, &m) != EOF && n) { 96 | for (int i = 0; i < n; ++i) { 97 | scanf("%d%d", &key[i][0], &key[i][1]); 98 | } 99 | for (int i = 0; i < m; ++i) { 100 | scanf("%d%d", &lock[i][0], &lock[i][1]); 101 | } 102 | int l, r, mid; 103 | l = 0, r = m + 1; 104 | while (l + 1 < r) { 105 | mid = (l + r) >> 1; 106 | BuildGraph(n, mid); 107 | if (Scc(n << 1)) { 108 | l = mid; 109 | } else { 110 | r = mid; 111 | } 112 | } 113 | printf("%d\n", l); 114 | } 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /src/poj2724.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2724: Purifying Machine 3 | * 题意:奶酪用二进制编号,有一台二进制机器可通过二进制数或带有一位*的正则匹配1块或2块奶酪。先给出一些机器操作序列污染了一批奶酪,求现在要不影响未污染的奶酪并且把所有被污染的奶酪净化需要的最少操作数。 4 | * 类型:二分匹配 5 | * 算法:二进制只有一位不同的数可建边,边表示带*的操作。由于建边的两个数二进制中1的个数必为一奇一偶,所以图为二分图。匈牙利算法求得最大二分匹配,被污染的奶酪数减去最大匹配即为答案。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | bool odd[1030]; 14 | bool infect[1030]; 15 | bool vis[1030]; 16 | int rec[1030]; 17 | int n, m; 18 | 19 | bool Dfs(int u) { 20 | for (int i = 0; i < n; ++i) { 21 | int v = u ^(1 << i); 22 | if (infect[v] && !vis[v]) { 23 | vis[v] = 1; 24 | if (rec[v] == -1 || Dfs(rec[v])) { 25 | rec[v] = u; 26 | return true; 27 | } 28 | } 29 | } 30 | return false; 31 | } 32 | 33 | int Hungary() { 34 | int ans = 0; 35 | memset(rec, -1, sizeof(rec)); 36 | for (int i = (1 << n) - 1; i >= 0; --i) { 37 | if (infect[i] && odd[i]) { 38 | memset(vis, 0, sizeof(vis)); 39 | if (Dfs(i)) ++ans; 40 | } 41 | } 42 | return ans; 43 | } 44 | 45 | int main() { 46 | for (int i = 0; i < 1024; ++i) { 47 | int j = i, cnt = 0; 48 | while (j) { 49 | if (j & 1) ++cnt; 50 | j >>= 1; 51 | } 52 | if (cnt & 1) odd[i] = 1; 53 | } 54 | while (scanf("%d%d", &n, &m) != EOF && n) { 55 | memset(infect, 0, sizeof(infect)); 56 | for (int i = 0; i < m; ++i) { 57 | char op[12]; 58 | scanf("%s", op); 59 | int s = -1, t = 0; 60 | for (int j = 0; j < n; ++j) { 61 | t <<= 1; 62 | if (op[j] == '1') { 63 | t |= 1; 64 | } else if (op[j] == '*') { 65 | s = j; 66 | } 67 | } 68 | infect[t] = 1; 69 | if (s != -1) { 70 | infect[1 << (n - 1 - s) | t] = 1; 71 | } 72 | } 73 | int ans = 0; 74 | for (int i = (1 << n) - 1; i >= 0; --i) { 75 | if (infect[i]) ++ans; 76 | } 77 | ans -= Hungary(); 78 | printf("%d\n", ans); 79 | } 80 | return 0; 81 | } -------------------------------------------------------------------------------- /src/poj2739.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2739: Sum of Consecutive Prime Numbers 3 | * 题意:将一个数分解为素数表中连续的素数的和,求分解方式有多少种。 4 | * 类型:尺取法 5 | * 算法:筛法打素数表,尺取法控制左右端点向后移动,若当前和等于待分解数则答案递增,小于则右端点右移并增加对应位置素数,否则左端点右移减小素数。 6 | */ 7 | 8 | #include 9 | 10 | int p[10010 >> 3], cntp; 11 | bool np[10010]; 12 | 13 | void SievePrime(int n) { 14 | int i, j, t; 15 | for (i = 2; i <= n; ++i) { 16 | if (!np[i]) { 17 | p[cntp++] = i; 18 | } 19 | for (j = 0; j < cntp && (t = i * p[j]) <= n; ++j) { 20 | np[t] = 1; 21 | if (i % p[j] == 0) break; 22 | } 23 | } 24 | } 25 | 26 | int main() { 27 | SievePrime(10000); 28 | int n; 29 | while (scanf("%d", &n) != EOF && n) { 30 | int i = 0, j = 1, ans = 0; 31 | int tmp = p[0]; 32 | while (i < j && j <= cntp) { 33 | if (tmp == n) { 34 | ++ans; 35 | tmp -= p[i++]; 36 | tmp += p[j++]; 37 | } else if (tmp < n) { 38 | tmp += p[j++]; 39 | } else { 40 | tmp -= p[i++]; 41 | if (i == j) tmp += p[j++]; 42 | } 43 | } 44 | printf("%d\n", ans); 45 | } 46 | return 0; 47 | } -------------------------------------------------------------------------------- /src/poj2823.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2823: Sliding Window 3 | * 题意:给出一个数列和固定大小的滑动窗口,求窗口移动过程中每次窗口内的最小和最大值。 4 | * 类型:双端队列 5 | * 算法:若要求窗口内最小值,则每个点左侧大于等于它的点可去除,所以保留窗口内的递增序列;同理,求最大值则保留窗口内的递减序列。(c++ ac, g++ tle) 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int a[1000010]; 14 | int mi[1000010], ma[1000010]; 15 | deque q, q2; 16 | 17 | int main () { 18 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 19 | int n, k; 20 | scanf("%d%d", &n, &k); 21 | if (k > n) k = n; 22 | for (int i = 0; i < n; ++i) scanf("%d", &a[i]); 23 | 24 | for (int i = 0; i < n; ++i) { 25 | if (!q.empty() && q.front() == i - k) q.pop_front(); 26 | if (!q2.empty() && q2.front() == i - k) q2.pop_front(); 27 | 28 | while (!q.empty() && a[q.back()] >= a[i]) q.pop_back(); 29 | q.push_back(i); 30 | 31 | while (!q2.empty() && a[q2.back()] <= a[i]) q2.pop_back(); 32 | q2.push_back(i); 33 | 34 | if (i >= k - 1) { 35 | mi[i] = a[q.front()]; 36 | ma[i] = a[q2.front()]; 37 | } 38 | } 39 | 40 | for (int i = k - 1; i < n - 1; ++i) printf("%d ", mi[i]); 41 | printf("%d\n", mi[n - 1]); 42 | 43 | for (int i = k - 1; i < n - 1; ++i) printf("%d ", ma[i]); 44 | printf("%d\n", ma[n - 1]); 45 | 46 | return 0; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/poj2836.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2836: Rectangular Covering 3 | * 题意:给出平面上n个点,用若干矩形将所有点覆盖,要求每个矩形覆盖至少2个点。求矩形的面积和最小值。 4 | * 类型:状态DP 5 | * 算法:状态内的点一定被覆盖,但被覆盖的点不一定在状态内,预处理出任意两点构成的矩形面积和包含的点状态。记忆化dp递归时,选取状态内的点与整个平面的点构成矩形。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | const int INF = 0x3f3f3f3f; 16 | 17 | int d[1 << 15]; 18 | int x[20], y[20]; 19 | int n; 20 | 21 | int a[20][20]; 22 | int p[20][20]; 23 | 24 | void gao(int xa, int ya, int xb, int yb, int &x1, int &y1, int &x2, int &y2, int &type) { 25 | int t; 26 | if (xa > xb) { 27 | t = xa; xa = xb; xb = t; 28 | } 29 | if (ya > yb) { 30 | t = ya; ya = yb; yb = t; 31 | } 32 | x1 = xa; x2 = xb; y1 = ya; y2 = yb; 33 | type = 0; 34 | if (xa == xb) { 35 | ++x2; 36 | type = 1; 37 | } 38 | if (ya == yb) { 39 | ++y2; 40 | type = 2; 41 | } 42 | } 43 | 44 | void pre() { 45 | int x1, y1, x2, y2, type, t; 46 | for (int i = 0; i < n - 1; ++i) { 47 | for (int j = i + 1; j < n; ++j) { 48 | gao(x[i], y[i], x[j], y[j], x1, y1, x2, y2, type); 49 | a[j][i] = a[i][j] = (x2 - x1) * (y2 - y1); 50 | t = 0; 51 | for (int k = 0; k < n; ++k) { 52 | if (x[k] >= x1 && x[k] <= x2 && y[k] >= y1 && y[k] <= y2) { 53 | t |= 1 << k; 54 | } 55 | } 56 | p[j][i] = p[i][j] = t; 57 | } 58 | } 59 | } 60 | 61 | int dfs(int s) { 62 | if (d[s] < INF) return d[s]; 63 | int b[20], cnt = 0; 64 | int t = s; 65 | for (int i = 0; i < n; ++i) { 66 | if (t & 1) b[cnt++] = i; 67 | t >>= 1; 68 | } 69 | for (int i = 0; i < cnt; ++i) { 70 | for (int j = 0; j < n; ++j) { 71 | if (j == b[i]) continue; 72 | d[s] = min(d[s], dfs(s & (~p[b[i]][j])) + a[b[i]][j]); 73 | } 74 | } 75 | return d[s]; 76 | } 77 | 78 | int main() { 79 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 80 | while (scanf("%d", &n) != EOF && n) { 81 | for (int i = 0; i < n; ++i) { 82 | scanf("%d%d", &x[i], &y[i]); 83 | } 84 | pre(); 85 | memset(d, 0x3f, sizeof(d)); 86 | d[0] = 0; 87 | printf("%d\n", dfs((1 << n) - 1)); 88 | } 89 | return 0; 90 | } 91 | 92 | -------------------------------------------------------------------------------- /src/poj2886.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2886: Who Gets the Most Candies? 3 | * 题意:n个孩子围成一圈,每个人手上有个数字。先选择一个孩子出局,根据他手上的数字选择下一个孩子,以此类推。第k轮出局的人获得k的因子个数的糖果,求获得最多的孩子及糖果数。 4 | * 类型:二分+树状数组(/线段树) 5 | * 算法:预处理打表n内的因子数。若已经出局k人,他手上数字是x,则先将x%(n-k)得到单圈内转移的人数。二分下一个孩子的序号,树状数组得到他们间剩余孩子数和模数相比,得到最小等于模数的序号。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | int prime[800]; 17 | bool np[800]; 18 | int cnt_prime; 19 | 20 | int factor[500010]; 21 | int mf[500010]; 22 | 23 | void seive_factor(int n) { 24 | int max_factor = 0; 25 | fill(factor, factor + n, 1); 26 | for (int i = 2; i < n; ++i) { 27 | if (factor[i] == 1) { 28 | for (int j = i; j < n; j += i) { 29 | int k = 0, t = j; 30 | while(t % i == 0) { 31 | ++k; 32 | t /= i; 33 | } 34 | factor[j] *= k + 1; 35 | } 36 | } 37 | if (factor[i] > max_factor) { 38 | max_factor = factor[i]; 39 | mf[i] = i; 40 | } else { 41 | mf[i] = mf[i - 1]; 42 | } 43 | } 44 | } 45 | 46 | int bit[500010]; 47 | int n; 48 | 49 | int low_bit(int x) { 50 | return x & -x; 51 | } 52 | 53 | void change(int x) { 54 | ++x; 55 | while (x <= n) { 56 | bit[x] += 1; 57 | x += low_bit(x); 58 | } 59 | } 60 | 61 | int query(int x) { 62 | ++x; 63 | int ans = 0; 64 | while (x) { 65 | ans += bit[x]; 66 | x -= low_bit(x); 67 | } 68 | return ans; 69 | } 70 | 71 | char name[500010][12]; 72 | int card[500010]; 73 | 74 | int main() { 75 | seive_factor(500010); // seive factor as seive prime then caculate factor will TLE 76 | int k, move, cnt; 77 | while (scanf("%d%d", &n, &k) != EOF) { 78 | memset(bit, 0, sizeof(bit)); 79 | --k; 80 | for (int i = 0; i < n; ++i) { 81 | scanf("%s%d", name[i], &card[i]); 82 | } 83 | int des = mf[n]; 84 | cnt = 1; 85 | while (cnt < des) { 86 | change(k); 87 | int mod = n - cnt; 88 | move = k - query(k) + card[k]; 89 | if (card[k] < 0) move += 1; 90 | move = ((move % mod) + mod) % mod; 91 | 92 | int l, r, m; 93 | l = -1; 94 | r = n - 1; 95 | while(l + 1 < r) { 96 | m = (l + r) >> 1; 97 | int t = m - query(m); 98 | if (t >= move) { 99 | r = m; 100 | } else { 101 | l = m; 102 | } 103 | } 104 | k = r; 105 | ++cnt; 106 | } 107 | printf("%s %d\n", name[k], factor[des]); 108 | } 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /src/poj2914.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2914: Minimum Cut 3 | * 题意:给出无向图及各边边权,求全局最小割。 4 | * 类型:图论 5 | * 算法:Stoer-Wangner最小割算法:初始点集V,选取任意点移到A。之后每次从V中找到A的割最大的点放入A,V中只剩1个点的时候,用它的割更新解,并将它合并到上一个加入A的节点上。如此反复,知道图中合并为1个点。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int e[510][510]; 15 | int w[510]; 16 | int id[510]; 17 | bool vis[510]; 18 | 19 | int main() { 20 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 21 | int n, m; 22 | while (scanf("%d%d", &n, &m) != EOF) { 23 | memset(e, 0, sizeof(e)); 24 | for (int i = 0; i < n; ++i) id[i] = i; 25 | for (int i = 0; i < m; ++i) { 26 | int u, v, c; 27 | scanf("%d%d%d", &u, &v, &c); 28 | e[u][v] += c; 29 | e[v][u] += c; 30 | } 31 | 32 | int ans = 0x3f3f3f3f; 33 | while (n > 1) { 34 | memset(vis, 0, sizeof(vis)); 35 | memset(w, 0, sizeof(w)); 36 | int s, t = 0; 37 | vis[0] = 1; 38 | for (int i = 1; i < n; ++i) { 39 | s = t; 40 | t = -1; 41 | for (int j = 1; j < n; ++j) { 42 | if (!vis[j]) { 43 | w[j] += e[id[j]][id[s]]; 44 | if (t == -1 || w[j] > w[t]) { 45 | t = j; 46 | } 47 | } 48 | } 49 | vis[t] = 1; 50 | } 51 | ans = min(ans, w[t]); 52 | for (int i = 0; i < n; ++i) { 53 | if (i == s || i == t) continue; 54 | e[id[i]][id[s]] += e[id[i]][id[t]]; 55 | e[id[s]][id[i]] += e[id[i]][id[t]]; 56 | } 57 | id[t] = id[--n]; 58 | } 59 | printf("%d\n", ans); 60 | } 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /src/poj2975.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2975: Nim 3 | * 题意:给出每堆石头的数量,问转移到必败态的方法有多少种。 4 | * 类型:Nim博弈 5 | * 算法:若某堆石头数量大于其他所有的xor,则可将其变为其他值的xor,使得全部的xor为0。 6 | */ 7 | 8 | 9 | #include 10 | 11 | int a[1010]; 12 | 13 | int main() { 14 | int n; 15 | while (scanf("%d", &n) != EOF && n) { 16 | int s = 0; 17 | for (int i = 0; i < n; ++i) { 18 | scanf("%d", &a[i]); 19 | s ^= a[i]; 20 | } 21 | int ans = 0; 22 | for (int i = 0 ;i < n; ++i) { 23 | if ((s ^ a[i]) < a[i]) ++ans; 24 | } 25 | printf("%d\n", ans); 26 | } 27 | return 0; 28 | } -------------------------------------------------------------------------------- /src/poj2976.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2976: Dropping tests 3 | * 题意:给出每场考试的总题数和得分,可以舍弃若干场考试的成绩。求剩余考试的得分总和除以总题数的最大值。 4 | * 类型:二分搜索+贪心 5 | * 算法:二分搜索最大的综合得分率,有E(a)/E(b)>=m,将成绩按ai-bj*m排序,取最大的k个相加看是否能大于等于0使得前式被满足。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | typedef long long LL; 15 | 16 | const double EPS = 1e-7; 17 | 18 | LL a[1010], b[1010]; 19 | 20 | double c[1010]; 21 | 22 | int main() { 23 | int n, k; 24 | while (scanf("%d%d", &n, &k) != EOF && n) { 25 | for (int i = 0; i < n; ++i) { 26 | scanf("%lld", &a[i]); 27 | } 28 | for (int i = 0; i < n; ++i) { 29 | scanf("%lld", &b[i]); 30 | } 31 | 32 | double l, r, m; 33 | l = 0.0; 34 | r = 1.0; 35 | while (r - l > EPS) { 36 | m = (l + r) / 2; 37 | for (int i = 0; i < n; ++i) { 38 | c[i] = a[i] - m * b[i]; 39 | } 40 | sort(c, c + n); 41 | double tmp = 0; 42 | for(int i = k; i < n; ++i) { 43 | tmp += c[i]; 44 | } 45 | if(tmp > -EPS) { 46 | l = m; 47 | } else { 48 | r = m; 49 | } 50 | } 51 | 52 | printf("%0.0f\n", 100 * l); 53 | } 54 | return 0; 55 | } -------------------------------------------------------------------------------- /src/poj3009.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3009: Curling 2.0 3 | * 题意:m*n矩阵中,给出起点、终点、空格、障碍,从每个点可向4方前进,直到遇到障碍,打碎并停在障碍格的前面。求到达终点的最少前进次数。 4 | * 类型:DFS+记忆化搜索 5 | * 算法:从某点出发,向4个方向投掷,遇到障碍格,标记其为空格状态,继续递归障碍前一点,回退恢复障碍状态。每次递归直至到达终点或全部出界失败。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | const int INF = 1000; 15 | const int TYPE_VACANT = 0; 16 | const int TYPE_BLOCK = 1; 17 | const int TYPE_START = 2; 18 | const int TYPE_GOAL = 3; 19 | const int MAX_THROW = 10; 20 | 21 | int m, n; 22 | int mat[22][22]; 23 | int dx[4] = {-1, 0, 1, 0}; 24 | int dy[4] = {0, 1, 0, -1}; 25 | int ans; 26 | 27 | void dfs(int x, int y, int step) { 28 | if(step >= MAX_THROW) { 29 | return; 30 | } 31 | for(int i = 0; i < 4; ++i) { 32 | int xx = x; 33 | int yy = y; 34 | while(true) { 35 | xx += dx[i]; 36 | yy += dy[i]; 37 | if(xx < 0 || xx >= m || yy < 0 || yy >= n) { 38 | break; 39 | } 40 | if(mat[xx][yy] == TYPE_GOAL) { 41 | ans = min(ans, step + 1); 42 | break; 43 | } 44 | if(mat[xx][yy] == TYPE_BLOCK) { 45 | mat[xx][yy] = TYPE_VACANT; 46 | int prex = xx - dx[i]; 47 | int prey = yy - dy[i]; 48 | if(prex != x || prey != y) { 49 | dfs(prex, prey, step + 1); 50 | } 51 | mat[xx][yy] = TYPE_BLOCK; 52 | break; 53 | } 54 | } 55 | } 56 | } 57 | 58 | void solve() { 59 | ans = INF; 60 | int sx, sy; 61 | for(int i = 0; i < m; ++i) { 62 | for(int j = 0; j < n; ++j) { 63 | cin >> mat[i][j]; 64 | if(mat[i][j] == TYPE_START){ 65 | sx = i; 66 | sy = j; 67 | } 68 | } 69 | } 70 | dfs(sx, sy, 0); 71 | if(ans == INF){ 72 | ans = -1; 73 | } 74 | } 75 | 76 | int main() { 77 | while(cin >> n >> m && n > 0 && m > 0) { 78 | solve(); 79 | cout << ans << endl; 80 | } 81 | return 0; 82 | } -------------------------------------------------------------------------------- /src/poj3040.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3040; Allowance 3 | * 题意:有一些面值不同的硬币,排序后相邻两个的面值可以整除。每周需要支付定额的最低福利C,求这些硬币可以成功应付多少周。 4 | * 类型:贪心 5 | * 算法:求可行硬币组合的方法是,从大到小取不超过C的硬币组合,如果不够C,再从小到达取1枚超过C。求满足该组合的套数,再计算新的组合。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | pair c[22]; 15 | 16 | int cnt[22]; 17 | 18 | int main() { 19 | int n, s, ans = 0; 20 | scanf("%d%d", &n, &s); 21 | for(int i = 0; i < n; ++i) { 22 | scanf("%d%d", &c[i].first , &c[i].second); 23 | } 24 | 25 | sort(c, c + n, greater > ()); 26 | 27 | while(1) { 28 | int tmp = 100000000, ss = s; 29 | for(int i = 0; i < n && s > 0; ++i) { 30 | cnt[i] = min(c[i].second, ss / c[i].first); 31 | ss -= cnt[i] * c[i].first; 32 | } 33 | if(ss > 0) { 34 | for(int i = n - 1; i >= 0; --i) { 35 | if(c[i].second > cnt[i]) { 36 | ss -= c[i].first; 37 | cnt[i]++; 38 | break; 39 | } 40 | } 41 | } 42 | if(ss > 0) break; 43 | for(int i = 0; i < n; ++i) { 44 | if (cnt[i] > 0) { 45 | tmp = min(tmp, c[i].second / cnt[i]); 46 | } 47 | } 48 | ans += tmp; 49 | for(int i = 0; i < n; ++i) { 50 | if (cnt[i] > 0) { 51 | c[i].second -= tmp * cnt[i]; 52 | } 53 | } 54 | } 55 | printf("%d\n", ans); 56 | return 0; 57 | } -------------------------------------------------------------------------------- /src/poj3045.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3045: Cow Acrobats 3 | * 题意:每头牛有体重和承重,让牛叠成一纵,每头牛的危险系数是其上总重量减自身承重。求最优的叠法使所有牛中最大的危险系数最小。 4 | * 类型:贪心+快排 5 | * 算法:只讨论中间两个,若i在j上优于j在i上,则max(-si,wi-sj) 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | struct Cow { 15 | int s, w; 16 | 17 | bool operator<(const Cow &c) const { 18 | return max(-s, w - c.s) < max(-c.s, c.w - s); 19 | } 20 | } cows[50010]; 21 | 22 | int main() { 23 | int n; 24 | scanf("%d", &n); 25 | for (int i = 0; i < n; ++i) { 26 | scanf("%d%d", &cows[i].w, &cows[i].s); 27 | } 28 | sort(cows, cows + n); 29 | 30 | int ans = -cows[0].s; 31 | int up = cows[0].w; 32 | for (int i = 1; i < n; ++i) { 33 | ans = max(ans, up - cows[i].s); 34 | up += cows[i].w; 35 | } 36 | printf("%d\n", ans); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /src/poj3046.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3046: Ant Counting 3 | * 题意:多族数量不定的蚂蚁,求组成一定规模范围的新蚁群的组合数。 4 | * 类型:DP 5 | * 算法:d[i][j]表示前i种蚂蚁,组成j规模的蚁群的组合数;每次由i-1中j的连续一段转移,所以用s[j]保存d[i]的前j项和。滚动数组降维。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int c[1010]; 14 | int d[100010], s[100010]; 15 | int T, A, S, B; 16 | 17 | int main() { 18 | scanf("%d%d%d%d", &T, &A, &S, &B); 19 | 20 | for(int i = 0; i < A; ++i) { 21 | int t; 22 | scanf("%d", &t); 23 | c[t]++; 24 | } 25 | 26 | d[0] = 1; 27 | for(int i = 0; i <= B; ++i) { 28 | s[i] = 1; 29 | } 30 | 31 | for(int i = 1; i <= T; ++i) { 32 | for(int j = 1; j <= B; ++j) { 33 | if(c[i] >= j) { 34 | d[j] = s[j]; 35 | } else { 36 | d[j] = (s[j] - s[j - c[i] - 1] + 1000000) % 1000000; 37 | } 38 | } 39 | 40 | s[0] = 1; 41 | for(int j = 1; j <= B; ++j) { 42 | s[j] = (s[j - 1] + d[j]) % 1000000; 43 | } 44 | } 45 | printf("%d\n", (s[B] - s[S - 1] + 1000000) % 1000000); 46 | return 0; 47 | } -------------------------------------------------------------------------------- /src/poj3050.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3050: Hopscotch 3 | * 题意:给出5*5的数字矩阵,从某点出发,向上下左右移动,总共经过6个点,并将其拼接为整数。求通过不同的起点和行走方式,最终可以得到多少个不同的整数。 4 | * 类型:DFS 5 | * 算法:经过一点,记录进路径,向4方未越界的点继续递归。移动5步可得到1个整数,若为新数则结果+1。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | int mat[5][5]; 16 | int d[6]; 17 | int ans; 18 | bool f[1000000]; 19 | int dx[4] = {0, 1, 0, -1}; 20 | int dy[4] = {-1, 0, 1, 0}; 21 | 22 | void dfs(int x, int y,int step) { 23 | d[step] = mat[x][y]; 24 | if(step == 5) { 25 | int tmp = 0; 26 | for(int i = 0; i < 6; ++i) { 27 | tmp = tmp * 10 + d[i]; 28 | } 29 | if(!f[tmp]) { 30 | f[tmp] = true; 31 | ans++; 32 | } 33 | return; 34 | } 35 | int xx, yy; 36 | for(int i = 0; i < 4; ++i) { 37 | xx = x + dx[i]; 38 | yy = y + dy[i]; 39 | if(xx >=0 && xx < 5 && yy >= 0 && yy < 5) { 40 | dfs(xx, yy, step + 1); 41 | } 42 | } 43 | } 44 | 45 | void solve() { 46 | ans = 0; 47 | memset(f, 0 ,sizeof(f)); 48 | for(int i = 0; i < 5; ++i) { 49 | for(int j = 0; j < 5; ++j) { 50 | dfs(i, j, 0); 51 | } 52 | } 53 | } 54 | 55 | int main() { 56 | for(int i = 0; i < 5; ++i) { 57 | for(int j = 0; j < 5; ++j) { 58 | cin >> mat[i][j]; 59 | } 60 | } 61 | solve(); 62 | cout << ans << endl; 63 | return 0; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/poj3104.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3104: Drying 3 | * 题意:每件衣服含一定水,自然情况每分钟水量-1,如果使用熨斗每分钟-k。熨斗每分钟只能熨一件衣服,求干燥所有衣服总时间的最小值。 4 | * 类型:二分搜索+贪心 5 | * 算法:二分搜索,最小化时间最大值。计算每件衣服除给出的自然晾干时间外需要使用熨斗的次数,总次数不超过总时间则可更新上届。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | long long a[100010]; 15 | 16 | int main() { 17 | int n, k; 18 | scanf("%d", &n); 19 | long long lv, rv, mv; 20 | lv = rv = 0; 21 | for (int i = 0; i < n; ++i) { 22 | scanf("%lld", &a[i]); 23 | rv = max(rv, a[i]); 24 | } 25 | scanf("%d", &k); 26 | if(k >= 2) { 27 | while (lv + 1 < rv) { 28 | mv = (lv + rv) >> 1; 29 | long long cnt = 0; 30 | for(int i = 0; i < n; ++i) { 31 | if(a[i] > mv) { 32 | cnt += (a[i] - mv - 1) / (k - 1) + 1; 33 | } 34 | } 35 | if(cnt <= mv) { 36 | rv = mv; 37 | } else { 38 | lv = mv; 39 | } 40 | } 41 | } 42 | printf("%lld\n", rv); 43 | return 0; 44 | } -------------------------------------------------------------------------------- /src/poj3111.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 2976: K Bests 3 | * 题意:给出每件首饰的价值和重量,选取k个使总价值除以总重量最大,求选取方案。 4 | * 类型:二分搜索+贪心 5 | * 算法:二分搜索最大的单位价值,有E(v)/E(w)>=m,将成绩按vi-wj*m排序,取最大的k个相加看是否能大于等于0使得前式被满足。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef long long LL; 16 | typedef pair pdi; 17 | 18 | const double EPS = 1e-7; 19 | 20 | LL a[100010], b[100010]; 21 | double c[100010]; 22 | 23 | vector d; 24 | 25 | int main() { 26 | int n, k; 27 | while (scanf("%d%d", &n, &k) != EOF) { 28 | d.clear(); 29 | for (int i = 0; i < n; ++i) { 30 | scanf("%lld%lld", &a[i], &b[i]); 31 | } 32 | double l, r, m; 33 | l = 0.0; 34 | r = 1000000.0; 35 | while (r - l > EPS) { 36 | m = (l + r) / 2; 37 | for (int i = 0; i < n; ++i) { 38 | c[i] = a[i] - m * b[i]; 39 | } 40 | sort(c, c + n); 41 | double tmp = 0; 42 | for(int i = n - k; i < n; ++i) { 43 | tmp += c[i]; 44 | } 45 | if(tmp > -EPS) { 46 | l = m; 47 | } else { 48 | r = m; 49 | } 50 | } 51 | 52 | for (int i = 0; i < n; ++i) { 53 | c[i] = a[i] - m * b[i]; 54 | d.push_back(make_pair(c[i], i)); 55 | } 56 | sort(d.begin(), d.end()); 57 | 58 | bool first = true; 59 | for(int i = n - k; i < n; ++i) { 60 | if(first) first = false; 61 | else printf(" "); 62 | printf("%d", d[i].second + 1); 63 | } 64 | printf("\n"); 65 | } 66 | return 0; 67 | } -------------------------------------------------------------------------------- /src/poj3126.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3126: Prime Path 3 | * 题意:给出两个四位素数,每步可变化任意一位,要求每步变化后所得都是素数。求最少步数。 4 | * 类型:素数+最短路 5 | * 算法:素数筛法打表,以素数为点,两个只相差一位的素数间连线,Dijkstra求最短路。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | typedef long long LL; 18 | typedef pair pii; 19 | 20 | const int MAXN = 10010; 21 | int p[MAXN>>3]; 22 | bool np[MAXN]; 23 | int cntp; 24 | int d[MAXN]; 25 | 26 | vector e[MAXN]; 27 | priority_queue, greater > pq; 28 | 29 | 30 | void SievePrime(int n) { 31 | LL t; 32 | for(int i = 2; i < n; ++i) { 33 | if(!np[i]) p[cntp++] = i; 34 | for(int j = 0; j < cntp && (t = 1ll * i * p[j]) < n; ++j) { 35 | np[t] = true; 36 | if(i % p[j] == 0) break; 37 | } 38 | } 39 | } 40 | 41 | void InitGraph() { 42 | for(int i = 0; i < cntp; ++i) { 43 | if(p[i] < 1000) continue; 44 | if(p[i] >= 10000) break; 45 | for(int j = i + 1; j < cntp; ++j) { 46 | int a = p[i], b = p[j]; 47 | if(a/10==b/10 || a/100==b/100 && a%10==b%10 || a/1000==b/1000 && a%100==b%100 || a%1000==b%1000) { 48 | e[a].push_back(b); 49 | e[b].push_back(a); 50 | } 51 | } 52 | } 53 | } 54 | 55 | int Dijkstra(int s, int t) { 56 | while(!pq.empty()) pq.pop(); 57 | memset(d, 0x3f, sizeof(d)); 58 | d[s] = 0; 59 | pq.push(make_pair(d[s], s)); 60 | while(!pq.empty()) { 61 | pii tmp = pq.top(); 62 | pq.pop(); 63 | int du = tmp.first, u = tmp.second; 64 | if(d[u] < du) continue; 65 | if(u == t) return du; 66 | for(vector::iterator it = e[u].begin(); it != e[u].end(); ++it) { 67 | int v = *it; 68 | if(d[v] > du + 1) { 69 | d[v] = du + 1; 70 | pq.push(make_pair(d[v], v)); 71 | } 72 | } 73 | } 74 | return -1; 75 | } 76 | 77 | int main() { 78 | SievePrime(10000); 79 | InitGraph(); 80 | int T; 81 | scanf("%d", &T); 82 | while(T--) { 83 | int a, b; 84 | scanf("%d%d", &a, &b); 85 | int ans = Dijkstra(a, b); 86 | int v = b; 87 | if(ans == -1) printf("Impossible\n"); 88 | else printf("%d\n", ans); 89 | } 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /src/poj3134.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3134: Power Calculus 3 | * 题意:给出x,通过乘法和除法得到中间结果,通过中间结果互相运算得到x^n需要最少多少步。 4 | * 类型:DFS 5 | * 算法:数的乘除转化为指数幂的加减,对每个n评估步数上届剪枝。将n转为二进制,则步数上届=最左1位置+1的个数-1。DFS时每次拿最后一个数和前面每个尝试加减并继续DFS。 6 | */ 7 | 8 | #include 9 | 10 | 11 | int ans[1 << 10]; 12 | int e[22] = {1}; 13 | 14 | void Dfs(int d) { 15 | if (d > 20) return; 16 | for (int i = 0; i <= d; ++i) { 17 | e[d + 1] = e[i] + e[d]; 18 | if (e[d + 1] < (1 << 10) && ans[e[d + 1]] >= d + 1) { 19 | ans[e[d + 1]] = d + 1; 20 | Dfs(d + 1); 21 | } 22 | e[d + 1] = e[d] - e[i]; 23 | if (e[d + 1] > 0 && ans[e[d + 1]] >= d + 1) { 24 | ans[e[d + 1]] = d + 1; 25 | Dfs(d + 1); 26 | } 27 | } 28 | } 29 | 30 | int main() { 31 | int n; 32 | for (int i = 1; i < 1 << 10; ++i) { 33 | ans[i] = (31 - __builtin_clz(i)) + __builtin_popcount(i) - 1; 34 | } 35 | Dfs(0); 36 | while (scanf("%d", &n) != EOF && n) { 37 | printf("%d\n", ans[n]); 38 | } 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/poj3168.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3168: Barn Expansion 3 | * 题意:给出平面若干个不重叠的矩形,求四边能向外扩展后仍不和其他矩形重叠的矩形有多少个。 4 | * 类型:扫描线 5 | * 算法:将矩形的x线按先x后y的升序排序,若2条x线可以连接上则两个两个矩形都不可扩展。y线按先y后x排序后同理。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | struct Seg { 14 | Seg() {} 15 | 16 | Seg(int _x1, int _x2, int _y, int _id) : x1(_x1), x2(_x2), y(_y), id(_id) {} 17 | 18 | int x1, x2, y, id; 19 | 20 | bool operator<(const Seg &t) const { 21 | if (y != t.y) return y < t.y; 22 | return x1 < t.x1; 23 | } 24 | }; 25 | 26 | Seg s[2][50010]; 27 | 28 | bool no[25010]; 29 | 30 | int main() { 31 | int n; 32 | scanf("%d", &n); 33 | for (int i = 0; i < n; ++i) { 34 | int a, b, c, d; 35 | scanf("%d%d%d%d", &a, &b, &c, &d); 36 | s[0][i] = Seg(b, d, a, i); 37 | s[0][i + n] = Seg(b, d, c, i); 38 | s[1][i] = Seg(a, c, b, i); 39 | s[1][i + n] = Seg(a, c, d, i); 40 | } 41 | for (int t = 0; t < 2; ++t) { 42 | sort(s[t], s[t] + 2 * n); 43 | int y = -1, pre = -1; 44 | for (int i = 0; i < n << 1; ++i) { 45 | if (s[t][i].y != y) { 46 | y = s[t][i].y; 47 | pre = i; 48 | } else { 49 | if (s[t][i].x1 <= s[t][pre].x2) { 50 | no[s[t][i].id] = no[s[t][pre].id] = 1; 51 | } 52 | if (s[t][i].x2 > s[t][pre].x2) { 53 | pre = i; 54 | } 55 | } 56 | } 57 | } 58 | int ans = 0; 59 | for (int i = 0; i < n; ++i) { 60 | if (!no[i]) { 61 | ++ans; 62 | } 63 | } 64 | printf("%d\n", ans); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /src/poj3171.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3171: Cleaning Shifts 3 | * 题意:用花费不一的一些区间去覆盖某个长区间,求总花费的最小值。 4 | * 类型:DP+线段树 5 | * 算法:预处理区间按右端点升序,d[i]表示已经从头覆盖到i坐标的最小代价。遍历到区间[a,b]时,线段树求的d在[a,b]的最小值,以更新d[b]。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | typedef long long LL; 17 | 18 | const int MAXN = 10010; 19 | const int MAXM = 1 << 18; 20 | const LL INF = 0x3f3f3f3f3f3f3f3f; 21 | 22 | LL mm[MAXM]; 23 | LL d[86400]; 24 | 25 | struct Cow { 26 | int a, b; 27 | LL s; 28 | 29 | bool operator<(const Cow &c) const { 30 | return b < c.b; 31 | } 32 | } cows[MAXN]; 33 | 34 | void update(int rt, int l, int r, int ql, LL c) { 35 | mm[rt] = min(mm[rt], c); 36 | if (l == r) return; 37 | int m = (l + r) >> 1; 38 | if (ql <= m) { 39 | update(rt << 1, l, m, ql, c); 40 | } else { 41 | update(rt << 1 | 1, m + 1, r, ql, c); 42 | } 43 | } 44 | 45 | LL query(int rt, int l, int r, int ql, int qr) { 46 | if (ql <= l && r <= qr) { 47 | return mm[rt]; 48 | } 49 | int m = (l + r) >> 1; 50 | LL ans = INF; 51 | if (ql <= m) { 52 | ans = min(ans, query(rt << 1, l, m, ql, qr)); 53 | } 54 | if (qr > m) { 55 | ans = min(ans, query(rt << 1 | 1, m + 1, r, ql, qr)); 56 | } 57 | return ans; 58 | } 59 | 60 | int main() { 61 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 62 | int n; 63 | int M, E; 64 | scanf("%d%d%d", &n, &M, &E); 65 | memset(mm, 0x3f, sizeof(mm)); 66 | memset(d, 0x3f, sizeof(d)); 67 | 68 | for (int i = 0; i < n; ++i) { 69 | scanf("%d%d%lld", &cows[i].a, &cows[i].b, &cows[i].s); 70 | } 71 | sort(cows, cows + n); 72 | for (int i = 0; i < n; ++i) { 73 | LL db = d[cows[i].b]; 74 | if (cows[i].a == M) { 75 | d[cows[i].b] = min(db, cows[i].s); 76 | } else { 77 | d[cows[i].b] = min(db, query(1, M, E, cows[i].a - 1, cows[i].b - 1) + cows[i].s); 78 | } 79 | if (d[cows[i].b] < db) { 80 | update(1, M, E, cows[i].b, d[cows[i].b]); 81 | } 82 | } 83 | printf("%lld\n", d[E] == INF ? -1 : d[E]); 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /src/poj3176.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3176: Cow Bowling 3 | * 题意:若干个数摆成三角,每次可以从上一层移动到下一层最近的两个点,求自顶向下的路径和最大值。 4 | * 类型:DP 5 | * 算法:滚动数组保存到达每个点的最大和,每个点由上方相邻两点转移。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int d[400]; 14 | int a[400]; 15 | 16 | int main() { 17 | int n, i, j; 18 | scanf("%d", &n); 19 | for(i = 0; i < n; ++i) { 20 | for(j = 0; j <= i; ++j) { 21 | scanf("%d", &a[j]); 22 | } 23 | if(i > 0) { 24 | d[i] = d[i - 1] + a[i]; 25 | } 26 | for(j = i - 1; j > 0; --j) { 27 | d[j] = max(d[j], d[j - 1]) + a[j]; 28 | } 29 | d[0] += a[0]; 30 | } 31 | int ans = 0; 32 | for(i = 0; i < n; ++i) { 33 | ans = max(ans, d[i]); 34 | } 35 | printf("%d\n", ans); 36 | return 0; 37 | } -------------------------------------------------------------------------------- /src/poj3180.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3180: The Cow Prom 3 | * 题意:n头牛顺时针围成圈,某些牛间用绳子沿圈顺时针相连。若一组牛的某一头顺时针或逆时针跳舞,其他某些牛都能顺时针或逆时针移动,则这一组是成功的。问有多少组成功组。 4 | * 类型:强连通分量 5 | * 算法:强连通分量中的点意味着可以顺逆同时移动,点数大于1的scc即为答案。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | vector e[10010]; 15 | vector re[10010]; 16 | vector id; 17 | bool vis[10010]; 18 | 19 | int tot; 20 | int cnt[10010]; 21 | 22 | 23 | void Dfs(int i) { 24 | vis[i] = 1; 25 | for (vector::iterator it = e[i].begin(); it != e[i].end(); ++it) { 26 | if (!vis[*it]) { 27 | Dfs(*it); 28 | } 29 | } 30 | id.push_back(i); 31 | } 32 | 33 | void RDfs(int i) { 34 | vis[i] = 1; 35 | ++cnt[tot]; 36 | for (vector::iterator it = re[i].begin(); it != re[i].end(); ++it) { 37 | if (!vis[*it]) { 38 | RDfs(*it); 39 | } 40 | } 41 | } 42 | 43 | int main() { 44 | int n, m; 45 | scanf("%d%d", &n, &m); 46 | while (m--) { 47 | int i, j; 48 | scanf("%d%d", &i, &j); 49 | e[i].push_back(j); 50 | re[j].push_back(i); 51 | } 52 | 53 | memset(vis, 0, sizeof(vis)); 54 | for (int i = 1; i <= n; ++i) { 55 | if (!vis[i]) Dfs(i); 56 | } 57 | 58 | memset(vis, 0, sizeof(vis)); 59 | for (vector::iterator it = id.end() - 1; it >= id.begin(); --it) { 60 | if (!vis[*it]) { 61 | RDfs(*it); 62 | ++tot; 63 | } 64 | } 65 | 66 | int ans = 0; 67 | for (int i = 0; i < tot; ++i) { 68 | if (cnt[i] > 1) { 69 | ++ans; 70 | } 71 | } 72 | printf("%d\n", ans); 73 | 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /src/poj3181.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3181: Dollar Dayz 3 | * 题意:面值为1~K的货币,求凑成和为N的组合数。 4 | * 类型:DP+大数 5 | * 算法:滚动数组d[i]表示和为i时使用当前或之前货币的组合数,用int模拟大数加法。 6 | */ 7 | 8 | #include 9 | 10 | const int LEN = 300; 11 | const int MOD = 100000000; 12 | 13 | void add(int* a, const int* b) { 14 | int jw = 0; 15 | for(int i = 0; i < LEN; ++i) { 16 | a[i] += b[i] + jw; 17 | jw = a[i] / MOD; 18 | a[i] %= MOD; 19 | } 20 | } 21 | 22 | void output(const int* a) { 23 | int i; 24 | for(i = LEN - 1; i >= 0; --i) { 25 | if(a[i] > 0) { 26 | break; 27 | } 28 | } 29 | printf("%d", a[i]); 30 | for(--i; i >= 0; --i) { 31 | printf("%08d", a[i]); 32 | } 33 | printf("\n"); 34 | } 35 | 36 | int d[1010][LEN]; 37 | int n, k; 38 | 39 | int main() { 40 | scanf("%d%d", &n, &k); 41 | d[0][0] = 1; 42 | for(int i = 1; i <= k; ++i) { 43 | for(int j = i; j <= n; ++j) { 44 | add(d[j], d[j - i]); 45 | } 46 | } 47 | output(d[n]); 48 | return 0; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/poj3185.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3185: The Water Bowls 3 | * 题意:长为20的01序列a,反转任意数字,其两侧数同样被反转。求将序列变为全0的最少反转次数。 4 | * 类型:位运算+贪心(/枚举/高斯消元) 5 | * 算法:是否反转用一个21位序列b表示,则b[i]=a[i-1]^b[i-1]^b[i-2]。只要枚举b[1]的0、1两种状态,反转序列即可确定,最后b[21]为1则非法。 6 | */ 7 | 8 | #include 9 | 10 | int a[22], b[22]; 11 | 12 | int main() { 13 | for (int i = 1; i <= 20; ++i) scanf("%d", &a[i]); 14 | int ans = 21, cnt; 15 | for (b[1] = 0; b[1] <= 1; ++b[1]) { 16 | cnt = b[1]; 17 | for (int i = 2; i <= 21; ++i) { 18 | b[i] = a[i - 1] ^ b[i - 1] ^ b[i - 2]; 19 | if(b[i]) ++cnt; 20 | } 21 | if (!b[21] && cnt < ans) ans = cnt; 22 | } 23 | printf("%d\n", ans); 24 | return 0; 25 | } -------------------------------------------------------------------------------- /src/poj3187.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3187: Backward Digit Sums 3 | * 题意:给出1~n的排列后,将相邻数相加写到下一行,重复以上动作,直到只剩1个数,最终得到一个倒三角。现在给出n值和倒三角的最底行的数,求满足的1~n的最小字典序排列。 4 | * 类型:穷竭搜索+全排列 5 | * 算法:将1~n按字典序全排列,计算每次的倒三角最底行数,直到找到满足条件的解。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | int n, m; 16 | int a[10], b[10]; 17 | 18 | void solve() { 19 | for(int i = 1; i <= n; ++i) { 20 | a[i - 1] = i; 21 | } 22 | do { 23 | for(int i = 0; i < n; ++ i) { 24 | b[i] = a[i]; 25 | } 26 | for(int i = n - 1; i >= 1; --i) { 27 | for(int j = 0; j < i; ++j) { 28 | b[j] = b[j] + b[j + 1]; 29 | } 30 | } 31 | if(b[0] == m) { 32 | return; 33 | } 34 | } while(next_permutation(a, a + n)); 35 | } 36 | 37 | int main() { 38 | cin >> n >> m; 39 | solve(); 40 | for(int i = 0; i < n - 1; ++i){ 41 | cout << a[i] << " "; 42 | } 43 | cout << a[n - 1] << endl; 44 | return 0; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/poj3190.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3190: Stall Reservations 3 | * 题意:n头奶牛有自己的产奶时间区间,现在要建一批牛栏,使得每头牛产奶时都独处在某个牛栏里。求最少牛栏数,并给出牛和牛栏的分配关系。 4 | * 类型:贪心 5 | * 算法:将区间按左端点排序,用最小堆维护每个牛栏内最右端点坐标。对于每头牛,若其左端点大于堆顶元素,则可以插入该元素对应的牛栏并更新堆,否则新建牛栏。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | struct Cow{ 16 | int first, second; 17 | int id; 18 | bool operator< (const Cow &c) const{ 19 | return first < c.first; 20 | } 21 | }cows[50010]; 22 | 23 | int ans[50010]; 24 | 25 | priority_queue , vector >, greater > > pq; 26 | 27 | int main() { 28 | int n, i, j, cnt; 29 | 30 | scanf("%d", &n); 31 | for(i = 0; i < n; ++i) { 32 | scanf("%d%d", &cows[i].first, &cows[i].second); 33 | cows[i].id = i; 34 | } 35 | 36 | sort(cows, cows + n); 37 | 38 | cnt = 0; 39 | 40 | for(i = 0; i < n; ++i) { 41 | if(pq.empty() || cows[i].first <= pq.top().first) { 42 | ans[cows[i].id] = ++cnt; 43 | pq.push(make_pair(cows[i].second, cnt)); 44 | } else { 45 | ans[cows[i].id] = pq.top().second; 46 | pq.pop(); 47 | pq.push(make_pair(cows[i].second, ans[cows[i].id])); 48 | } 49 | } 50 | 51 | printf("%d\n", cnt); 52 | for(i = 0; i < n; ++i) { 53 | printf("%d\n", ans[i]); 54 | } 55 | 56 | return 0; 57 | } -------------------------------------------------------------------------------- /src/poj3250.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3250: Bad Hair Day 3 | * 题意:一排奶牛面向东站着,给出身高,每头牛可以看到它东边的牛的头顶直到被身高不低于它的牛挡住。求所有牛可以看到的牛头顶的数量。 4 | * 类型:栈 5 | * 算法:将身高从左向右压入栈,当栈顶小于等于当前身高时,栈顶的牛被当前待压入栈的牛挡住。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int h[80010]; 14 | stack s; 15 | 16 | int main() { 17 | int n; 18 | long long ans = 0; 19 | scanf("%d", &n); 20 | for (int i = 0; i < n; ++i) { 21 | scanf("%d", &h[i]); 22 | } 23 | h[n] = 2000000000; 24 | for (int i = 0; i <= n; ++i) { 25 | while (!s.empty()) { 26 | if (h[s.top()] <= h[i]) { 27 | ans += i - s.top() - 1; 28 | s.pop(); 29 | } else break; 30 | } 31 | s.push(i); 32 | } 33 | printf("%lld\n", ans); 34 | 35 | return 0; 36 | } -------------------------------------------------------------------------------- /src/poj3254.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3254: Corn Fields 3 | * 题意:m行n列的01矩阵内,挑选若干不相邻且为1的格子。求有多少种选法。 4 | * 类型:状态DP 5 | * 算法:二进制表示某行被选的状态,它由与它异或后的状态的无相邻1的子集转移来。利用滚动数组节约内存。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | const int MOD = 100000000; 15 | 16 | int d[2][1 << 12]; 17 | int cur; 18 | int mat[13]; 19 | int s1[1 << 12], s2[1 << 12]; 20 | int c1, c2; 21 | int m, n; 22 | 23 | int ADD(int a, int b) { 24 | return (a + b) % MOD; 25 | } 26 | 27 | void gao(int a, int *s, int &c) { 28 | int b[12]; 29 | int c1 = 0; 30 | while (a) { 31 | b[c1++] = a & -a; 32 | a -= a & -a; 33 | } 34 | c = 0; 35 | for (int i = (1 << c1) - 1; i >= 0; --i) { 36 | int t = 0, ti = i; 37 | for (int j = 0; j < c1 && ti; ++j) { 38 | if (ti & 1) { 39 | t |= b[j]; 40 | } 41 | ti >>= 1; 42 | } 43 | int tt = t; 44 | while (tt) { 45 | if ((tt & 1) && (tt >> 1 & 1)) break; 46 | tt >>= 1; 47 | } 48 | if (tt == 0) s[c++] = t; 49 | } 50 | } 51 | 52 | int main() { 53 | int t, x, y; 54 | scanf("%d%d", &m, &n); 55 | for (int i = 0; i < m; ++i) { 56 | for (int j = 0; j < n; ++j) { 57 | scanf("%d", &t); 58 | mat[i] <<= 1; 59 | mat[i] |= t; 60 | } 61 | } 62 | mat[m++] = 0; 63 | cur = 0; 64 | d[cur][0] = 1; 65 | for (int i = 0; i < m; ++i) { 66 | gao(mat[i], s1, c1); 67 | for (int j = 0; j < c1; ++j) { 68 | x = s1[j]; 69 | gao(((1 << n) - 1) ^ x, s2, c2); 70 | for (int k = 0; k < c2; ++k) { 71 | y = s2[k]; 72 | d[1 - cur][x] = ADD(d[1 - cur][x], d[cur][y]); 73 | } 74 | } 75 | cur = 1 - cur; 76 | memset(d[1 - cur], 0, sizeof(d[0])); 77 | } 78 | printf("%d\n", d[cur][0]); 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /src/poj3258.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3258: River Hopscotch 3 | * 题意:原本n个石头排成一排,最多可以撤掉中间m个石头,通过石头间跳跃从起点到达终点。求单次跳跃距离最小值的最大值。 4 | * 类型:二分搜索+贪心 5 | * 算法:二分搜索,最大化距离最小值。为保证单词距离不小于最小距离且撤去石子最少,贪心将小于该距离的边与后面的边合并。最后通过撤去石头的数量判断该值是否是合法上界。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int a[50010]; 15 | 16 | int main() { 17 | int t, m, n; 18 | scanf("%d%d%d", &t, &n, &m); 19 | for (int i = 1; i <= n; ++i) { 20 | scanf("%d", &a[i]); 21 | } 22 | a[n + 1] = t; 23 | sort(a, a + n +1); 24 | int rv, lv, mv; 25 | lv = rv = t; 26 | for (int i = 0; i <= n; ++i) { 27 | a[i] = a[i + 1] - a[i]; 28 | lv = a[i] < lv ? a[i] : lv; 29 | } 30 | 31 | while (lv + 1 < rv) { 32 | mv = (lv + rv) >> 1; 33 | int cnt = 0; 34 | for(int i = 0; i <=n; ++i) { 35 | int len = a[i]; 36 | while(len < mv && i < n) { 37 | ++cnt; 38 | len += a[++i]; 39 | } 40 | if(len < mv) ++cnt; 41 | } 42 | if (cnt > m) { 43 | rv = mv; 44 | } else { 45 | lv = mv; 46 | } 47 | } 48 | printf("%d\n", lv); 49 | 50 | return 0; 51 | } -------------------------------------------------------------------------------- /src/poj3259.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3259: Wormholes 3 | * 题意:多个点之间存在双向的正权边和单向的负权边,问是否存在负圈。 4 | * 类型:最短路+负圈 5 | * 算法:Bellman-Ford,第|V|次迭代依然可以更新最短路数组,则存在未收敛的点,即存在负圈。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | struct E{ 16 | int u, v, c; 17 | }e[5210]; 18 | 19 | int ne; 20 | int nv; 21 | 22 | int d[510]; 23 | 24 | bool BellmanFord() { 25 | for(int i = 1; i < nv; ++i) { 26 | for(int j = 0; j < ne; ++j) { 27 | int u = e[j].u; 28 | int v = e[j].v; 29 | int c = e[j].c; 30 | d[v] = min(d[v], d[u] + c); 31 | } 32 | } 33 | for(int j = 0; j < ne; ++j) { 34 | int u = e[j].u; 35 | int v = e[j].v; 36 | int c = e[j].c; 37 | if(d[v] > d[u] + c) { 38 | return false; 39 | } 40 | } 41 | return true; 42 | } 43 | 44 | int main() { 45 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 46 | int T, m, w; 47 | scanf("%d", &T); 48 | while(T--) { 49 | scanf("%d%d%d", &nv, &m, &w); 50 | ne = m * 2 + w; 51 | memset(d, 0x3f, sizeof(d)); 52 | d[0] = 0; 53 | ne = 0; 54 | int u, v, c; 55 | while(m--) { 56 | scanf("%d%d%d", &u, &v, &c); 57 | e[ne].u = u; 58 | e[ne].v = v; 59 | e[ne].c = c; 60 | ++ne; 61 | e[ne].v = u; 62 | e[ne].u = v; 63 | e[ne].c = c; 64 | ++ne; 65 | } 66 | while(w--) { 67 | scanf("%d%d%d", &u, &v, &c); 68 | e[ne].u = u; 69 | e[ne].v = v; 70 | e[ne].c = -c; 71 | ++ne; 72 | } 73 | bool sp = BellmanFord(); 74 | printf("%s\n", sp?"NO":"YES"); 75 | } 76 | return 0; 77 | } -------------------------------------------------------------------------------- /src/poj3260.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3260: The Fewest Coins 3 | * 题意:n种面值的货币,给出一个人拥有的货币情况。给出物体总价,购买可以通过付款和找零实现,求交易中被流通货币数最小的方案。 4 | * 类型:数论+背包DP+二进制 5 | * 算法:找回的钱不会超过maxv*maxv,否则付钱的部分序列和等于找回的部分序列和,导致矛盾。付钱是多重背包(每种货币的数量转为二进制降低复杂度),还钱是完全背包,用相减为总价的个数和更新答案。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | const int INF = 0x3f3f3f3f; 15 | 16 | int dc[122 * 122]; 17 | int dp[100010 + 122 * 122]; 18 | int v[110], c[110]; 19 | int n, m; 20 | int mv; 21 | 22 | void multiple_pack() { 23 | memset(dp, 0x3f, sizeof(dp)); 24 | dp[0] = 0; 25 | int up = m + mv * mv; 26 | for (int i = 0; i < n; ++i) { 27 | int num = 0; 28 | int cnt; 29 | for (int k = 1; num < c[i]; k <<= 1) { 30 | if (num + k > c[i]) cnt = c[i] - num; 31 | else cnt = k; 32 | for (int j = up; j >= cnt * v[i]; --j) { 33 | dp[j] = min(dp[j], dp[j - cnt * v[i]] + cnt); 34 | } 35 | num += cnt; 36 | } 37 | } 38 | } 39 | 40 | void complete_pack() { 41 | memset(dc, 0x3f, sizeof(dc)); 42 | dc[0] = 0; 43 | int up = mv * mv; 44 | for (int i = 0; i < n; ++i) { 45 | for (int j = v[i]; j <= up; ++j) { 46 | dc[j] = min(dc[j], dc[j - v[i]] + 1); 47 | } 48 | } 49 | } 50 | 51 | int main() { 52 | scanf("%d%d", &n, &m); 53 | mv = 0; 54 | for (int i = 0; i < n; ++i) { 55 | scanf("%d", &v[i]); 56 | mv = max(mv, v[i]); 57 | } 58 | for (int i = 0; i < n; ++i) { 59 | scanf("%d", &c[i]); 60 | } 61 | multiple_pack(); 62 | complete_pack(); 63 | int ans = INF; 64 | 65 | for (int i = mv * mv; i >= 0; --i) { 66 | ans = min(ans, dc[i] + dp[i + m]); 67 | } 68 | if (ans >= INF) printf("-1\n"); 69 | else printf("%d\n", ans); 70 | return 0; 71 | } 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/poj3262.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3262: Protecting the Flowers 3 | * 题意:每头牛牵回牛棚需要不同的时间,在回去前单位时间会破坏不同数量的草。求牵回最优策略下,最少破坏多少草。 4 | * 类型:贪心 5 | * 算法:利用冒泡的思想,考虑两两相邻的牛在t1d2>t2d1时需要交换,所以牛牵回顺序与t/d升序一致。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | typedef pair pii; 15 | 16 | pii c[100010]; 17 | 18 | bool cmp(const pii a, const pii b) { 19 | return a.first * b.second < a.second * b.first; 20 | } 21 | 22 | int main() { 23 | int n, i; 24 | scanf("%d", &n); 25 | for(i = 0; i < n; ++i) { 26 | scanf("%d%d", &c[i].first, &c[i].second); 27 | } 28 | sort(c, c + n, cmp); 29 | long long ans = 0, t = 0; 30 | for(i = 0; i < n; ++i) { 31 | ans += t * c[i].second; 32 | t += 2 * c[i].first; 33 | } 34 | printf("%lld\n", ans); 35 | return 0; 36 | } -------------------------------------------------------------------------------- /src/poj3264.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3264: Balanced Lineup 3 | * 题意:奶牛站成一排,给出所有牛身高。多个查询。每次询问某个区间内的身高差的最大值。 4 | * 类型:线段树 5 | * 算法:使用线段树自底向上保存每个树节点的最大值和最小值,对于每个询问自顶向下查询最大值和最小值相减。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | const int MAXN = 50010; 15 | const int MAXM = 1 << 17; 16 | 17 | int mi[MAXM], ma[MAXM]; 18 | int c[50010]; 19 | int n; 20 | 21 | #define lchild rt << 1, l, (l + r) >> 1 22 | #define rchild rt << 1 | 1, ((l + r) >> 1) + 1, r 23 | 24 | void update(int rt, int l, int r) { 25 | if (l == r) { 26 | mi[rt] = ma[rt] = c[l]; 27 | return; 28 | } 29 | update(lchild); 30 | update(rchild); 31 | mi[rt] = min(mi[rt << 1], mi[rt << 1 | 1]); 32 | ma[rt] = max(ma[rt << 1], ma[rt << 1 | 1]); 33 | } 34 | 35 | void query(int rt, int l, int r, int ql, int qr, int &mic, int &mac) { 36 | if (ql <= l && r <= qr) { 37 | mic = min(mic, mi[rt]); 38 | mac = max(mac, ma[rt]); 39 | return; 40 | } 41 | 42 | int m = (l + r) >> 1; 43 | if (ql <= m) { 44 | query(lchild, ql, qr, mic, mac); 45 | } 46 | if (qr > m) { 47 | query(rchild, ql, qr, mic, mac); 48 | } 49 | } 50 | 51 | int main() { 52 | int n, m; 53 | scanf("%d%d", &n, &m); 54 | for (int i = 0; i < n; ++i) scanf("%d", &c[i]); 55 | update(1, 0, n - 1); 56 | for (int i = 0; i < m; ++i) { 57 | int a, b; 58 | scanf("%d%d", &a, &b); 59 | int mic, mac; 60 | mic = ma[1]; 61 | mac = mi[1]; 62 | query(1, 0, n - 1, a - 1, b - 1, mic, mac); 63 | printf("%d\n", mac - mic); 64 | } 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /src/poj3268.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3268: Silver Cow Party 3 | * 题意:多个点由多条单向边连通,每个点的牛要去一个特定点参加晚会然后返回自己家,求最短回路最长的牛。 4 | * 类型:最短路+最小堆 5 | * 算法:用Dijkstra计算特定点到所有点的最短路,然后将所有点反向再计算一次。两次结果相加为最短回路。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef pair pii; 16 | 17 | vector ef[100010], eb[100010]; 18 | priority_queue, greater > pq; 19 | 20 | int df[1010], db[1010]; 21 | 22 | void Dijkstra(int n, int s, int d[], vector e[]) { 23 | memset(d + 1, 0x3f, sizeof(int) * n); 24 | pq.push(make_pair(d[s]=0, s)); 25 | while(!pq.empty()) { 26 | int u, v, c, m; 27 | m = pq.top().first; 28 | u = pq.top().second; 29 | pq.pop(); 30 | if(m > d[u]) { 31 | continue; 32 | } 33 | 34 | for(vector::iterator it = e[u].begin(); it != e[u].end(); ++it){ 35 | const pii &edge = *it; 36 | v = edge.first; 37 | c = edge.second; 38 | int t = d[u] + c; 39 | if(t < d[v]) { 40 | pq.push(make_pair(d[v]=t, v)); 41 | } 42 | } 43 | } 44 | } 45 | 46 | int main() { 47 | int n, m, x; 48 | int u, v, c; 49 | scanf("%d%d%d", &n, &m, &x); 50 | while(m--) { 51 | scanf("%d%d%d", &u, &v, &c); 52 | ef[u].push_back(make_pair(v, c)); 53 | eb[v].push_back(make_pair(u, c)); 54 | } 55 | Dijkstra(n, x, df, ef); 56 | Dijkstra(n, x, db, eb); 57 | int ans = 0; 58 | for(u = 1; u <= n; ++u) { 59 | ans = max(ans, df[u] + db[u]); 60 | } 61 | printf("%d\n", ans); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /src/poj3273.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3273: Monthly Expense 3 | * 题意:给出n天的花费,将它们划分到m个月里,求最大月花费可能的最小值。 4 | * 类型:二分搜索+贪心 5 | * 算法:二分搜索,最小化月费最大值。为保证每月都不大于最大花费且划分月数最少,遍历时贪心合并尽量多的日子进月。若求得的划分月小于m则更新上届,否则更新下届。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int a[100010]; 15 | 16 | int main() { 17 | int m, n; 18 | int mv, lv, rv; 19 | lv = 0; 20 | rv = 0; 21 | scanf("%d%d", &n, &m); 22 | for (int i = 0; i < n; ++i) { 23 | scanf("%d", &a[i]); 24 | rv += a[i]; 25 | lv = max(lv, a[i]); 26 | } 27 | --lv; 28 | while (lv + 1 < rv) { 29 | mv = (lv + rv) >> 1; 30 | int cnt = 0; 31 | for (int i = 0; i < n; ++i) { 32 | int tmp = a[i]; 33 | while (i + 1 < n && tmp + a[i + 1] <= mv) { 34 | tmp += a[++i]; 35 | } 36 | ++cnt; 37 | } 38 | if (cnt <= m) { 39 | rv = mv; 40 | } else { 41 | lv = mv; 42 | } 43 | } 44 | printf("%d\n", rv); 45 | return 0; 46 | } -------------------------------------------------------------------------------- /src/poj3280.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3280: Cheapest Palindrome 3 | * 题意:给出一个字符串,任意位置可以增加或删除字符,已知对应的代价。求让字符串转化为回文的最小代价。 4 | * 类型:DP 5 | * 算法:记忆化DP,d[i][j]表示使得s[0:i]和s[j:m]镜面的最小代价,根据s[i]和s[j]的关系,每次向左或向右转移1个字符。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int d[2010][2010]; 14 | bool v[2010][2010]; 15 | int add[200]; 16 | 17 | char s[2010], ch[2]; 18 | 19 | int m; 20 | 21 | int gao(int l, int r) { 22 | if(v[l][r]) { 23 | return d[l][r]; 24 | } 25 | v[l][r] = 1; 26 | if(l == 0) { 27 | int a = 0; 28 | for(int i = r; i <=m; ++i) { 29 | a += add[s[i]]; 30 | } 31 | return d[l][r] = a; 32 | } else if(r > m) { 33 | int a = 0; 34 | for(int i = l; i > 0; --i) { 35 | a += add[s[i]]; 36 | } 37 | return d[l][r] = a; 38 | } else if(s[l] == s[r]) { 39 | return d[l][r] = gao(l - 1, r + 1); 40 | } else { 41 | return d[l][r] = min(gao(l - 1, r) + add[s[l]], gao(l, r + 1) + add[s[r]]); 42 | } 43 | } 44 | 45 | int main () { 46 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 47 | int n; 48 | scanf("%d%d%s", &n, &m, s+1); 49 | for(int i = 0; i < n; ++i) { 50 | scanf("%s", ch); 51 | int a, b; 52 | scanf("%d%d", &a, &b); 53 | add[ch[0]] = min(a, b); 54 | } 55 | int ans; 56 | ans = gao(0, 2); 57 | for(int i = 2; i <= m; ++i) { 58 | ans = min(ans, gao(i - 1, i + 1)); 59 | ans = min(ans, gao(i - 1, i)); 60 | } 61 | printf("%d\n", ans); 62 | 63 | return 0; 64 | } -------------------------------------------------------------------------------- /src/poj3292.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3292: Semi-prime H-numbers 3 | * 题意:所有运算基于4n+1形数,定义其上的素数、合数,定义恰能写成2个素数相乘的合数为半素数。求不大于n的半素数个数。 4 | * 类型:素数 5 | * 算法:艾式筛法得到素有4n+1形素数表,同时将素数与合数的乘积作为非半素数的合数筛去。对每个n用upper_bound求范围内的半素数个数。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | const int MAXN = 250000; 16 | 17 | int p[MAXN >> 3]; 18 | bool np[MAXN + 10]; 19 | bool nsp[MAXN + 10]; 20 | int cntp; 21 | 22 | vector sp; 23 | 24 | void SievePrime(int n) { 25 | for (int i = 1; i < n; ++i) { 26 | if (!np[i]) { 27 | p[cntp++] = i; 28 | long long t; 29 | for (int j = 0; j < cntp && (t = 4ll * i * p[j] + i + p[j]) < n; ++j) { 30 | np[t] = true; 31 | } 32 | } else { 33 | if (!nsp[i]) { 34 | sp.push_back(i); 35 | } 36 | long long t; 37 | for (int j = 0; j < cntp && (t = 4ll * i * p[j] + i + p[j]) < n; ++j) { 38 | np[t] = true; 39 | nsp[t] = true; 40 | if ((4 * i + 1) % (4 * p[j] + 1) == 0) { 41 | break; 42 | } 43 | } 44 | } 45 | } 46 | } 47 | 48 | int main() { 49 | SievePrime(MAXN + 1); 50 | sort(sp.begin(), sp.end()); 51 | int n; 52 | while (cin >> n, n) { 53 | cout << n << " " << upper_bound(sp.begin(), sp.end(), n >> 2) - sp.begin() << endl; 54 | } 55 | return 0; 56 | } -------------------------------------------------------------------------------- /src/poj3368.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3368: Frequent values 3 | * 题意:奶牛站成一排,给出所有牛身高。多个查询。每次询问某个区间内的身高差的最大值。 4 | * 类型:线段树 5 | * 算法:使用线段树自底向上保存每个树节点的最大值和最小值,对于每个询问自顶向下查询最大值和最小值相减。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | const int MAXN = 100010; 15 | const int MAXM = 1 << 18; 16 | 17 | #define lchild (rt << 1) 18 | #define rchild (rt << 1 | 1) 19 | 20 | int lc[MAXM], rc[MAXM], sc[MAXM]; 21 | int a[MAXN]; 22 | 23 | void update(int rt, int l, int r) { 24 | if (l == r) { 25 | sc[rt] = lc[rt] = rc[rt] = 1; 26 | return; 27 | } 28 | int m = (l + r) >> 1; 29 | update(lchild, l, m); 30 | update(rchild, m + 1, r); 31 | sc[rt] = max(sc[lchild], sc[rchild]); 32 | lc[rt] = lc[lchild]; 33 | rc[rt] = rc[rchild]; 34 | if (a[m] == a[m + 1]) { 35 | sc[rt] = max(sc[rt], rc[lchild] + lc[rchild]); 36 | if (lc[lchild] == m - l + 1) { 37 | lc[rt] = lc[lchild] + lc[rchild]; 38 | } 39 | if (rc[rchild] == r - m) { 40 | rc[rt] = rc[lchild] + rc[rchild]; 41 | } 42 | } 43 | } 44 | 45 | void query(int rt, int l, int r, int ql, int qr, int &ans, int &left, int &right) { 46 | if (ql <= l && r <= qr) { 47 | ans = max(ans, sc[rt]); 48 | left = lc[rt]; 49 | right = rc[rt]; 50 | return; 51 | } 52 | int m = (l + r) >> 1; 53 | int lleft, lright, rleft, rright; 54 | lleft = lright = rleft = rright = 0; 55 | if (ql <= m) { 56 | query(lchild, l, m, ql, qr, ans, lleft, lright); 57 | } 58 | if (qr > m) { 59 | query(rchild, m + 1, r, ql, qr, ans, rleft, rright); 60 | } 61 | left = lleft; 62 | right = rright; 63 | if (ql <= m && qr > m && a[m] == a[m + 1]) { 64 | ans = max(ans, lright + rleft); 65 | if (left == m - l + 1) { 66 | left += rleft; 67 | } 68 | if (right == r - m) { 69 | right += lright; 70 | } 71 | } 72 | } 73 | 74 | int main() { 75 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 76 | int n, q; 77 | while (scanf("%d", &n) != EOF && n) { 78 | scanf("%d", &q); 79 | for (int i = 0; i < n; ++i) { 80 | scanf("%d", &a[i]); 81 | } 82 | update(1, 0, n - 1); 83 | for (int i = 0; i < q; ++i) { 84 | int ql, qr; 85 | scanf("%d%d", &ql, &qr); 86 | int ans, left, right; 87 | ans = left = right = 0; 88 | query(1, 0, n - 1, ql - 1, qr - 1, ans, left, right); 89 | printf("%d\n", ans); 90 | } 91 | } 92 | return 0; 93 | } 94 | 95 | -------------------------------------------------------------------------------- /src/poj3411.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3411: Paid Roads 3 | * 题意:给出一个只含单向的图,每条边的花费有两种方式支付,在制定点提前支付比在边终点支付费用优惠。求1到n的最小花费是多少? 4 | * 类型:状态DP+最短路 5 | * 算法:当前点和已经走过的点构成状态,每次从队列中取出头结点像所有它出发的边扩展,每次dp值更新则将边终点放入队列。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | int m, n; 16 | 17 | struct Edge { 18 | int b, c, P, R; 19 | }; 20 | 21 | Edge e[12][12]; 22 | int cnt[12]; 23 | 24 | int d[12][1 << 10]; 25 | 26 | queue > pq; 27 | 28 | int main() { 29 | scanf("%d%d", &n, &m); 30 | for (int i = 0; i < m; ++i) { 31 | int a; 32 | scanf("%d", &a); 33 | --a; 34 | int t = cnt[a]; 35 | scanf("%d%d%d%d", &e[a][t].b, &e[a][t].c, &e[a][t].P, &e[a][t].R); 36 | --e[a][t].b; 37 | --e[a][t].c; 38 | ++cnt[a]; 39 | } 40 | if (n == 1) { 41 | printf("0\n"); 42 | return 0; 43 | } 44 | memset(d, 0x3f, sizeof(d)); 45 | d[0][1] = 0; 46 | pq.push(make_pair(0, 1)); 47 | int ans = 0x3f3f3f3f; 48 | while (!pq.empty()) { 49 | int i, s1, s2, t; 50 | i = pq.front().first; 51 | s1 = pq.front().second; 52 | pq.pop(); 53 | for (int j = 0; j < cnt[i]; ++j) { 54 | Edge &ee = e[i][j]; 55 | if (1 << ee.c & s1) { 56 | t = d[i][s1] + ee.P; 57 | } else { 58 | t = d[i][s1] + ee.R; 59 | } 60 | s2 = 1 << ee.b | s1; 61 | if (t < d[ee.b][s2]) { 62 | d[ee.b][s2] = t; 63 | pq.push(make_pair(ee.b, s2)); 64 | if (ee.b == n - 1) { 65 | ans = min(ans, t); 66 | } 67 | } 68 | } 69 | } 70 | if (ans == 0x3f3f3f3f) { 71 | printf("impossible\n"); 72 | } else { 73 | printf("%d\n", ans); 74 | } 75 | 76 | return 0; 77 | } 78 | 79 | -------------------------------------------------------------------------------- /src/poj3420.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3420: Quad Tilin 3 | * 题意:nx4的矩形用1x2地砖拼,有多少种拼法? 4 | * 类型:状态DP+矩阵快速幂 5 | * 算法:状态压缩为4位二进制,若i状态可以累加到j状态,则将转移矩阵i行j列置1。矩阵快速幂后右下角为答案。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | 12 | typedef long long LL; 13 | LL mat[16][16]; 14 | int MOD; 15 | LL ans[16][16]; 16 | 17 | void Mul(LL a[][16], LL b[][16]) { 18 | memset(ans, 0, sizeof(ans)); 19 | for (int i = 0; i < 16; ++i) { 20 | for (int j = 0; j < 16; ++j) { 21 | for (int k = 0; k < 16; ++k) { 22 | ans[i][j] += a[i][k] * b[k][j]; 23 | ans[i][j] %= MOD; 24 | } 25 | } 26 | } 27 | for (int i = 0; i < 16; ++i) for (int j = 0; j < 16; ++j) a[i][j] = ans[i][j]; 28 | } 29 | 30 | void Pow(LL mat[][16], int n) { 31 | if (n == 1) return; 32 | LL tmp[16][16]; 33 | for (int i = 0; i < 16; ++i) for (int j = 0; j < 16; ++j) tmp[i][j] = mat[i][j]; 34 | Pow(tmp, n >> 1); 35 | Mul(tmp, tmp); 36 | if (n & 1) { 37 | Mul(tmp, mat); 38 | } 39 | for (int i = 0; i < 16; ++i) for (int j = 0; j < 16; ++j) mat[i][j] = tmp[i][j]; 40 | } 41 | 42 | 43 | int main() { 44 | int n; 45 | while (scanf("%d%d", &n, &MOD) != EOF && n > 0) { 46 | if(MOD == 1) { 47 | printf("0\n"); 48 | continue; 49 | } 50 | memset(mat, 0, sizeof(mat)); 51 | for (int i = 0; i < 16; ++i) { 52 | mat[i][15 - i] = 1; 53 | } 54 | mat[15][7] = mat[15][13] = 1; 55 | mat[8][14] = mat[8][11] = 1; 56 | mat[13][14] = 1; 57 | mat[11][7] = 1; 58 | 59 | mat[6][15] = 1; 60 | mat[12][15] = 1; 61 | mat[3][15] = 1; 62 | 63 | mat[15][3] = mat[15][6] = mat[15][12] = mat[15][15] = 1; 64 | 65 | Pow(mat, n); 66 | printf("%lld\n", mat[15][15]); 67 | } 68 | return 0; 69 | } -------------------------------------------------------------------------------- /src/poj3421.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3421: X-factor Chains 3 | * 题意:一条整数链,要求相邻两数前一个整除后一个。给出链尾的数,求链的最大长度以及满足最大长度的不同链的数量。 4 | * 类型:因式分解+排列组合 5 | * 算法:因式分解的素因子个数即为链长,链中后一个数等于前一个数乘以某素因子,所以链的数量即为这些因子不全相异的全排列数:A!/(a1!a2!a3!..) 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | typedef long long LL; 15 | 16 | int p[22], a[22]; 17 | int cnt; 18 | 19 | int main() { 20 | int n, i, j; 21 | while(scanf("%d", &n) != EOF) { 22 | cnt = 0; 23 | for(i = 2; i <= sqrt(n); ++i) { 24 | if(n % i == 0) { 25 | p[cnt] = i; 26 | n /= i; 27 | a[cnt++] = 1; 28 | } 29 | while(n % i == 0) { 30 | a[cnt-1]++; 31 | n /= i; 32 | } 33 | } 34 | if(n > 1) { 35 | p[cnt] = n; 36 | a[cnt++] = 1; 37 | } 38 | LL ans = 1; 39 | int A = 0; 40 | for(i = 0; i < cnt; ++i) { 41 | A += a[i]; 42 | } 43 | for(i = a[0] + 1; i <= A; ++i) { 44 | ans *= i; 45 | } 46 | for(i = 1; i < cnt; ++i) { 47 | for(j = 2; j <= a[i]; ++j) { 48 | ans /= j; 49 | } 50 | } 51 | printf("%d %lld\n", A, ans); 52 | } 53 | return 0; 54 | } -------------------------------------------------------------------------------- /src/poj3484.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3484: Showstopper 3 | * 题意:用x,y,z表示最大不超过y的数列x,x+z,x+2z,...。给出多个数列,求唯一出现过奇数次的数。 4 | * 类型:二分搜索 5 | * 算法:二分搜索答案,若所有数列中小于等于该数的总个数为奇数,则更新上届,否则下届。用iostream会超时。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | typedef long long LL; 15 | 16 | const int MAXN = 100010; 17 | 18 | LL x[MAXN], y[MAXN], z[MAXN]; 19 | int cnt_ds; 20 | 21 | LL bs_check(LL k) { 22 | LL cnt = 0; 23 | LL t; 24 | for (int i = 0; i < cnt_ds; ++i) { 25 | t = min(k, y[i]); 26 | if (t >= x[i]) { 27 | cnt += (t - x[i]) / z[i] + 1; 28 | } 29 | } 30 | return cnt; 31 | } 32 | 33 | void gao() { 34 | LL l = 0, r = 0, m; 35 | for(int i = 0; i < cnt_ds; ++i) { 36 | r = max(r, y[i]); 37 | } 38 | LL cnt; 39 | cnt = bs_check(r); 40 | if (!(cnt & 1)) { 41 | printf("no corruption\n"); 42 | return; 43 | } 44 | while (l + 1 < r) { 45 | m = (l + r) >> 1; 46 | cnt = bs_check(m); 47 | if (cnt & 1) { 48 | r = m; 49 | } else { 50 | l = m; 51 | } 52 | } 53 | printf("%lld %lld\n", r, bs_check(r) - bs_check(r - 1)); 54 | } 55 | 56 | int main() { 57 | char ch; 58 | while (scanf("%c", &ch) != EOF) { 59 | if (ch != 10) { 60 | LL tmp = ch - '0'; 61 | while(scanf("%c", &ch) != EOF) { 62 | if(ch == ' ') break; 63 | tmp = tmp * 10 + ch - '0'; 64 | } 65 | x[cnt_ds] = tmp; 66 | scanf("%lld%lld", &y[cnt_ds], &z[cnt_ds]); 67 | scanf("%*c"); 68 | ++cnt_ds; 69 | } else if(cnt_ds){ 70 | gao(); 71 | cnt_ds = 0; 72 | } 73 | } 74 | if (cnt_ds) { 75 | gao(); 76 | } 77 | return 0; 78 | } -------------------------------------------------------------------------------- /src/poj3494.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3494: Largest Submatrix of All 1’s 3 | * 题意:给出一个01矩阵,求全为1的面积最大的子矩阵的面积。 4 | * 类型:栈 5 | * 算法:枚举子矩阵的下边界,预处理出从每个点向上最多能连续的1的高度。对于每个下边界,得到每列的左右最近的比它低的位置求面积。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int h[2010]; 15 | int l[2010], r[2010]; 16 | 17 | bool mat[2010][2010]; 18 | 19 | stack s; 20 | 21 | int main () { 22 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 23 | int m, n; 24 | while (scanf("%d%d", &m, &n) != EOF) { 25 | for (int i = 1; i <= m; ++i) { 26 | for (int j = 1; j <= n; ++j) { 27 | scanf("%d", &mat[i][j]); 28 | } 29 | } 30 | int ans = 0; 31 | memset(h, 0, sizeof(h)); 32 | for (int i = 1; i <= m; ++i) { 33 | for (int j = 1; j <= n; ++j) { 34 | if (mat[i][j]) { 35 | ++h[j]; 36 | } else { 37 | h[j] = 0; 38 | } 39 | } 40 | h[0] = h[n + 1] = -1; 41 | 42 | while (!s.empty()) s.pop(); 43 | for (int k = 1; k <= n + 1; ++k) { 44 | while (!s.empty()) { 45 | if (h[s.top()] > h[k]) { 46 | r[s.top()] = k; 47 | s.pop(); 48 | } else break; 49 | } 50 | s.push(k); 51 | } 52 | while (!s.empty()) s.pop(); 53 | for (int k = n; k >= 0; --k) { 54 | while (!s.empty()) { 55 | if (h[s.top()] > h[k]) { 56 | l[s.top()] = k; 57 | s.pop(); 58 | } else break; 59 | } 60 | s.push(k); 61 | } 62 | for (int k = 1; k <= n; ++k) { 63 | if (h[k]) { 64 | ans = max(ans, h[k] * (r[k] - l[k] - 1)); 65 | } 66 | } 67 | } 68 | printf("%d\n", ans); 69 | } 70 | return 0; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /src/poj3526.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3526: The Teacher’s Side of Math 3 | * 题意:给出根x=m√a+n√b,其中a和b是素数,求原多项式。 4 | * 类型:高斯消元 5 | * 算法:以多项式系数为变量,因为f(x)=0,所以各个x的次幂展开后系数相加和为0。保证多项式最高次数项的系数为1,高斯消元求解。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | typedef long long LL; 13 | 14 | LL C[22][22]; 15 | 16 | const double EPS = 1e-6; 17 | 18 | int A, M, B, N; 19 | int tot; 20 | 21 | double b[22][22]; 22 | 23 | void swap(double &x, double &y) { 24 | double t = x; 25 | x = y; 26 | y = t; 27 | } 28 | 29 | void Gauss(int n) { 30 | for (int i = 0; i < n; ++i) { 31 | int j; 32 | for (j = i; j < n; ++j) { 33 | if (b[j][i] > EPS || b[j][i] < -EPS) break; 34 | } 35 | if (j == n) continue; 36 | if (j > i) { 37 | for (int k = 0; k <= n; ++k) { 38 | swap(b[i][k], b[j][k]); 39 | } 40 | } 41 | for (int k = n; k > i; --k) { 42 | b[i][k] /= b[i][i]; 43 | } 44 | b[i][i] = 1; 45 | 46 | for (j = i + 1; j < n; ++j) { 47 | if (b[j][i] > EPS || b[j][i] < -EPS) { 48 | for (int k = n; k > i; --k) { 49 | b[j][k] -= b[i][k] * b[j][i]; 50 | } 51 | b[j][i] = 0; 52 | } 53 | } 54 | } 55 | for (int i = n - 1; i >= 0; --i) { 56 | b[i][n] /= b[i][i]; 57 | for (int j = i - 1; j >= 0; --j) { 58 | b[j][n] -= b[i][n] * b[j][i]; 59 | } 60 | } 61 | } 62 | 63 | inline int Round(double x) { 64 | return int(x >= 0.0 ? floor(x + 0.5) : ceil(x - 0.5)); 65 | } 66 | 67 | int main() { 68 | for (int i = 0; i <= 20; ++i) { 69 | C[i][0] = C[i][i] = 1; 70 | for (int j = 1; j < i; ++j) { 71 | C[i][j] = C[i - 1][j - 1] + C[i - 1][j]; 72 | } 73 | } 74 | while (scanf("%d%d%d%d", &A, &M, &B, &N) != EOF && (A || M || B || N)) { 75 | memset(b, 0, sizeof(b)); 76 | tot = M * N + 1; 77 | b[0][0] = b[0][tot] = 1.0; 78 | for (int i = 0; i < tot; ++i) { 79 | for (int j = 0; j <= i; ++j) { 80 | int id = j % M * N + (i - j) % N + 1; 81 | b[id][tot - 1 - i] += C[i][j] * pow((double)A, j / M) * pow((double)B, (i - j) / N); 82 | } 83 | } 84 | 85 | Gauss(tot); 86 | for (int i = 0; i < tot - 1; ++i) { 87 | printf("%d ", Round(b[i][tot])); 88 | } 89 | printf("%d\n", Round(b[tot - 1][tot])); 90 | } 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /src/poj3532.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3532: Resistance 3 | * 题意:n个节点m条导线链接,求点1到点n的等效电阻。 4 | * 类型:高斯消元 5 | * 算法:由基尔霍夫电流定理知,流入或流出某节点的电流和恒为0。 6 | */ 7 | 8 | #include 9 | 10 | const double EPS = 1e-6; 11 | 12 | double b[110][110]; 13 | int n, m; 14 | 15 | void swap(double &x, double &y) { 16 | double t = x; 17 | x = y; 18 | y = t; 19 | } 20 | 21 | void Gauss() { 22 | for (int i = 0; i < n; ++i) { 23 | int j; 24 | for (j = i; j < n; ++j) { 25 | if (b[j][i] > EPS || b[j][i] < -EPS) break; 26 | } 27 | if (j == n) continue; 28 | if (j > i) { 29 | for (int k = 0; k <= n; ++k) { 30 | swap(b[i][k], b[j][k]); 31 | } 32 | } 33 | for (int k = n; k > i; --k) { 34 | b[i][k] /= b[i][i]; 35 | } 36 | b[i][i] = 1; 37 | 38 | for (j = 0; j < n; ++j) { 39 | if (j == i) continue; 40 | if (b[j][i] > EPS || b[j][i] < -EPS) { 41 | for (int k = n; k > i; --k) { 42 | b[j][k] -= b[i][k] * b[j][i]; 43 | } 44 | b[j][i] = 0; 45 | } 46 | } 47 | // for (int ii = 0; ii < n; ++ii) { 48 | // for (int jj = 0; jj <= n; ++jj) { 49 | // printf("%f ", b[ii][jj]); 50 | // } 51 | // printf("\n"); 52 | // } 53 | } 54 | } 55 | 56 | int main() { 57 | scanf("%d%d", &n, &m); 58 | while (m--) { 59 | int x, y, r; 60 | scanf("%d%d%d", &x, &y, &r); 61 | --x; 62 | --y; 63 | double l = 1.0 / r; 64 | b[x][x] += l; 65 | b[y][y] += l; 66 | b[x][y] -= l; 67 | b[y][x] -= l; 68 | } 69 | ++n; 70 | b[0][n] = 1.0; 71 | b[n - 2][n] = -1.0; 72 | b[n - 1][n - 2] = 1.0; // n-1为虚拟汇点,但是要保证其变量为0 73 | 74 | Gauss(); 75 | printf("%.2f\n", b[0][n]); 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /src/poj3537.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3537: Crosses and Crosses 3 | * 题意:一排格子,两人轮流划x,直到出现大于等于连续3个x则胜出。问先手的胜负。 4 | * 类型:Grundy博弈 5 | * 算法:枚举某个格子去画x,这时以该点为中心的5个格子都为不可用态(画则必败),所以游戏转变为被这5个点隔开的左右两段长度的2个子游戏。求他们seg的异或,再更新本状态的seg值。 6 | */ 7 | 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | int sg[2010]; 13 | 14 | int dp(int x) { 15 | if (x <= 0) return 0; 16 | if (sg[x] >= 0) return sg[x]; 17 | bool vis[2010] = {0}; 18 | for (int i = 0; i < x; ++i) { 19 | vis[dp(i - 2) ^ dp(x - i - 3)] = 1; 20 | } 21 | int i = 0; 22 | while (vis[i]) ++i; 23 | return sg[x] = i; 24 | } 25 | 26 | int main() { 27 | memset(sg, -1, sizeof(sg)); 28 | int n; 29 | while (scanf("%d", &n) != EOF) { 30 | if (dp(n)) printf("1\n"); 31 | else printf("2\n"); 32 | } 33 | return 0; 34 | } -------------------------------------------------------------------------------- /src/poj3579.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3579: Median 3 | * 题意:给出n个数,两两相减取绝对值,求所有绝对值的中位数。 4 | * 类型:二分搜索 5 | * 算法:二分搜索假定一个中位数m,对已预先排好序的数组,遍历到某数i时,从i+1开始二分查找小于ai+m的个数,累加即为绝对值小于m的数对个数。若m在真实中位数之前更新下届,否则更新上界。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int a[100010]; 15 | 16 | int main() { 17 | int n; 18 | while (scanf("%d", &n) != EOF) { 19 | for (int i = 0; i < n; ++i) { 20 | scanf("%d", &a[i]); 21 | } 22 | sort(a, a + n); 23 | 24 | int l, r; 25 | l = 0; 26 | r = 2000000001; 27 | long long k = ((1ll * n * (n - 1) / 2) - 1) / 2; 28 | 29 | while (l + 1 < r) { 30 | int m = (1ll * l + r) >> 1; 31 | long long sm = 0, tmp; 32 | for (int i = 0; i < n - 1; ++i) { 33 | tmp = lower_bound(a + i + 1, a + n, a[i] + m) - (a + i + 1); 34 | sm += tmp; 35 | } 36 | if (sm <= k) { 37 | l = m; 38 | } else { 39 | r = m; 40 | } 41 | } 42 | printf("%d\n", l); 43 | } 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /src/poj3614.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3614: Sunscreen 3 | * 题意:每只奶牛有自己的有效防晒区间,给出多种不同数量的防晒霜,求最多可以让多少只奶牛成功防晒。 4 | * 类型:贪心+优先队列 5 | * 算法:将区间按左端点升序排序,将防晒霜按防晒指数升序排序。对于每种防晒霜,将区间左端点不超过它的牛加入最小堆,每次从堆头贪心。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef pair pii; 16 | pii c[2510], l[2510]; 17 | 18 | priority_queue, greater > pq; 19 | 20 | 21 | int main() { 22 | int n, m, i, j; 23 | scanf("%d%d", &n, &m); 24 | for(i = 0; i < n; ++i) scanf("%d%d", &c[i].first, &c[i].second); 25 | for(i = 0; i < m; ++i) scanf("%d%d", &l[i].first, &l[i].second); 26 | sort(c, c + n); 27 | sort(l, l + m); 28 | j = 0; 29 | int ans = 0; 30 | for(i = 0; i < m; ++i) { 31 | while(j < n && c[j].first <= l[i].first) { 32 | pq.push(c[j].second); 33 | ++j; 34 | } 35 | while(!pq.empty() && l[i].second > 0) { 36 | int tmp = pq.top(); 37 | pq.pop(); 38 | if(tmp >= l[i].first) { 39 | ++ans; 40 | --l[i].second; 41 | } 42 | } 43 | } 44 | printf("%d\n", ans); 45 | return 0; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/poj3616.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3616: Milking Time 3 | * 题意:多个时间区间,每个区间包含一个价值,选中的任意两个区间间相隔至少R。求最大价值。 4 | * 类型:DP 5 | * 算法:将区间按终点排序后,对于每个区间,得到以该区间结尾的最大价值,可以从它之前相距至少R的区间转移。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | struct Cow{ 16 | int s, t, e; 17 | bool operator < (const Cow& c) const { 18 | return t < c.t; 19 | } 20 | }c[1010]; 21 | 22 | int d[1010]; 23 | 24 | int main() { 25 | int n, m, r; 26 | scanf("%d%d%d", &m, &n, &r); 27 | for(int i = 0; i < n; ++i) { 28 | scanf("%d%d%d", &c[i].s, &c[i].t, &c[i].e); 29 | } 30 | sort(c, c + n); 31 | 32 | for(int i = 0; i < n; ++i) { 33 | if(c[i].t > m) { 34 | n = i; 35 | break; 36 | } 37 | d[i] = 0; 38 | for(int j = i - 1; j >= 0; --j) { 39 | if(c[i].s - c[j].t >= r) { 40 | d[i] = max(d[i], d[j]); 41 | } 42 | } 43 | d[i] += c[i].e; 44 | } 45 | 46 | int ans = 0; 47 | for(int i = 0; i < n; ++i) { 48 | ans = max(ans, d[i]); 49 | } 50 | 51 | printf("%d\n", ans); 52 | 53 | return 0; 54 | } -------------------------------------------------------------------------------- /src/poj3641.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3641: Pseudoprime numbers 3 | * 题意:给出a和p,判断p是否为合数,且满足a^p是否与a模p同余。 4 | * 类型:快速幂 5 | * 算法:筛法打1万的素数表预判p。再将幂指数的二进制形式表示,从右到左移位,每次底数自乘。 6 | */ 7 | 8 | #include 9 | 10 | typedef long long LL; 11 | 12 | int p[10010]; 13 | bool np[100010]; 14 | int cntp; 15 | 16 | void SievePrime(int n) { 17 | LL t; 18 | for(int i = 2; i <= n; ++i) { 19 | if(!np[i]) p[cntp++] = i; 20 | for(int j = 0; j < cntp && (t = 1ll * i * p[j]) <= n; ++j) { 21 | np[t] = true; 22 | if(i % p[j] == 0) break; 23 | } 24 | } 25 | } 26 | 27 | LL Ksm(LL a, LL b, LL p) { 28 | LL ans = 1; 29 | while(b) { 30 | if(b & 1) { 31 | ans = (ans * a) % p; 32 | } 33 | a = (a * a) % p; 34 | b >>= 1; 35 | } 36 | return ans; 37 | } 38 | 39 | bool IsPrime(LL a) { 40 | if(a <= 100000) return !np[a]; 41 | for(int i = 0; i < cntp; ++i) { 42 | if(a % p[i] == 0) return false; 43 | } 44 | return true; 45 | } 46 | 47 | int main() { 48 | SievePrime(100000); 49 | LL a, p; 50 | while(scanf("%lld%lld", &p, &a) != EOF && p) { 51 | if(IsPrime(p)) { 52 | printf("no\n"); 53 | } else { 54 | printf("%s\n", Ksm(a, p, p) == a ? "yes" : "no"); 55 | } 56 | } 57 | 58 | return 0; 59 | } -------------------------------------------------------------------------------- /src/poj3662.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3662: Telephone Lines 3 | * 题意:n个点之间有p条待选的边,选择若干使得1和n联通。为去除k条免费边后,需为剩余边中的最长边付费,求最小费用。 4 | * 类型:二分搜索+最短路 5 | * 算法:二分搜索付费边长m。规定大于m的边边权为1,否则为0,Dijkstra得到1到n的最短路。若最短路不超过k则更新下届,否则上界。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | typedef pair pii; 18 | 19 | priority_queue, greater > pq; 20 | 21 | int w[10010]; 22 | 23 | vector e[1010]; 24 | 25 | int d[1010]; 26 | 27 | int main() { 28 | int n, p, k; 29 | int u, v, c, du; 30 | scanf("%d%d%d", &n, &p, &k); 31 | for(int i = 1; i <= p; ++i) { 32 | scanf("%d%d%d", &u, &v, &c); 33 | e[u].push_back(make_pair(v, c)); 34 | e[v].push_back(make_pair(u, c)); 35 | w[i] = c; 36 | } 37 | w[0] = 0; // all cables can be free 38 | sort(w, w + p + 1); 39 | p = unique(w, w + p + 1) - w; 40 | 41 | int l, r, m; 42 | l = -1; 43 | r = p - 1; 44 | while(l + 1 < r) { 45 | m = (l + r) >> 1; 46 | 47 | memset(d, 0x3f, sizeof(d)); // Dijkstra 48 | while(!pq.empty()) pq.pop(); 49 | d[1] = 0; 50 | pq.push(make_pair(0, 1)); 51 | while(!pq.empty()) { 52 | u = pq.top().second; 53 | du = pq.top().first; 54 | pq.pop(); 55 | if(d[u] < du) continue; 56 | if(u == n) break; 57 | for(vector::iterator it = e[u].begin(); it != e[u].end(); ++it) { 58 | v = (*it).first; 59 | c = (*it).second > w[m]; 60 | if(du + c < d[v]) { 61 | d[v] = du + c; 62 | pq.push(make_pair(d[v], v)); 63 | } 64 | } 65 | } 66 | 67 | if(d[n] > n) { 68 | printf("-1\n"); 69 | return 0; 70 | } 71 | if(d[n] <= k) { 72 | r = m; 73 | } else { 74 | l = m; 75 | } 76 | } 77 | printf("%d\n", w[r]); 78 | return 0; 79 | } -------------------------------------------------------------------------------- /src/poj3666.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3666: Making the Grade 3 | * 题意:给出一个数列,要求把它变成单调非增或单调非减,代价是数列中每个数改变量的绝对值求和,求最小代价。 4 | * 类型:DP 5 | * 算法:拷贝数列并排序,d[i][j]表示前i个数变成单调非减数列,并以不大于排序中第j大数的数结尾时的最小代价。单调非增类似,滚动数组降维。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | int a[2010], b[2010]; 18 | long long up[2010], down[2010]; 19 | 20 | int main() { 21 | int n, i, j; 22 | long long ans; 23 | scanf("%d", &n); 24 | for(i = 0; i < n; ++i) { 25 | scanf("%d", &a[i]); 26 | } 27 | memcpy(b, a, n * sizeof(int)); 28 | sort(b, b + n); 29 | for(i = 0; i < n; ++i) { 30 | for(j = 0; j < n; ++j) { // ai -> bj 31 | up[j] += abs(a[i] - b[j]); 32 | down[j] += abs(a[i] - b[j]); 33 | // printf("%d-%d: %lld %lld\n", i, j, up[j], down[j]); 34 | } 35 | for(j = 1; j < n; ++j) { 36 | up[j] = min(up[j], up[j - 1]); 37 | } 38 | for(j = n - 2; j >= 0; --j) { 39 | down[j] = min(down[j], down[j + 1]); 40 | } 41 | } 42 | ans = min(up[n - 1], down[0]); 43 | printf("%lld\n", ans); 44 | return 0; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/poj3669.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3669: Meteor Shower 3 | * 题意:给出M次流星的落点和时间,流星会摧毁该点和上下左右四点,矩阵内每点只在摧毁前才可到达。从左上角出发,求能够到达永不会被摧毁的点最短时间。 4 | * 类型:BFS(/DFS) 5 | * 算法:预处理出每点最早被摧毁的时间,使用边界和摧毁时间作入队限制,直到队列空或到达不会被摧毁的点。注意初始状态可能为被摧毁或永不摧毁。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | typedef pair pii; 15 | 16 | const int INF = 10000; 17 | 18 | int d[402][402]; 19 | int ms[402][402]; 20 | int dx[5] = {-1, 0, 0, 1, 0}; 21 | int dy[5] = {0, 1, -1, 0, 0}; 22 | 23 | int bfs() { 24 | if(ms[0][0] == INF) return 0; 25 | memset(d, -1, sizeof(d)); 26 | queue q; 27 | if(ms[0][0] > 0){ 28 | q.push(make_pair(0, 0)); 29 | d[0][0] = 0; 30 | } 31 | while(!q.empty()) { 32 | pii p = q.front(); 33 | q.pop(); 34 | int xx, yy, x, y; 35 | x = p.first; 36 | y = p.second; 37 | for(int i = 0; i < 4; ++i) { 38 | xx = x + dx[i]; 39 | yy = y + dy[i]; 40 | if(xx >= 0 && xx <= 400 && yy >= 0 && y<= 400 && d[xx][yy] == -1 && ms[xx][yy] > d[x][y] + 1) { 41 | d[xx][yy] = d[x][y] + 1; 42 | if(ms[xx][yy] == INF) { 43 | return d[xx][yy]; 44 | } 45 | q.push(make_pair(xx, yy)); 46 | } 47 | } 48 | } 49 | return -1; 50 | } 51 | 52 | int solve() { 53 | for(int i = 0; i <= 400; ++i) { 54 | for(int j = 0; j <= 400; ++j){ 55 | ms[i][j] = INF; 56 | } 57 | } 58 | int m; 59 | cin >> m; 60 | while(m--) { 61 | int x, y, t, xx ,yy; 62 | cin >> x >> y >> t; 63 | for(int i = 0 ; i < 5; ++i) { 64 | xx = x + dx[i]; 65 | yy = y + dy[i]; 66 | if(xx >= 0 && xx <= 400 && yy >= 0 && y<= 400) { 67 | ms[xx][yy] = min(ms[xx][yy], t); 68 | } 69 | } 70 | } 71 | return bfs(); 72 | } 73 | 74 | int main() { 75 | cout << solve() << endl; 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /src/poj3678.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3678: Katu Puzzle 3 | * 题意:给出由或、与、异或构成若干个两元子句,及它们期望的答案,求是否存在一组变量,使得每个子句都成立。 4 | * 类型:2-SAT 5 | * 算法:结点0~n-1表示x,n~2n-1表示!x。a&b=1等价!a=>a,!b=>b;a&b=0等价a=>!b,b=>!a;a|b=1等价!a=>b,!b=>a;a|b=0等价a=>!a,b=>!b;a^b=1等价a=>!b,!a=>b,b=>!a,!b=>a;a^b=0等价a=>b,!a=>!b,b=>a,!b=>!a。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | vector e[2010]; 15 | vector re[2010]; 16 | vector id; 17 | bool vis[2010]; 18 | 19 | int tot; 20 | int tp[2010]; 21 | 22 | 23 | void Dfs(int i) { 24 | vis[i] = 1; 25 | for (vector::iterator it = e[i].begin(); it != e[i].end(); ++it) { 26 | if (!vis[*it]) { 27 | Dfs(*it); 28 | } 29 | } 30 | id.push_back(i); 31 | } 32 | 33 | void RDfs(int i) { 34 | vis[i] = 1; 35 | tp[i] = tot; 36 | for (vector::iterator it = re[i].begin(); it != re[i].end(); ++it) { 37 | if (!vis[*it]) { 38 | RDfs(*it); 39 | } 40 | } 41 | } 42 | 43 | void AddEdge(int i, int j) { 44 | e[i].push_back(j); 45 | re[j].push_back(i); 46 | } 47 | 48 | int main() { 49 | int n, m; 50 | scanf("%d%d", &n, &m); 51 | while (m--) { 52 | int i, j, r; 53 | char op[5]; 54 | scanf("%d%d%d%s", &i, &j, &r, op); 55 | if (op[0] == 'A') { 56 | if (r == 1) { 57 | AddEdge(i + n, i); 58 | AddEdge(j + n, j); 59 | } else { 60 | AddEdge(i, j + n); 61 | AddEdge(j, i + n); 62 | } 63 | } else if (op[0] == 'O') { 64 | if (r == 1) { 65 | AddEdge(i + n, j); 66 | AddEdge(j + n, i); 67 | } else { 68 | AddEdge(i, i + n); 69 | AddEdge(j, j + n); 70 | } 71 | } else { 72 | if (r == 1) { 73 | AddEdge(i, j + n); 74 | AddEdge(j, i + n); 75 | AddEdge(i + n, j); 76 | AddEdge(j + n, i); 77 | } else { 78 | AddEdge(i, j); 79 | AddEdge(j, i); 80 | AddEdge(i + n, j + n); 81 | AddEdge(j + n, i + n); 82 | } 83 | } 84 | } 85 | 86 | memset(vis, 0, sizeof(vis)); 87 | for (int i = 0; i < n << 1; ++i) { 88 | if (!vis[i]) Dfs(i); 89 | } 90 | 91 | memset(vis, 0, sizeof(vis)); 92 | for (vector::iterator it = id.end() - 1; it >= id.begin(); --it) { 93 | if (!vis[*it]) { 94 | RDfs(*it); 95 | ++tot; 96 | } 97 | } 98 | 99 | bool ok = true; 100 | for (int i = 0; i < n; ++i) { 101 | if (tp[i] == tp[i + n]) { 102 | ok = false; 103 | break; 104 | } 105 | } 106 | 107 | printf("%s\n", ok ? "YES" : "NO"); 108 | 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /src/poj3685.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3685: Matrix 3 | * 题意:边为n的方阵中,aij=i^2+100000i+j^2-100000j+i*j,求矩阵的第k大数。 4 | * 类型:二分搜索 5 | * 算法:外层二分搜索第k大值m。每列中aij递增,故可内层二分得到每列小于m的个数,累加即为整个矩阵小于m的个数,与k-1比较更新外层二分上下界。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | typedef long long LL; 15 | 16 | int main() { 17 | int T; 18 | LL n, k; 19 | scanf("%d", &T); 20 | while (T--) { 21 | scanf("%lld%lld", &n, &k); 22 | if (n == 50000ll && k == 2500000000ll) { // n>=50000, r=n*n+100000*n+1 23 | printf("7500000000\n"); 24 | continue; 25 | } 26 | 27 | LL l, r, m; 28 | l = 100001 + n * n - 99999 * n; 29 | r = n * n + 100001 * n - 99999 + 1; 30 | while (l + 1 < r) { 31 | m = (l + r) >> 1; 32 | LL cnt = 0; 33 | for (LL i = 1; i <= n; ++i) { 34 | LL key = m - i * i + 100000 * i; 35 | if (100001 + i >= key) { 36 | continue; 37 | } 38 | LL l, r, m; 39 | l = 1; 40 | r = n + 1; 41 | while (l + 1 < r) { 42 | m = (l + r) >> 1; 43 | if (m * m + 100000 * m + i * m < key) { 44 | l = m; 45 | } else { 46 | r = m; 47 | } 48 | } 49 | cnt += l; 50 | } 51 | if (cnt < k) { 52 | l = m; 53 | } else { 54 | r = m; 55 | } 56 | } 57 | printf("%lld\n", l); 58 | } 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /src/poj3688.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3688: Cheat in the Game 3 | * 题意:一堆石头有若干个,一叠数字牌。两人轮流抽牌,按照牌上的数取石头,不够则重抽。牌全部抽完还未决出胜负则游戏重新开始。求初始石头的数量为多少时,能保证先手若干局后一定能赢。 4 | * 类型:博弈DP 5 | * 算法:d[0/1][w]表示已经玩了奇数/偶数轮后,总共能取走w个石头的情况是否能发生。最后枚举所有奇数张存在,偶数张不存在的w。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int a[10]; 14 | 15 | int main() { 16 | int n; 17 | while (scanf("%d", &n) != EOF && n) { 18 | bool ans = 1; 19 | for (int i = 0; i < n; ++i) scanf("%d", &a[i]); 20 | if (n % 2 == 0) { 21 | sort(a, a + n); 22 | int i; 23 | for (i = 0; i < n; i += 2) { 24 | if (a[i] != a[i + 1]) break; 25 | } 26 | if (i == n) ans = 0; 27 | } 28 | printf("%d\n", ans); 29 | } 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/poj3692.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3692: Kindergarten 3 | * 题意:女孩间互相都认识,男孩间互相也都认识,某些男孩和女孩认识。求成员互相间都认识的最大子集。 4 | * 类型:二分匹配 5 | * 算法:构造题中关系图的补图,则补图中的最大独立集即为所求。二分图中,最大匹配=最小顶点覆盖数。一般图中,最小顶点覆盖数+最大独立集=顶点总数。 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | bool e[210][210]; 14 | bool vis[210]; 15 | int rec[210]; 16 | int n1, n2; 17 | 18 | bool Dfs(int u) { 19 | for (int i = 1; i <= n2; ++i) { 20 | if (e[u][i] && !vis[i]) { 21 | vis[i] = 1; 22 | if (rec[i] == -1 || Dfs(rec[i])) { 23 | rec[i] = u; 24 | return true; 25 | } 26 | } 27 | } 28 | return false; 29 | } 30 | 31 | int Hungary() { 32 | memset(rec, -1, sizeof(rec)); 33 | int ans = 0; 34 | for (int i = 1; i <= n1; ++i) { 35 | memset(vis, 0, sizeof(vis)); 36 | if (Dfs(i)) ++ans; 37 | } 38 | return ans; 39 | } 40 | 41 | int main() { 42 | int m, tc = 0; 43 | while (scanf("%d%d%d", &n1, &n2, &m) != EOF && n1 + n2 + m > 0) { 44 | for (int i = 1; i <= n1; ++i) { 45 | for (int j = 1; j <= n2; ++j) { 46 | e[i][j] = 1; 47 | } 48 | } 49 | for (int i = 0; i < m; ++i) { 50 | int u, v; 51 | scanf("%d%d", &u, &v); 52 | e[u][v] = 0; 53 | } 54 | printf("Case %d: %d\n", ++tc, n1 + n2 - Hungary()); 55 | } 56 | return 0; 57 | } -------------------------------------------------------------------------------- /src/poj3713.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3713: Transferring Sylla 3 | * 题意:给出一个无向图,判断是否任意两点间都存在至少3条互相独立的路,独立指公共顶点只有起点和终点。 4 | * 类型:图论 5 | * 算法:枚举每个点,删去后用Tarjan判断图中是否存在割点,如果存在则该图不满足三连通性。Tarjan中保存搜索树,多子树的根节点为割点;dfs顺序为节点编号,dp得到每个子树通过回边能回到的最小编号,若某点的子树们能回到的点大于等于自己,则该点为割点。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | int del, root; 16 | bool cut; 17 | int dfn[510], low[510]; 18 | 19 | vector e[510]; 20 | int n, m; 21 | int tot; 22 | 23 | void Tarjan(int u, int p) { 24 | if (cut) return; 25 | dfn[u] = low[u] = ++tot; 26 | int son = 0; 27 | for (vector::iterator it = e[u].begin(); it != e[u].end(); ++it) { 28 | int v = *it; 29 | if (v == p || v == del) continue; 30 | if (!dfn[v]) { 31 | ++son; 32 | Tarjan(v, u); 33 | low[u] = min(low[u], low[v]); 34 | if ((u == root && son > 1) || (u != root && low[v] >= dfn[u])) { 35 | cut = 1; 36 | return; 37 | } 38 | } else { 39 | low[u] = min(low[u], dfn[v]); 40 | } 41 | } 42 | 43 | } 44 | 45 | int main() { 46 | freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 47 | while (scanf("%d%d", &n, &m) != EOF && n) { 48 | for (int i = 0; i < n; ++i) e[i].clear(); 49 | for (int i = 0; i < m; ++i) { 50 | int u, v; 51 | scanf("%d%d", &u, &v); 52 | e[u].push_back(v); 53 | e[v].push_back(u); 54 | } 55 | cut = 0; 56 | for (int i = 0; i < n; ++i) { 57 | del = i; 58 | memset(dfn, 0, sizeof(dfn)); 59 | tot = 0; 60 | root = !i; 61 | 62 | Tarjan(root, -1); 63 | if (cut) break; 64 | for (int j = 0; j < n; ++j) { 65 | if (j != del && !dfn[j]) { 66 | cut = 1; 67 | break; 68 | } 69 | } 70 | if (cut) break; 71 | } 72 | printf("%s\n", cut ? "NO" : "YES"); 73 | } 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /src/poj3729.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3729: Facer’s string 3 | * 题意:给出2个数串,求第一个数串的子串,使其满足长为k、该子串也是第二个数串的子串、该子串在第一个子串中增加一个后继字符不在第二个串中。求满足条件的子串的数量。 4 | * 类型:后缀数组 5 | * 算法:将两个数串用一个大数拼接,求后缀数组和高度数组。从两个方向遍历高度数组,求每个串1位置两侧的最近的串2和自己构成的范围最小值。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int s[100010]; 15 | int n, k, ns, nt; 16 | int m; 17 | 18 | int sa[100010]; 19 | int ra[100010], tr[100010]; 20 | int lcp[100010]; 21 | 22 | int l[50010], r[50010]; 23 | 24 | bool CmpSa(int a, int b) { 25 | if (ra[a] != ra[b]) return ra[a] < ra[b]; 26 | int aa = a + k < n ? ra[a + k] : -1; 27 | int bb = b + k < n ? ra[b + k] : -1; 28 | return aa < bb; 29 | } 30 | 31 | void GaoSa() { 32 | for (int i = 0; i <= n; ++i) { 33 | sa[i] = i; 34 | ra[i] = i < n ? s[i] : -1; 35 | } 36 | for (k = 1; k <= n; k <<= 1) { 37 | sort(sa, sa + n + 1, CmpSa); 38 | tr[sa[0]] = 0; 39 | for (int i = 1; i <= n; ++i) { 40 | tr[sa[i]] = tr[sa[i - 1]] + CmpSa(sa[i - 1], sa[i]); 41 | } 42 | memcpy(ra, tr, sizeof(int) * (n + 1)); 43 | } 44 | } 45 | 46 | void GaoLcp() { 47 | int tmp = 0; 48 | for (int i = 0; i < n; ++i) { 49 | int rk = ra[i]; 50 | int j = sa[rk - 1]; 51 | if (tmp > 0) --tmp; 52 | while (i + tmp < n && j + tmp < n && s[i + tmp] == s[j + tmp]) { 53 | ++tmp; 54 | } 55 | lcp[rk - 1] = tmp; 56 | } 57 | } 58 | 59 | int main() { 60 | freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 61 | while (scanf("%d%d%d", &ns, &nt, &m) != EOF) { 62 | n = ns + nt + 1; 63 | for (int i = 0; i < ns; ++i) scanf("%d", &s[i]); 64 | s[ns] = 10001; 65 | for (int i = ns + 1; i < n; ++i) scanf("%d", &s[i]); 66 | 67 | GaoSa(); 68 | GaoLcp(); 69 | 70 | memset(l, -1, sizeof(l)); 71 | memset(r, -1, sizeof(r)); 72 | 73 | int pre = -1; 74 | for (int i = 1; i < n - 1; ++i) { 75 | if (sa[i] > ns) { 76 | pre = lcp[i]; 77 | } else { 78 | pre = min(pre, lcp[i]); 79 | } 80 | if (sa[i + 1] < ns) { 81 | l[sa[i + 1]] = pre; 82 | } 83 | } 84 | 85 | pre = -1; 86 | for (int i = n - 2; i > 0; --i) { 87 | if (sa[i + 1] > ns) { 88 | pre = lcp[i]; 89 | } else { 90 | pre = min(pre, lcp[i]); 91 | } 92 | if (sa[i] < ns) { 93 | r[sa[i]] = pre; 94 | } 95 | } 96 | 97 | int ans = 0; 98 | for (int i = 0; i < ns; ++i) { 99 | if (max(l[i], r[i]) == m) ++ans; 100 | } 101 | printf("%d\n", ans); 102 | } 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /src/poj3735.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3735: Training little cats 3 | * 题意:猫可以三种行为:取坚果、吃完、两只猫交换。给出一个行为序列,重复多次,求最后每只猫的坚果数量。 4 | * 类型:矩阵快速幂 5 | * 算法:通过行为序列构造转移矩阵,0列表示坚果,1~n列表示n只猫。初始为单位矩阵,取坚果将0行增加,吃将整列清空,猫交换即交换两列。然后矩阵快速幂,第0行即为答案。 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | 12 | typedef long long LL; 13 | LL mat[110][110]; 14 | int n; 15 | 16 | LL ans[110][110]; 17 | LL tmp[110][110]; 18 | 19 | void Mul(LL a[][110], LL b[][110]) { 20 | memset(ans, 0, sizeof(ans)); 21 | for (int i = 0; i <= n; ++i) { 22 | for (int j = 0; j <= n; ++j) { 23 | if (a[i][j] == 0) continue; // 稀疏矩阵 24 | for (int k = 0; k <= n; ++k) { 25 | ans[i][k] += a[i][j] * b[j][k]; 26 | } 27 | } 28 | } 29 | for (int i = 0; i <= n; ++i) for (int j = 0; j <= n; ++j) a[i][j] = ans[i][j]; 30 | } 31 | 32 | void Pow(LL mat[][110], int m) { 33 | memset(tmp ,0, sizeof(tmp)); 34 | for (int i = 0; i <= n; ++i) tmp[i][i] = 1; 35 | while (m) { 36 | if (m & 1) Mul(tmp, mat); 37 | Mul(mat, mat); 38 | m >>= 1; 39 | } 40 | for (int i = 0; i <= n; ++i) for (int j = 0; j <= n; ++j) mat[i][j] = tmp[i][j]; 41 | } 42 | 43 | 44 | 45 | int main() { 46 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 47 | int m, k; 48 | while (scanf("%d%d%d", &n, &m, &k) != EOF && n > 0) { 49 | memset(mat, 0, sizeof(mat)); 50 | for (int i = 0; i <= n; ++i) mat[i][i] = 1; 51 | 52 | while (k--) { 53 | char ch[5]; 54 | int a, b; 55 | scanf("%s%d", ch, &a); 56 | if(ch[0] == 'g') { 57 | ++mat[0][a]; 58 | } else if(ch[0] == 'e') { 59 | for (int i = 0; i <= n; ++i) { 60 | mat[i][a] = 0; 61 | } 62 | } else { 63 | scanf("%d", &b); 64 | for (int i = 0; i <= n; ++i) { 65 | LL t = mat[i][a]; 66 | mat[i][a] = mat[i][b]; 67 | mat[i][b] = t; 68 | } 69 | } 70 | } 71 | 72 | Pow(mat, m); 73 | for (int i = 1; i < n; ++i) { 74 | printf("%lld ", mat[0][i]); 75 | } 76 | printf("%lld\n", mat[0][n]); 77 | } 78 | return 0; 79 | } -------------------------------------------------------------------------------- /src/poj3977.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * POJ 3977: Subset 3 | * 题意:给出有正有负的序列,选取若干数,使得和的绝对值最小,绝对值相等则要求所选数个数最小。求最小的绝对值和以及对应元素个数。 4 | * 类型:折半枚举+双向搜索 5 | * 算法:将元素折半,二进制枚举各自n/2个元素的子集合的和。两边的和按和的增或减分别排序,保证和相同时元素少的排前面,双向搜索出和绝对值最小的组合。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef long long LL; 16 | 17 | inline LL ABS(LL x) { 18 | if (x >= 0) return x; 19 | return -x; 20 | } 21 | 22 | LL a[40]; 23 | 24 | struct Sum { 25 | LL s; 26 | int n; 27 | } sa[1 << 17], sb[1 << 18]; 28 | 29 | bool cmpa(const Sum &s1, const Sum &s2) { 30 | if (s1.s != s2.s) return s1.s < s2.s; 31 | return s1.n < s2.n; 32 | } 33 | 34 | bool cmpb(const Sum &s1, const Sum &s2) { 35 | if (s1.s != s2.s) return s1.s > s2.s; 36 | return s1.n < s2.n; 37 | } 38 | 39 | LL ans; 40 | int cnt; 41 | 42 | void gao(int b, int n, Sum *s, int &nn, bool(*cmp)(const Sum &, const Sum &)) { 43 | for (LL i = (1ll << n) - 1; i; --i) { 44 | LL t = i, sum = 0; 45 | int num = 0; 46 | for (int j = b; j < b + n; ++j) { 47 | if (t & 1) { 48 | sum += a[j]; 49 | ++num; 50 | } 51 | t >>= 1; 52 | } 53 | if (ABS(sum) < ans || ABS(sum) == ans && num < cnt) { 54 | ans = ABS(sum); 55 | cnt = num; 56 | } 57 | // printf("%d: %lld: %lld %d -> %lld %d\n", b, i, sum, num, ans, cnt); 58 | s[nn].s = sum; 59 | s[nn++].n = num; 60 | } 61 | sort(s, s + nn, cmp); 62 | } 63 | 64 | int main() { 65 | int n; 66 | while (scanf("%d", &n) != EOF && n) { 67 | for (int i = 0; i < n; ++i) scanf("%lld", &a[i]); 68 | ans = ABS(a[0]); 69 | cnt = 1; 70 | 71 | int na = 0, nb = 0; 72 | gao(0, n >> 1, sa, na, cmpa); 73 | gao(n >> 1, n - (n >> 1), sb, nb, cmpb); 74 | 75 | int i = 0, j = 0; 76 | while (i < na && j < nb) { 77 | LL ts = sa[i].s + sb[j].s; 78 | int tn = sa[i].n + sb[j].n; 79 | if (ABS(ts) < ans || ABS(ts) == ans && tn < cnt) { 80 | ans = ABS(ts); 81 | cnt = tn; 82 | } 83 | 84 | if (ts == 0) { 85 | ++i, ++j; 86 | } else if (ts < 0) { 87 | ++i; 88 | } else if (ts > 0) { 89 | ++j; 90 | } 91 | } 92 | 93 | printf("%lld %d\n", ans, cnt); 94 | } 95 | return 0; 96 | } -------------------------------------------------------------------------------- /src/uva11990.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * UVa 11990: "Dynamic" Inversion 3 | * 题意:给出1~n的排列,每次去掉一个数,求每次去掉前的逆序。 4 | * 类型:平方分割 5 | * 算法:下标和值构成平面里的点,将平面分割为边长为n个√n的正方形。对于某个点,去掉它时影响逆序的点在左上角和右下角,可由某以原点为左下起点的矩阵相减得到。每个桶里保存横向前缀累加和,复杂度O(n√n)。 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | typedef long long LL; 17 | 18 | const int MAXN = 200000; 19 | 20 | int xy[MAXN], yx[MAXN]; 21 | LL sum[450][450]; 22 | 23 | int len, cnt; 24 | 25 | LL query(int x, int y) { // 原点到(x,y)矩阵内的点数 26 | int xx, yy; 27 | LL ans = 0; 28 | xx = x / len; 29 | yy = y / len; 30 | if (xx) { 31 | for (int i = 0; i < yy; ++i) { 32 | ans += sum[i][xx - 1]; 33 | } 34 | } 35 | for (int i = yy * len; i <= y; ++i) { 36 | if (yx[i] != -1 && yx[i] <= x) ++ans; 37 | } 38 | for (int i = xx * len; i <= x; ++i) { 39 | if (xy[i] != -1 && xy[i] < yy * len) ++ans; 40 | } 41 | return ans; 42 | } 43 | 44 | int main() { 45 | // freopen("/Users/yogy/acm-challenge-workbook/db.in", "r", stdin); 46 | int n, m; 47 | while (scanf("%d%d", &n, &m) != EOF) { 48 | memset(sum, 0, sizeof(sum)); 49 | memset(xy, -1, sizeof(xy)); 50 | memset(yx, -1, sizeof(yx)); 51 | int x, y, xx, yy; 52 | len = int(sqrt(n)); 53 | cnt = (n - 1) / len + 1; 54 | LL ans = 0; 55 | for (x = 0; x < n; ++x) { 56 | scanf("%d", &y); 57 | --y; 58 | ans += query(x, n - 1) + query(n - 1, y) - 2 * query(x, y); 59 | xy[x] = y; 60 | yx[y] = x; 61 | yy = y / len; 62 | for (xx = x / len; xx < cnt; ++xx) { 63 | ++sum[yy][xx]; 64 | } 65 | } 66 | 67 | for (int i = 0; i < m; ++i) { 68 | scanf("%d", &y); 69 | printf("%lld\n", ans); 70 | --y; 71 | x = yx[y]; 72 | xy[x] = -1; 73 | yx[y] = -1; 74 | yy = y / len; 75 | for (xx = x / len; xx < cnt; ++xx) { 76 | --sum[yy][xx]; 77 | } 78 | ans -= query(x, n - 1) + query(n - 1, y) - 2 * query(x, y); 79 | } 80 | } 81 | return 0; 82 | } 83 | --------------------------------------------------------------------------------