2019 icpc 上海网络赛

F. Rhyme scheme
题意
给定n和k,要求输出长度为n的第k个Rhyme scheme。(1 ≤ n ≤ 26,1 ≤ k ≤ Bell Number(n) )

题解
1、Bell(26) 的值为12737758376199653042,远远超过unsigned long long,我们可以使用__int128。
2、使用动态规划做,详细的看代码。

代码

#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 27;

int t, n, ans[N];
__int128 d[N][N][N], k;

void read (__int128 &x) {
	x = 0;
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	for (; c <= '9' && c >= '0'; c = getchar()) {
		x = x * 10 + c - '0';
	}
}

void dp () {
	for (int i = 0; i <= 25; i++) {
		for (int j = 0; j <= 25; j++) {
			d[25][i][j] = 1;
		}
	}
	// 索引l 
	for (int l = 24; l >= 0; l--) {
		// i为索引l的字母为 i + 'A' 
		for (int i = 0; i <= l; i++) {
			// 父节点以及自己这个节点最大值为j 
			for (int j = 0; j <= l; j++) {
				// k为自己的节点的子节点的值 
				d[l][i][j] = d[l+1][j+1][j+1];
				for (int k = 0; k <= j; k++)  {
					d[l][i][j] += d[l+1][k][j];
				}
			}
		}
	}
}

void find (int cur, int i, int maxi) {
	if (n == cur) return ;
	for (int j = 0; j <= maxi; j++) {
		if (d[i][j][maxi] >= k) {
			ans[cur] = j;
			find(cur + 1, i + 1, maxi);
			return ;
		}
		k -= d[i][j][maxi];
	}
	ans[cur] = maxi + 1;
	find(cur + 1, i + 1, maxi + 1);
}

int main () {
	dp();
	scanf("%d\n", &t);
	for (int kase = 1; kase <= t; kase++) {
		scanf("%d\n", &n); read(k);
		find(0, 26 - n, 0);
		printf("Case #%d: ", kase);
		for (int i = 0; i < n; i++) {
			printf("%c", ans[i] + 'A');
		}
		printf("\n");
	}
	return 0;
}

比赛上我写出的题目

B. Light bulbs

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;

const int M = 1010;

vector<int> c;
int t, n, m, p[M*4], op[M][2];

int find (int x) {
	int l = 0, r = c.size() - 1;
	while (l < r) {
		int mid = (l + r + 1) / 2;
		if (c[mid] <= x) l = mid;
		else r = mid - 1;
	}
	return l + 1;
}

int main () {
	scanf("%d", &t);
	for (int kase = 1; kase <= t; kase++) {
		c.clear();
		memset(p, 0, sizeof(p));
		scanf("%d%d", &n, &m);
		for (int i = 0; i < m; i++) {
			scanf("%d%d", &op[i][0], &op[i][1]);
			c.push_back(op[i][0]);
			c.push_back(op[i][1]);
			c.push_back(op[i][1]+1);
		}
		sort(c.begin(), c.end());
		c.erase(unique(c.begin(), c.end()), c.end());
		for (int i = 0; i < m; i++) {
			int l = find(op[i][0]), r = find(op[i][1]);
			p[l]++;
			p[r+1]--;
		}
		for (int i = 1; i < c.size(); i++) {
			p[i] = p[i-1] + p[i] ;
		}
		int ans = 0;
		for (int i = 1; i < c.size(); i++) {
			if (p[i] % 2 == 1) {
				ans += c[i] - c[i-1];
			}
		}
		printf("Case #%d: %d\n", kase, ans);
	}
	return 0;
}

D. Counting Sequences I

#include <cstdio>

using namespace std;

typedef long long ll;

const int N = 3010;
const int mod = 1e9 + 7;

int t, n, val = 1, cache = 0;
ll f[N];
int num[1000], cnt[1000], tot;

ll quickpow(ll a, ll b) {
    if (b < 0) return 0;
    ll ret = 1;
    a %= mod;
    while (b) {
        if (b & 1) ret = (ret * a) % mod;
        b >>= 1;
        a = (a * a) % mod;
    }
    return ret;
}
ll inv(ll a) {
    return quickpow(a, mod - 2);
}

ll A (int x, int y) {
	ll val = 1;
	for (int i = y - x + 1; i <= y; i++) {
		val = (val * i) % mod;
	}
	return val;
}

void dfs (int cur, int i) {
	if (cur + val - cache >= 2 && cur + val - cache <= 3000) {
		ll ans = A(cur, cur + val - cache);
//		if (cur + val - cache == 3000) {
//			int z = 0;
//		}
		for (int j = 1; j <= tot; j++) {
			ans = (ans * inv(A(cnt[j], cnt[j]))) % mod;
		}
		f[cur + val - cache] = (f[cur + val - cache] + ans) % mod;
	}
	
	if (i > 1 && cur + val * i - i - cache <= 6000) {
		cache += i;
		val = val * i;
		cnt[tot]++;
		dfs(cur + 1, i);
		val = val / i;
		cnt[tot]--;
		cache -= i;
	}
	for (i = i + 1; i <= 3000; i++) {
		num[++tot] = i;
		if (cur + val * i - i - cache <= 6000) {
			cache += i;
			cnt[tot]++;
			val = val * i;
			
			dfs(cur + 1, i);
			
			val = val / i;
			cnt[tot]--;
			cache -= i;
		}
		tot--;
	}
}

int main () {
	dfs(0, 1);
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		printf("%lld\n", f[n]);
	}
	return 0;
}

J. Stone game

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;

const int N = 301;
const int M = 80000;
const int mod = 1e9 + 7;

int t, p[N], n, m, m0, m1;
ll cnt[M];

int main () {
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		m = 0;
		for (int i = 0; i < n; i++) {
			scanf("%d", &p[i]);
			p[i] = -p[i];
			m -= p[i];
		}
		sort(p, p + n);
		m0 = m / 2;
		m1 = m - m0;
		ll ans = 0;
		memset(cnt, 0, sizeof(cnt));
		cnt[0] = 1;
		for (int i = 0; i < n; i++) {
			p[i] = -p[i];
			for (int j = m0; j >= 0; j--)  {
				if (cnt[j] == 0)  continue;
				if (j + p[i] >= m1 && j <= m - j - p[i]) {
					ans = (ans + cnt[j]) % mod;
				}
				if (j + p[i] <= m0) {
					cnt[j + p[i]] = (cnt[j + p[i]] + cnt[j]) % mod;
				} 
			}
		}
		printf("%lld\n", ans);
	}
}

L. Digit sum

#include<cstdio> 

using namespace std;

const int N = 1e6 + 10;
const int B = 10 + 10;

int t, a, b;
int f[N][B];
int val[30];

void init () {
	int n, b, cnt;
	for (b = 2; b <= 10; b++) {
		cnt = 0;
		for (int i = 0; i < 30; i++) val[i] = 0;
		for (n = 1; n <= 1e6; n++) {
//			printf("%d %d\n", n, b);
			for (int i = 0; i < 30; i++) {
				val[i]++;
				cnt++;
				if (val[i] < b) break;
				val[i] = 0;
				cnt -= b;
			}
			f[n][b] += cnt + f[n-1][b];
		}
	}
}

int main () {
	init();
	scanf("%d", &t);
	for (int kase = 1; kase <= t; kase++) {
		int ans = 0;
		scanf("%d%d", &a, &b);
		printf("Case #%d: %d\n", kase, f[a][b]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值