The Preliminary Contest for ICPC Asia Shanghai 2019 F. Rhyme scheme (DP + int128)

46 篇文章 0 订阅
19 篇文章 0 订阅

The Preliminary Contest for ICPC Asia Shanghai 2019 F. Rhyme scheme

题目

题意很绕,其实大致就是给你 n 个数,让你划分集合,例如 n = 3;
集合划分为 :(一共有 5 种)
1 1 1
1 1 2
1 2 1
2 1 1
1 2 3
划分完集合后,让你用大写字母代表每个集合,但是从左往右填入字母按字典序来填:
在这里插入图片描述
其实给定 n 后,划分集合的方式数就是贝尔数。现在问你 第 k 个字符串是多少。

分析

其实对于每一个字符串 str,str[i] 最大是前面出现过的最大字母 + 1。可以用字典树表示:
在这里插入图片描述
现在问题变成问你这棵树第 n 层,第 m 个节点的路径。

找路径可以 DFS,但是暴力找不行。

如果我知道当前节点在第 n 层能扩展多少节点,那么对于每一层都可以直接确定走第几个节点。

可以用 dp 预处理下上面的。

代码

#include <bits/stdc++.h>
#define INF 0x3fffffff
#define fuck(x) cout << (x) << endl
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e6 + 10;

int t, n;
__int128 m, dp[100][100][100]; 
// dp[n][i][j] 表示长度为 n 时,在第 i 层,前面出现的字母最大是 j 有多少个

template <typename T> void read(T &x) {     // __int128 要自己实现 IO
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;    
}   

void init(){                        // 最多 26 层
	for(int n = 1; n <= 26; n++){
		for (int i = n; i >= 1; i--){
			if(i == n){	
				for (int j = 1; j <= i; j++)
					dp[n][i][j] = 1;
			}else{
				for(int j = 1; j <= i; j++){
					dp[n][i][j] = dp[n][i + 1][j] * j + dp[n][i + 1][j + 1];
				}
			}
		}
	}
}

void dfs(int id, int mmax){	// 遍历字符串树, id 表示第几层, mmax表示遇到最大的字符
	if(id == n)
		return;
	for (int i = 1; i <= mmax + 1; i++){ 	// 每层的上界都是遇到最大的字符 + 1
		int tmp = max(mmax, i);
		if(dp[n][id+1][tmp] < m){
			m -= dp[n][id + 1][tmp];
		}else{
			putchar('A' + i - 1);			// 选择输出第几个儿子
			dfs(id + 1, tmp);
			return;
		}
	}
}

int main(){
    init();
    scanf("%d", &t);
    for(int cas = 1; cas <= t; cas++){
        scanf("%d", &n);
        read(m);
        printf("Case #%d: ", cas);
		putchar('A');		// 'A' 是根节点
		dfs(1, 1);
		puts("");
    }
	return 0;
}
/*
1 1 1 1 1
1 2 3 4 5
2 5 10 17 26
5 15 37 77 141
15 52 151 372 799
*/

另一种 dp:

#include <bits/stdc++.h>
#define INF 0x3fffffff
#define fuck(x) cout << (x) << endl
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e6 + 10;

int t, n;
__int128 m, dp[32][32]; 
// dp[i][j] 表示后面还有 i 位,前面出现最大字母是 j 的节点儿子代表的不同字典序的数量

template <typename T> void read(T &x) {     // __int128 要自己实现 IO
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;    
}   

void init(){                        // 最多 26 层
    for (int i = 0; i <= 30; i++)   // 初始化,第 0 层节点只有一个
        dp[0][i] = 1;
    for (int i = 1; i <= 30; i++)
        for (int j = 0; j <= 30; j++)
            dp[i][j] = dp[i - 1][j] * j + dp[i - 1][j + 1];
}

int main(){
    init();
    scanf("%d", &t);
    for(int cas = 1; cas <= t; cas++){
        scanf("%d", &n);
        read(m);
        printf("Case #%d: ", cas);
        int tmp = 0, c = 0;
        for(int i = 1; i <= n; i++){
            for(c = 0; (m > dp[n-i][tmp]) && (c < tmp); c++)
                m -= dp[n - i][tmp];
            putchar('A' + c);
            tmp = max(tmp, c + 1);
        }
        puts("");
    }
    return 0;
}
/*
1 1 1 1 1
1 2 3 4 5
2 5 10 17 26
5 15 37 77 141
15 52 151 372 799
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000005;
int read(){
	int f=1,g=0;
	char ch=getchar();
	for (;!isdigit(ch);ch=getchar()) if (ch=='-') ch=-1;
	for (;isdigit(ch);ch=getchar()) g=g*10+ch-'0';
	return f*g;
}
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int T,n;
__int128 m,f[32][32];
int main(){
	for (int i=0;i<=30;i++) f[0][i]=1;
	for (int i=1;i<=30;i++)
	for (int j=0;j<=30;j++)
	f[i][j]=f[i-1][j]*j+f[i-1][j+1];
	T=read();
	for (int op=1;op<=T;op++){
		n=read();read(m);
		printf("Case #%d: ",op);
		int t=0,c=0;
		for (int i=1;i<=n;i++){
			for (c=0;(m>f[n-i][t])&&(c<t);c++) m-=f[n-i][t];
			putchar('A'+c);
			t=max(t,c+1);
		}
		puts("");
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Sure, I'd be happy to give you some ideas for organizing a speech contest. Here are some suggestions: 1. Determine the theme and rules: Decide on the theme of the contest and the rules for participants. Will it be an open topic, or will there be a specific theme? What is the maximum length of the speech? Will there be any specific guidelines for language or content? 2. Decide on the judging criteria: Determine how the speeches will be evaluated. Will judges be looking for content, delivery, or both? Will there be a score sheet or rubric that judges will use to score the speeches? 3. Recruit judges: Find people who are qualified to judge the speeches. Ideally, they should have experience in public speaking or have a background in the theme of the contest. 4. Promote the contest: Advertise the contest to potential participants, such as students, professionals, or members of a specific community. Use social media, flyers, and other methods to get the word out. 5. Registration and selection: Set a deadline for registration and selection of participants. Consider having a preliminary round to narrow down the field before the final competition. 6. Prepare the venue: Ensure that the venue is suitable for the contest. Make sure that there is adequate seating, sound equipment, and lighting for the speakers. 7. Hold the contest: Set a date and time for the contest, and make sure that all participants and judges are aware of the schedule. Encourage audience participation and provide refreshments. 8. Award ceremony: After the contest, hold an award ceremony to recognize the winners and participants. Provide certificates or other prizes to the top performers. I hope these ideas help you in organizing a successful speech contest!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值