ZOJ Monthly, January 2015 (B、E、G、H)

B题:

先处理出已有卡牌,然后进行dfs,dfs有个很大的剪枝,就是当前位置如果字典序小于了,那么后面就不用继续放了,直接用组合数学进行计算即可,如果大于就不用考虑了,如果等于才继续往后搜,这样的话,搜等于只要在字典序相等的一条路上搜,时间可以接受

E题:模拟即可,不存在无解情况

G题:先全部数字GCD一遍,如果不为1,就是无解,如果为1,那么构造答案,其实只要拿第一个数字,可以其他每个数字做一次gcd,第一个数字就是1了,然后再拿第一个数字和后面数字做gcd,就全部都是1了,一共进行n - 2次

H题:这题有个大坑啊,字符串居然只要满足是子串就可以了- -,感觉题目说的不是那么清楚,于是只要把已有字符串构造一棵字典树,然后dp[x][y][u],表示当前在x,y这个位置,在字典树中位置为u的状态需要的最小步树,然后进行最短路即可,遇到单词结点的时候,可以记录一下答案的最小值

代码:

B:

#include <cstdio>
#include <cstring>

typedef long long ll;
const int MOD = 1000000007;
char str[105];

int st[52], have[14], stn, hn, C[105][105];

int cal(int tot) {
    int ans = 1;
    for (int i = 1; i <= 13; i++) {
	if (have[i]) {
	    ans = (int)((ll)ans * C[tot][have[i]] % MOD);
	    tot -= have[i];
	}
    }
    return ans;
}

int dfs(int u) {
    int ans = 0;
    if (u == stn) return 0;
    if (hn - u == 0) return 1;
    for (int i = 1; i <= st[u]; i++) {
	if (!have[i]) continue;
	have[i]--;
	if (i == st[u]) {
	    ans = (ans + dfs(u + 1)) % MOD;
	}
	else if (i < st[u]) {
	    ans = (ans + cal(hn - u - 1)) % MOD;
	}
	have[i]++;
    }
    return ans;
}

int main() {
    for (int i = 0; i < 105; i++) {
	C[i][0] = C[i][i] = 1;
	for (int j = 1; j < i; j++) {
	    C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
	}
    }
    while (gets(str) != NULL) {
	stn = 0;
	hn = 0;
	int len = strlen(str);
	memset(have, 0, sizeof(have));
	for (int i = 0; i < len; i++) {
	    if (str[i] == 'A') st[stn++] = 1;
	    else if (str[i] == '1') {
		st[stn++] = 10;
		i++;
	    }
	    else if (str[i] >= '2' && str[i] <= '9')
		st[stn++] = str[i] - '2' + 2;
	    else if (str[i] == 'J') st[stn++] = 11;
	    else if (str[i] == 'Q') st[stn++] = 12;
	    else if (str[i] == 'K') st[stn++] = 13;
	    have[st[stn - 1]]++;
	}
	for (int i = 1; i <= 13; i++) {
	    have[i] = 4 - have[i];
	    hn += have[i];
	}
	printf("%d\n", dfs(0));
    }
    return 0;
}

E:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 15;
const int INF = 0x3f3f3f3f;

int t, n, a[N];

void gao() {
    while (1) {
	int Min = INF, Max = -INF;
	int Minv, Maxv;
	for (int i = 0; i < n; i++) {
	    if (Min > a[i]) {
		Min = a[i];
		Minv = i;
	    }
	    if (Max < a[i]) {
		Max = a[i];
		Maxv = i;
	    }
	}
	if (Min == Max) break;
	a[Minv] = a[Maxv] = Max - Min;
    }
}

int main() {
    scanf("%d", &t);
    while (t--) {
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	    scanf("%d", &a[i]);
	gao();
	printf("%d\n", a[0]);
    }
    return 0;
}

G:

#include <cstdio>
#include <cstring>

const int N = 100005;

int gcd(int a, int b) {
    if (!b) return a;
    return gcd(b, a % b);
}

int n, a;

int main() {
    int cas = 0;
    while (~scanf("%d", &n)) {
	int s = 0;
	for (int i = 0; i < n; i++) {
	    scanf("%d", &a);
	    s = gcd(s, a);
	}
	printf("Case %d: ", ++cas);
	if (s != 1) {
	    printf("-1\n");
	} else {
	    printf("%d\n", 2 * n - 2);
	    for (int i = 2; i <= n; i++)
		printf("1 %d\n", i);
	    for (int i = 2; i <= n; i++)
		printf("1 %d\n", i);
	}
	printf("\n");
    }
    return 0;
}

H:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

const int N = 25;
const int MAXN = 20005;
const int INF = 0x3f3f3f3f;

int t, n, m;
char str[N][N], s[105];

int ch[MAXN][26], sz, dp[N][N][MAXN];
bool val[MAXN];

void init() {
    sz = 0;
    memset(val, 0, sizeof(val));
    memset(ch[0], 0, sizeof(ch[0]));
}

int idx(char c) {
    return c - 'A';
}

void insert(char *str) {
    int len = strlen(str);
    int u = 0;
    for (int i = 0; i < len; i++) {
	int c = idx(str[i]);
	if (!ch[u][c]) {
	    ch[u][c] = ++sz;
	    memset(ch[sz], 0, sizeof(ch[sz]));
	}
	u = ch[u][c];
    }
    val[u] = true;
}

struct State {
    int x, y, u, val;
    State() {}
    State(int x, int y, int u, int val) {
	this->x = x;
	this->y = y;
	this->u = u;
	this->val = val;
    }
    bool operator < (const State& c) const {
	return val > c.val;
    }
};

const int d[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};

int main() {
    scanf("%d", &t);
    while (t--) {
	priority_queue<State> Q;
	scanf("%d%d", &n, &m);
	memset(dp, INF, sizeof(dp));
	for (int i = 0; i < n; i++) {
	    scanf("%s", str[i]);
	    for (int j = 0; j < m; j++) {
		if (str[i][j] == '@') {
		    Q.push(State(i, j, 0, 0));
		    dp[i][j][0] = 0;
		}
	    }
	}
	int q;
	int ans = INF;
	scanf("%d", &q);
	init();
	while (q--) {
	    scanf("%s", s);
	    insert(s);
	}
	while (!Q.empty()) {
	    State now = Q.top();
	    Q.pop();
	    if (val[now.u])
		ans = min(ans, now.val);
	    if (now.val >= ans) continue;
	    for (int i = 0; i < 4; i++) {
		int x = now.x + d[i][0];
		int y = now.y + d[i][1];
		if (x < 0 || x >= n || y < 0 || y >= m || str[x][y] == '#') continue;
		if (dp[x][y][0] > now.val + 1) {
		    dp[x][y][0] = now.val + 1;
		    Q.push(State(x, y, 0, now.val + 1));
		}
		if (str[x][y] >= 'A' && str[x][y] <= 'Z') {
		    int u = now.u;
		    int c = idx(str[x][y]);
		    while (1) {
			u = ch[u][c];
			if (u == 0) break;
			if (dp[x][y][u] > now.val + 1) {
			    dp[x][y][u] = now.val + 1;
			    Q.push(State(x, y, u, now.val + 1));
			}
		    }
		} else {
		    int u = now.u;
		    if (dp[x][y][u] > now.val + 1) {
			dp[x][y][u] = now.val + 1;
			Q.push(State(x, y, u, now.val + 1));
		    }
		}
	    }
	}
	if (ans == INF) ans = -1;
	printf("%d\n", ans);
    }
    return 0;
}
时间: 2024-11-25 02:15:32

ZOJ Monthly, January 2015 (B、E、G、H)的相关文章

matrix_2015_1 138 - ZOJ Monthly, January 2015

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3844 第一个,n个数,每次操作最大数和最小数都变成他们的差值,最后n个数相同时输出此时的值,暴力跑. 1 #include<cstdio> 2 int main(){ 3 int t,n,a[16]; 4 while(~scanf("%d",&t)){ 5 while(t--){ 6 scanf("%d",&n);

Help Bob (141 - ZOJ Monthly, July 2015 )

题意: 现在有1-n个数,每次从中取出一个数,同时把这个数的所有因子取出.最后一个不能取数的人输 分析: 1是所有数的因子,所有第一次任取一个数1都会被取走:下面分两种情况: 我们先把1拿出来,对于其他的数 1.如果先手必败,那么先手第一次取1,然后把这种必败的状态留给对手,则先手必胜 2.如果先手必胜,则按照必胜的策越即可(1作为附带的被取出) #include <cstdio> int main() { int n; while(scanf("%d",&n)==

ZOJ 3905 Ant ZOJ Monthly, October 2015 - C

Cake Time Limit: 4 Seconds      Memory Limit: 65536 KB Alice and Bob like eating cake very much. One day, Alice and Bob went to a bakery and bought many cakes. Now we know that they have bought n cakes in the bakery. Both of them like delicious cakes

ZOJ 3910 Market ZOJ Monthly, October 2015 - H

Market Time Limit: 2 Seconds      Memory Limit: 65536 KB There's a fruit market in Byteland. The salesmen there only sell apples. There are n salesmen in the fruit market and the i-th salesman will sell at most wi apples. Every salesman has an immedi

ZOJ 3908 Number Game ZOJ Monthly, October 2015 - F

Number Game Time Limit: 2 Seconds      Memory Limit: 65536 KB The bored Bob is playing a number game. In the beginning, there are n numbers. For each turn, Bob will take out two numbers from the remaining numbers, and get the product of them. There i

ZOJ 3911 Prime Query ZOJ Monthly, October 2015 - I

Prime Query Time Limit: 1 Second      Memory Limit: 196608 KB You are given a simple task. Given a sequence A[i] with N numbers. You have to perform Q operations on the given sequence. Here are the operations: A v l, add the value v to element with i

Twelves Monkeys (multiset解法 141 - ZOJ Monthly, July 2015 - H)

Twelves Monkeys Time Limit: 5 Seconds      Memory Limit: 32768 KB James Cole is a convicted criminal living beneath a post-apocalyptic Philadelphia. Many years ago, the Earth's surface had been contaminated by a virus so deadly that it forced the sur

The Exchange of Items (141 - ZOJ Monthly, July 2015 - E 最小费用最大流)

The Exchange of Items Time Limit: 2 Seconds      Memory Limit: 65536 KB Bob lives in an ancient village, where transactions are done by one item exchange with another. Bob is very clever and he knows what items will become more valuable later on. So,

ZOJ Monthly, January 2018

A. Candy Game 显然最优策略是一个一个吃,故比较哪种糖果的个数比较多即可. #include<cstdio> int T,n,i,x,sum; int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n); sum=0; for(i=1;i<=n;i++)scanf("%d",&x),sum+=x; for(i=1;i<=n;i++)sca