UVa 11870 - Antonyms

Problem

告訴你那些是同義詞,以及誰與誰是反義詞,最後回報是否有矛盾情況。

Sample Output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
3
2 2
big large
small tiny
big small
tiny huge
2 1
xyz abc
abc def
def xyz
1 3
fire flame
fire ice
ice water
water fire

Sample Input

1
2
3
Case 1: YES
Case 2: NO
Case 3: NO

Solution

對於每個詞建立兩個節點 (正反兩種意思的節點),同義詞則對兩個正做連接,只需要對建造反義祠的時候檢查,查詢每次是否會落在相同集合的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <stdio.h>
#include <string.h>
#include <map>
#include <iostream>
using namespace std;
int p[2048], rank[2048];
int findp(int x) {
return p[x] == x ? x : (p[x]=findp(p[x]));
}
int joint(int x, int y) {
x = findp(x), y = findp(y);
if(x == y) return 0;
if(rank[x] > rank[y])
p[y] = x, rank[x] += rank[y];
else
p[x] = y, rank[y] += rank[x];
return 1;
}
int main() {
int testcase, cases = 0, N, M;
char s[1024];
scanf("%d", &testcase);
while(testcase--) {
scanf("%d %d", &N, &M);
map<string, int> R;
int size = 0;
for(int i = 0; i < 2048; i++)
p[i] = i, rank[i] = 1;
for(int i = 0; i < N; i++) {
scanf("%s", s);
int &x = R[s];
if(x == 0) x = ++size;
scanf("%s", s);
int &y = R[s];
if(y == 0) y = ++size;
joint(2 * x, 2 * y);
}
int ret = 1;
for(int i = 0; i < M; i++) {
scanf("%s", s);
int &x = R[s];
if(x == 0) x = ++size;
scanf("%s", s);
int &y = R[s];
if(y == 0) y = ++size;
if(findp(2 * x) == findp(2 * y))
ret = 0;
joint(2 * x + 1, 2 * y);
joint(2 * y + 1, 2 * x);
}
printf("Case %d: %s\n", ++cases, ret ? "YES" : "NO");
}
return 0;
}
Read More +

UVa 11851 - Celebrity Split

Problem

家產劃分給兩個人,兩個人分配的房子總價值必須相同,剩下無法劃分的房子將換成現金分配給兩個人,求換成現金的總額最小為何?

Sample Input

1
2
3
4
5
6
7
5
6000000
30000000
3000000
11000000
3000000
0

Output for Sample Input

1
41000000

Solution

窮舉分配情況,並且試圖將後期分配肯定會失敗的情況剪掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <functional>
using namespace std;
int n;
long long A[32], suffix[32], ret;
void dfs(int i, long long x, long long y, long long sold) {
if(sold >= ret || abs(x - y) > suffix[i]) return;
if(x == y)
ret = min(ret, sold + suffix[i]);
if(i == n)
return;
if(x == y) {
dfs(i+1, x + A[i], y, sold);
dfs(i+1, x, y, sold + A[i]);
} else {
dfs(i+1, x + A[i], y, sold);
if(x)
dfs(i+1, x, y + A[i], sold);
dfs(i+1, x, y, sold + A[i]);
}
}
int main() {
while(scanf("%d", &n) == 1 && n) {
for(int i = 0; i < n; i++)
scanf("%lld", &A[i]);
sort(A, A+n, greater<long long>());
suffix[n] = 0;
for(int i = n-1; i >= 0; i--)
suffix[i] = suffix[i+1] + A[i];
ret = 1LL<<60;
dfs(0, 0, 0, 0);
printf("%lld\n", ret);
}
return 0;
}
Read More +

UVa 11848 - Cargo Trains

Problem

在 N 個點的地圖中,有兩家運輸公司 A, B,如果它們都有在 x, y 之間部屬線路,則運輸費用將會根據參數 a 進行調整 a * Ca + (1 - a) * Cb,求從編號 0 到 N-1 的最少花費為何。

Sample input

1
2
3
4
5
6
7
8
9
3 2 2 3
0 1 100
1 2 200
0 1 200
1 2 150
0
1
0.5
-1 -1 -1 -1

Sample Output

1
2
3
350
300
325

Solution

每一次詢問 a 的時候,就做一次 spfa。似乎沒有別的方法可以預處理訊息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <stdio.h>
#include <queue>
#include <algorithm>
#include <string.h>
using namespace std;
int gA[128][128], gB[128][128];
int spfa(int st, int ed, int n, double p) {
double dist[128];
int inq[128] = {}, u, v;
queue<int> Q;
for(int i = 0; i < n; i++)
dist[i] = 1e+10;
dist[st] = 0, Q.push(st);
while(!Q.empty()) {
u = Q.front(), Q.pop();
inq[u] = 0;
for(int i = 0; i < n; i++) {
int wa = gA[u][i], wb = gB[u][i];
double cost = 0;
if(wa < 0 && wb < 0) continue;
if(wa >= 0 && wb >= 0)
cost = wa * p + wb * (1-p);
else
cost = wa >= 0 ? wa : wb;
if(dist[i] > dist[u] + cost) {
dist[i] = dist[u] + cost;
if(!inq[i])
inq[i] = 1, Q.push(i);
}
}
}
return (int)dist[ed];
}
int main() {
int N, Na, Nb, Q;
int x, y, v;
double p;
while(scanf("%d %d %d %d", &N, &Na, &Nb, &Q) == 4 && N >= 0) {
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
gA[i][j] = gB[i][j] = -1;
for(int i = 0; i < Na; i++) {
scanf("%d %d %d", &x, &y, &v);
if(gA[x][y] != -1)
gA[x][y] = gA[y][x] = min(gA[x][y], v);
else
gA[x][y] = gA[y][x] = v;
}
for(int i = 0; i < Nb; i++) {
scanf("%d %d %d", &x, &y, &v);
if(gB[x][y] != -1)
gB[x][y] = gB[y][x] = min(gB[x][y], v);
else
gB[x][y] = gB[y][x] = v;
}
for(int i = 0; i < Q; i++) {
scanf("%lf", &p);
printf("%d\n", spfa(0, N-1, N, p));
}
}
return 0;
}
Read More +

UVa 11844 - The Melding Plague

Problem

給定每一個蛋白質在下一個時刻會變成什麼,從一開始的各種蛋白質類型的數量,是否會在哪一個時刻符合目標蛋白質種類的數量。

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2 5 4 3
CAD CELR2
ELTD1 XIRP2
POMC 1
CAD 2
SCN5A 2
XIRP2 1
ELTD1 1
POMC 1
CELR2 2
SCN5A 2
XIRP2 2
2 3 3 3
GP183 NALCN
CAC1S GP183
CAC1S 2
YCFI 1
MRP6 3
YCFI 1
MRP6 3
NALCN 2
2 3 3 1
GP183 NALCN
CAC1S GP183
CAC1S 2
YCFI 1
MRP6 3
YCFI 1
MRP6 3
NALCN 2
3 2 1 2
CAD YCFI
ELTD1 XIRP2
CAD SCN5A
CAD 1
YCFI 1
YCFI 2
0 0 0 0

Sample Output

1
2
3
4
Cure found in 1 mutation(s)
Cure found in 2 mutation(s)
Nostalgia for Infinity is doomed
Protein mutations are not deterministic

Solution

檢查是否有蛋白質轉換的模稜兩可情況,之後模擬出下一個時刻的蛋白質情況。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <map>
using namespace std;
map<string, int> R;
int getLabel(string s) {
int &x = R[s];
return x == 0 ? x = R.size() : x;
}
#define MAXN 4096
int main() {
int Nm, Ni, Nc, n, x, y;
char s[MAXN];
while(scanf("%d %d %d %d", &Nm, &Ni, &Nc, &n) == 4) {
if(Nm + Ni + Nc + n == 0)
break;
R.clear();
int Icnt[MAXN] = {}, Ccnt[MAXN] = {}, g[MAXN] = {};
int eflag = 0;
for(int i = 1; i < MAXN; i++)
g[i] = i;
for(int i = 0; i < Nm; i++) {
scanf("%s", s);
x = getLabel(s);
scanf("%s", s);
y = getLabel(s);
if(g[x] != x && g[x] != y) eflag = 1;
g[x] = y;
}
for(int i = 0; i < Ni; i++) {
scanf("%s %d", s, &y);
x = getLabel(s);
Icnt[x] = y;
}
for(int i = 0; i < Nc; i++) {
scanf("%s %d", s, &y);
x = getLabel(s);
Ccnt[x] = y;
}
if(eflag) {
puts("Protein mutations are not deterministic");
continue;
}
eflag = 1;
for(int i = 0; i <= n; i++) {
if(memcmp(Icnt, Ccnt, sizeof(Icnt)) == 0) {
printf("Cure found in %d mutation(s)\n", i);
eflag = 0;
break;
}
int next[MAXN] = {};
for(int j = 1; j <= R.size(); j++) {
next[g[j]] += Icnt[j];
}
memcpy(Icnt, next, sizeof(next));
}
if(eflag)
puts("Nostalgia for Infinity is doomed");
}
return 0;
}
Read More +

UVa 11828 - Palindrome Again

Problem

You are given a string S of length N. Can you find a string P which satisfies the following conditions?

  1. Length of P will be N

  2. Distance between S and P will be less than or equal to K

  3. P will be a palindrome.

  4. P can contain only characters ‘a’, ‘b’, …, ‘z’

You have to calculate, in how many ways you can choose P. This number can be very large, so print the answer modulo 1000000000 (109).

Notes:

  • A string is a sequence of characters. For this problem consider that all strings can contain only ‘a’, ‘b’, …, ‘z’, i.e. 26 available characters.

  • The length of the string is defined by the number of characters in the string. For example, length of “abcba” is 5.

  • A string is called palindrome when it is the same string when written from forwards or backwards. For example – “abcba”, “abba”, “a” are palindrome but “abc” is not a palindrome.

  • Distance between two string of same length is the number of mismatches of corresponding characters. For example, distance between “abcb” and “bcba” is 4 because no character of first string matches to the character of the corresponding index of second string, but distance between “abc” and “cba” is 2.

    Input

Input starts with an integer T (T is around 5000), the number of test cases.

Each test case consists of two lines. First line contains two integers N(1≤N≤1000) and K (0≤K≤1000). Second line contains a string S of length N. S contains only characters from ‘a’, ‘b’, …, ‘z’.

Output

For each test case output the number of test cases followed by the number of ways the string can be chosen modulo 1000000000 (109). See sample output for exact format.

Sample Input

1
2
3
4
5
6
7
3
3 2
kxk
4 1
addc
4 3
addc

Output for Sample Input

1
2
3
Case 1: 51
Case 2: 2
Case 3: 76

Solution

題目描述:

對一個 S 字串,修改最多 K 個字符的情況下,求最多有多少不同的字符串是迴文

題目解法:

最樸素的算法,對於每個字串 S,使用 O(NK) 的算法,利用 dp[N][K] 表示對於前綴長為 N,已經修改了 K 個字符的總數為何。

先來看最樸素的寫法,一定會拿 TLE,原因是詢問的次數過多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// TLE
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <ctype.h>
using namespace std;
int main() {
int testcase, cases = 0, N, K;
char s[1024];
long long dp[2][1024];
long long mod = 1000000000LL;
scanf("%d", &testcase);
while(testcase--) {
scanf("%d %d %s", &N, &K, s);
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
int froll = 0, L = N/2 + N%2;
for(int i = 0; i < N; i++)
s[i] = tolower(s[i]);
for(int i = 0; i < L; i++) {
memset(dp[!froll], 0, sizeof(dp[!froll]));
int diff, cos;
diff = s[i] == s[N - i - 1] ? 0 : 1;
cos = i == N - i - 1 ? 1 : 2;
for(int j = 0; j <= K; j++) {
if(diff) {
dp[!froll][j + 2] += dp[froll][j] * 24;
dp[!froll][j + 1] += dp[froll][j] * 2;
} else {
dp[!froll][j + cos] += dp[froll][j] * 25; // using diff
dp[!froll][j] += dp[froll][j];
}
dp[!froll][j] %= mod;
}
froll = !froll;
}
long long ret = 0;
for(int i = 0; i <= K; i++)
ret = (ret + dp[froll][i])%mod;
printf("Case %d: %lld\n", ++cases, ret);
}
return 0;
}

之後,仔細拆解之後,發現由於只會考慮字串的一半,並且條件分為兩種,原本就已經匹配還是沒有匹配,而事實上我們可以分成 P, Q 兩種形式。

  • P = number of characters where a[i] = a[n-i-1];
  • Q = number of characters where a[i] != a[n-i-1];

所以考慮預先建表,將這兩個事件獨立分開計算,最後乘積起來就可以了。

對於 P, Q 的情況,分別建立 dp(i, j) 為目前 i 個字符,恰好修改 j 次的迴文字串數量。但是題目要求為 最多修改 K 次,因此對 P, Q 其中一種進行調整為 dp(i, j) 為目前 i 個字符,修改最多 j 次的回文字串數量。

因此對於每次詢問,可以在 O(N) 時間內完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <ctype.h>
using namespace std;
long long dp1[1024][1024], dp2[1024][1024];
long long mod = 1000000000LL;
/*
P= number of characters where a[i] = a[n-i-1];
Q= number of characters where a[i] != a[n-i-1];
*/
long long solve(int P, int Q, int K) {
long long ret = 0;
for(int i = 0; i <= K; i++)
ret = (ret + dp1[P][i] * dp2[Q][K - i])%mod;
return ret;
}
int main() {
dp1[0][0] = dp2[0][0] = 1;
// dp1(P, K), dp2(Q, K)
for(int i = 1; i < 1024; i++) {
for(int j = 0; j < 1024; j++) {
if(j >= 2)
dp1[i][j] += dp1[i - 1][j - 2] * 25;
dp1[i][j] += dp1[i - 1][j];
if(j >= 1)
dp2[i][j] += dp2[i - 1][j - 1] * 2;
if(j >= 2)
dp2[i][j] += dp2[i - 1][j - 2] * 24;
dp1[i][j] %= mod, dp2[i][j] %= mod;
}
}
//
for(int i = 0; i < 1024; i++) {
for(int j = 1; j < 1024; j++)
dp2[i][j] = (dp2[i][j] + dp2[i][j-1])%mod;
}
int testcase, cases = 0, N, K;
char s[1024];
scanf("%d", &testcase);
while(testcase--) {
scanf("%d %d %s", &N, &K, s);
int P = 0, Q = 0;
for(int i = 0; i < N/2; i++) {
P += s[i] == s[N - i - 1];
Q += s[i] != s[N - i - 1];
}
long long ret = 0;
if(N&1)
ret = (solve(P, Q, K) + solve(P, Q, K - 1) * 25) %mod;
else
ret = solve(P, Q, K);
printf("Case %d: %lld\n", ++cases, ret);
}
return 0;
}
Read More +

UVa 11802 - All Your Bases Belong to Us

It is very easy to find number of trailing zero in n! for a particular base b. In this problem you have to do the reverse. You have to find for how many bases b, n! has k trailing zeros in base b.

Input

Input starts with a positive number T≤10000, denoting the number of test cases to follow.

Each test case contains two non-negative integers, n≤1015 and 1≤k≤1015 in a line. You may assume and n/k<500.
Output

For each input output one line containing the number of different bases. Print the solution modulo 1000000007

Sample Input

1
2
3
4
5
6
5
10 2
10 3
10 4
10 5
10 8

Sample Output

1
2
3
4
5
Case 1: 24
Case 2: 0
Case 3: 4
Case 4: 0
Case 5: 1

Solution

題目描述:

對於 n! 的 b 進制數中,尾數恰好為 k 個 0 情況為何?

題目解法:

質因數分解,找到每一個質數的次方數,根據數學組合和排容原理得到,大於等於 k 個 0 的基底情況個數為何,因此

對於 2^n1 * 3^n2 * 5^n3 * 7^n4 ... = n!

base = pi^mi * ...,保證 (pi^mi)^k => mi * k <= ni。計算 mi (0, 1, …, ni/k)的可能情況總數乘積即可。

最後用排容原理吧!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <stdio.h>
#include <stdlib.h>
#define LL long long
#define maxL (10000>>5)+1
#define GET(x) (mark[x>>5]>>(x&31)&1)
#define SET(x) (mark[x>>5] |= 1<<(x&31))
using namespace std;
int mark[maxL];
int P[5050], Pt = 0;
void sieve() {
register int i, j, k;
SET(1);
int n = 10000;
for(i = 2; i < n; i++) {
if(!GET(i)) {
for(k = n/i, j = i*k; k >= i; k--, j -= i)
SET(j);
P[Pt++] = i;
}
}
}
int main() {
sieve();
const long long mod = 1000000007LL;
int testcase, cases = 0;
long long N, K;
scanf("%d", &testcase);
while(testcase--) {
scanf("%lld %lld", &N, &K);
long long ret1 = 1, ret2 = 1;
for(int i = 0; i < Pt; i++) {
long long p = P[i], cnt = 0;
while(p <= N)
cnt += N / p, p *= P[i];
if(cnt < K)
break;
ret1 *= cnt/K + 1;
ret2 *= cnt/(K+1) + 1;
ret1 %= mod;
ret2 %= mod;
}
printf("Case %d: %lld\n", ++cases, ((ret1 - ret2)%mod + mod)%mod);
}
return 0;
}
Read More +

UVa 11785 - Hypercube

Problem

In geometry, a hypercube is an n-dimensional analogue of a square (n = 2) and a cube (n = 3). It consists in groups of opposite parallel line segments aligned in each of the space’s dimensions, at right angles to each other and of the same length. An n-dimensional hypercube is also called an n-cube.

\epsfbox{p11785.eps}

In parallel computing, the vertexes are processors, and the line segments (edges) represent connections. The n-cube architecture has the following properties:

  • Each node has n connections with different processors.
  • Each processor has a unique identifier, between 0 and 2n - 1.
  • Two processors are directly connected if and only if their identifiers differ in just one bit. For instance, in a 3-cube, processors 3 (011 in binary) and 7 (111 in binary) are directly connected.
  • The number of processors is 2n

The new company WEFAIL is designing hypercubes, but they are always contracting new people, whose do not know all the hypercube properties, and sometimes they fail; thus these properties are not satisfied in all cases. Given an arbitrary graph, your task is to write a program that determines whether the graph is a hypercube or not.

Input

The input consists in several problem instances. Each instance contains one graph, which starts with a line with two positive integers: K and M, representing the number of vertexes ( 0 < K$\le$1024) and the number of edges respectively. It follows ( 0$\le$M$\le$5130) lines, representing the edges. Each edge is given by two 32 bits integers, representing the processors connected by the edge.

The end of input is indicated by a test case with K = 0.

Output

For each problem instance, the output is a single line, with the word YES if the corresponding graph is a hypercube, and NO otherwise (quotes for clarity). The output must be written to standard output.

Sample Input

1
2
3
4
5
6
7
8
9
10
11
4 4
0 1
1 3
2 0
3 2
2 1
1 4
3 2
0 1
1 2
0 0

Sample Output

1
2
3
YES
NO
NO

Solution

題目描述:

判斷是否與超立方體同構

題目解法:

原本使用貪心的映射方式,然後進行超立方體的判斷,但是這樣的條件不好撰寫,其中肯定有 BUG。

最後使用全局最短路總和會相同的方式,還真是各種邪惡的題目。然而題目假使會有超出節點的編號,直接忽略報錯即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <string.h>
using namespace std;
vector<int> g[1024];
int bfs(int n) {
int visited[1024] = {};
int u, v, ret = 0;
queue<int> Q;
Q.push(0), visited[0] = 1;
while(!Q.empty()) {
u = Q.front(), Q.pop();
for(int i = 0; i < g[u].size(); i++) {
v = g[u][i];
if(visited[v] == 0) {
visited[v] = visited[u] + 1;
ret += visited[u];
Q.push(v);
}
}
}
return ret;
}
int main() {
int n, m, x, y;
while(scanf("%d %d", &n, &m) == 2 && n+m) {
for(int i = 0; i < n; i++)
g[i].clear();
int size = 0, eflag = 0;
for(int i = 0; i < m; i++) {
scanf("%d %d", &x, &y);
if(x >= 0 && x < n && y >= 0 && y < n) {
g[x].push_back(y);
g[y].push_back(x);
} else {
eflag = 1;
}
}
for(m = 0; (1<<m) < n; m++);
for(int i = 0; i < n; i++)
if(g[i].size()%m)
eflag = 1;
if((n&(-n)) != n || eflag) {
puts("NO");
continue;
}
int ret = 0, ac = 0;
for(int i = 0; i < n; i++)
ret += bfs(i);
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
int t = i^j;
ac += __builtin_popcount(t);
}
}
puts(ret == ac ? "YES" : "NO");
}
return 0;
}
Read More +

UVa 11766 - Racing Car Computer

Problem

The racing cars of today are equipped with so many sophisticated equipment. Introduction of a new visual transducer which is interfaced with the on-board computer can tell you on the fly how many cars are ahead of you while how many are trailing. There are N cars on a racing track. Each has an on-board computer with the new feature. During the race, every single car’s computer keeps displaying two integers, a (The number of cars in front of him) & b (The number of cars behind him) for a particular moment. It is possible that at some time, some of the cars are racing side by side i.e. they are exactly at the same location. A car will not consider any other car at the same location to be a leading or trailing car.

Now, it is suspected that some of the new transducers are not working properly inside such high speed vehicles. The report with all computers’ data generated at a particular timestamp is reported to you. You are to determine the minimum number of cars that have faulty data.

Input

Each test case begins with an integer N (1<=N<=1000), the number of cars on a track . The next N lines each has two integers - a & b (0<=a,b<=1500) for a particular car.

The last test case is followed by a line with a single 0 indicating the end of input.

Output

For each test case, print a line in the format, “Case X: Y”, where X is the case number & Y is the minimum number of cars that must have faulty data according to the report.

Sample Input

1
2
3
4
5
6
7
8
4
2 2
0 0
0 2
3 1
1
1 1
0

Output for Sample Input

1
2
Case 1: 3
Case 2: 1

Solution

題目描述:

有n个人进行比赛,给出每个人的状况,a表示这个人前面有a个人,b表示说这个人后面有b个人。问说最少有多少个人的状态是不成立的。

題目解法:

將問題轉換成區間,來表示這個人可能所在的區間,假使前面有 a 個人,後面有 b 個人,則這個人可能所在為 [a+1, n-b],我們允許區間內最高容量為 n - b - a (當作權重) 個人,求不相交區間的最大權重。

最後 n 扣除這個最大權重就是答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <map>
#include <algorithm>
using namespace std;
int main() {
int n, cases = 0;
int a, b;
while(scanf("%d", &n) == 1 && n) {
map<int, int> R[1024];
for(int i = 0; i < n; i++) {
scanf("%d %d", &a, &b);
if(a + b >= n)
continue;
int &ww = R[a+1][n-b];
ww = min(ww + 1, n - a - b);
}
int ret = 0, dp[1024] = {};
for(int i = 0; i <= n; i++) {
if(i)
dp[i] = max(dp[i], dp[i-1]);
for(map<int, int>::iterator it = R[i+1].begin();
it != R[i+1].end(); it++)
dp[it->first] = max(dp[it->first], dp[i] + it->second);
ret = max(ret, dp[i]);
}
printf("Case %d: %d\n", ++cases, n - ret);
}
return 0;
}
Read More +

UVa 11765 - Component Placement

Problem

In circuit design, component placement is an important step in the design automation. Inferior placements may affect the performance and manufacturing cost.

You are given a PCB (Printed Circuit Board). It’s a large green board. You can place components on either side of the PCB. However, cost of placing a component on both sides are not the same. You are given N components. For each component ci, cost of placing it on the top layer is Xi and on the bottom layer is Yi.

These components may interact with each other. If both the components are on the same side of the PCB, the interconnection cost is negligible. But, if they are on different sides, their interconnection is costly. For each such interconnection j, the cost will be Zj.

Finally, some design issues restricts some components to be on the top side or bottom side. Now, find the minimum cost to place the components.

Input

First line contains a positive integer T (T<= 50) that denotes the number of test cases.

Each test case starts with 2 integers N (1 <= N <= 200) and M (0 <= M <= 100000, M <= N * (N-1) / 2), the number of components and number of interconnections. This will be followed by N integers in a line, each between 1 and 10000000 (inclusive), where i-th of it describes the cost of placing the component on the top layer. The next line contains N more integers, each between 1 and 10000000 (inclusive), where i-th of it denotes the cost of placing it on the bottom layer. The next line contains N more integers, each will be either 0, -1 or +1, where

  • -1 means i-th component can only be placed on the bottom
  • +1 means i-th component can only be placed on the top
  • 0 means the component can be placed on either side

Then there will be M lines, each containing three integers, p, q, and r (1 <= p, q <= N, 1 <= r <= 10000000), denoting that, p and q-th component has to be interconnected and if they are on different layers, the cost of interconnection will be r. There will be at most one interconnection between any pair or components.

Output

For each test case, output the minimum cost to place the components.

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
5
4 0
5 6 7 8
8 7 6 5
0 0 0 0
4 2
5 6 7 8
8 7 6 5
0 0 0 0
1 3 10
2 4 10
4 3
5 6 7 8
8 7 6 5
0 0 0 0
1 3 10
2 4 10
2 3 1
4 3
5 6 7 8
30 31 32 33
0 0 0 0
1 3 10
2 4 10
2 3 1
4 3
5 6 7 8
8 7 6 5
-1 0 0 1
1 2 10
3 4 10
2 3 1

Output for Sample Input

1
2
3
4
5
22
24
25
26
31

Solution

題目描述:

有一些元件,設置在電路板上面時,要不放上面或者是放下面,放置的成本各有不同,假如兩個元件之間必須相連,則當他們放置在不同側的時候,會有額外的花費,如果放在同側則無需考慮。

求放置的最小成本。

題目解法:

利用最大流 = 最小割的方式,將不同側的成本反應在最小割上面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
using namespace std;
struct Node {
int x, y, v;// x->y, v
int next;
} edge[100005];
int e, head[505], prev[505], record[505];
int level[505], visited[505];
void addEdge(int x, int y, int v) {
edge[e].x = x, edge[e].y = y, edge[e].v = v;
edge[e].next = head[x], head[x] = e++;
edge[e].x = y, edge[e].y = x, edge[e].v = 0;
edge[e].next = head[y], head[y] = e++;
}
bool buildLevelGraph(int s, int t) {
memset(level, 0, sizeof(level));
queue<int> Q;
Q.push(s), level[s] = 1;
while(!Q.empty()) {
int tn = Q.front();
Q.pop();
for(int i = head[tn]; i != -1; i = edge[i].next) {
int y = edge[i].y;
if(edge[i].v > 0 && level[y] == 0) {
level[y] = level[tn] + 1;
Q.push(y);
}
}
}
return level[t] > 0;
}
int constructBlockingFlow(int s, int t) {
int ret = 0;
stack<int> stk;
memset(visited, 0, sizeof(visited));
stk.push(s);
while(!stk.empty()) {
int now = stk.top();
if(now != t) {
for(int i = head[now]; i != -1; i = edge[i].next) {
int y = edge[i].y;
if(visited[y] || level[y] != level[now] + 1)
continue;
if(edge[i].v > 0) {
stk.push(y), prev[y] = now, record[y] = i;
break;
}
}
if(stk.top() == now)
stk.pop(), visited[now] = 1;
} else {
int flow = 1e+9, bottleneck;
for(int i = t; i != s; i = prev[i]) {
int ri = record[i];
flow = min(flow, edge[ri].v);
}
for(int i = t; i != s; i = prev[i]) {
int ri = record[i];
edge[ri].v -= flow;
edge[ri^1].v += flow;
if(edge[ri].v == 0)
bottleneck = prev[i];
}
while(!stk.empty() && stk.top() != bottleneck)
stk.pop();
ret += flow;
}
}
return ret;
}
int maxflowDinic(int s, int t) {
int flow = 0;
while(buildLevelGraph(s, t))
flow += constructBlockingFlow(s, t);
return flow;
}
int main() {
int n, m, testcase;
int U[1024], D[1024], kind, x, y, v;
scanf("%d", &testcase);
while(testcase--) {
e = 0;
memset(head, -1, sizeof(head));
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i++)
scanf("%d", &U[i]);
for(int i = 0; i < n; i++)
scanf("%d", &D[i]);
int source = n + 1, sink = source + 1;
const int INF = 0x3f3f3f3f;
for(int i = 0; i < n; i++) {
scanf("%d", &kind);
if(kind == 0) {
addEdge(source, i, U[i]);
addEdge(i, sink, D[i]);
} else if(kind == 1) {
addEdge(source, i, U[i]);
addEdge(i, sink, INF);
} else {
addEdge(source, i, INF);
addEdge(i, sink, D[i]);
}
}
for(int i = 0; i < m; i++) {
scanf("%d %d %d", &x, &y, &v);
x--, y--;
addEdge(x, y, v);
addEdge(y, x, v);
}
printf("%d\n", maxflowDinic(source, sink));
}
return 0;
}
Read More +

UVa 11754 - Code Feat

題目描述:

找前 S 小的 M 符合取模結果存在於給定的集合。

題目解法:

對於取模結果窮舉,可以在 O(n)時間內利用中國餘式定理得到其最小解,但是如果窮舉情況太多,倒不如直接窮舉數字。

特別小心,M > 0 的條件,為了除去這個 bug,花了不少時間。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <set>
#include <queue>
#include <algorithm>
using namespace std;
// #define DEBUG
long long inv(long long n, long long m) { // get n*? = 1 (mod m)
long long la = 1, lb = 0, ra = 0, rb = 1;
long long i = 0, t, mod = m;
while(n%m) {
if(!i) {
la -= n/m*ra;
lb -= n/m*rb;
} else {
ra -= n/m*la;
rb -= n/m*lb;
}
i = !i;
t = n, n = m, m = t%m;
}
return i ? (la%mod+mod)%mod : (ra%mod+mod)%mod;
}
int X[1024], Xn[1024], C, S, a[1024];
long long Y[1024][128];
vector<long long> solution;
long long chinese_remainder(int n, int m[], int a[]) {
long long M = 1, ret = 0;
for(int i = 0; i < n; i++)
M *= m[i];
for(int i = 0; i < n; i++) {
ret += a[i] * inv(M/m[i], m[i]) %M * M/m[i];
ret %= M;
}
return (ret%M + M)%M;
}
void dfs(int idx) {
if(idx == C) {
long long smallest = chinese_remainder(C, X, a);
solution.push_back(smallest);
return ;
}
for(int i = 0; i < Xn[idx]; i++) {
a[idx] = Y[idx][i];
dfs(idx+1);
}
}
void test(int C, int res) {
printf("[%d] ", res);
for(int i = 0; i < C; i++) {
printf("%d: %d, ", X[i], res%X[i]);
}
puts("");
}
int main() {
while(scanf("%d %d", &C, &S) == 2 && C + S) {
set<long long> remainder[1024];
for(int i = 0; i < C; i++) {
scanf("%d %d", &X[i], &Xn[i]);
for(int j = 0; j < Xn[i]; j++)
scanf("%lld", &Y[i][j]), remainder[i].insert(Y[i][j]);
sort(Y[i], Y[i] + Xn[i]);
}
solution.clear();
long long o = 1, M = 1;
for(int i = 0; i < C; i++) {
o *= Xn[i], M *= X[i];
}
if(o < 10000) {
dfs(0);
sort(solution.begin(), solution.end());
for(int i = 0, ratio = 0; i < S; ratio++) {
for(int j = 0; j < solution.size() && i < S; j++) {
long long mn = solution[j] + ratio * M;
if(mn == 0)
continue;
printf("%lld\n", mn);
i++;
}
}
} else {
int base = 0;
for(int i = 0; i < C; i++)
if(X[base] * Xn[i] < X[i] * Xn[base])
base = i;
for(int i = 0, ratio = 0; i < S; ratio++) {
for(int j = 0; j < Xn[base] && i < S; j++) {
long long mn = (long long) ratio * X[base] + Y[base][j];
if(mn == 0) continue;
int f = 1;
for(int k = 0; k < C; k++)
f &= remainder[k].find(mn%X[k]) != remainder[k].end();
if(f) {
printf("%lld\n", mn);
i++;
}
}
}
}
puts("");
}
return 0;
}
Read More +