小天的子序列(牛客小白月赛83)

D-小天的子序列_牛客小白月赛83 (nowcoder.com)

题目:
小天的子序列(牛客小白月赛83)_第1张图片

分析:

注意到字符串的长度并不大,而询问的次数是1e5,我们大概可以知道,必须要在O(1)的时间复杂度去求出答案,这就要求我在询问之前去把答案求出来,怎么去求?暴力枚举以哪个字符开始,以哪个字符结尾,取的长度是多少? 因此我们就用一个数组ret[x][y][len]表示的是以x开头y结尾长度是len的子序列的个数, 但是还有个问题给你一段n,让你取出来m个的可能性是多少?高中数学问题!!! 在这里用一个C[n][m]表示的是在n个字符里面求出m个字符的情况C[n][m] = C[n - 1][m] + C[n - 1][m -1],但是需要注意的是C[n][0] = 1 这可别忘了

C[n][m] = C[n - 1][m] + C[n - 1][m - 1]的解释:
假如x是在n里面,那么在n选择m个的时候,x有两种情况,被选还是不被选, 要是被选的话,那就在剩下的里面(n - 1)再去选(m - 1)个, 要是不被选的话,那就是在剩下的(n - 1)里面去选(m)个,把这两种情况加在一起就是全部的情况了

代码:

#include
#define y1 Y1
#define fi first
#define endl "\n"
#define se second
#define PI acos(-1)
#define int long long
#define pb(x) push_back(x)
#define PII pair
#define Yes cout << "Yes\n";
#define No cout << "No\n";
#define YES cout << "YES\n";
#define NO cout << "NO\n";
#define _for(i, a, b) for(int i = a; i <= b; ++i)
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;

const int N = 2e5 + 10;
const int mod = 998244353;

int a[N];
int n, m;
string s;
int ret[30][30][510];
int c[510][510];

signed main() {
	IOS;
	cin >> n;
	cin >> s;
	 for (int i = 0; i <= n; i++)
        for (int j = 0; j <= i; j++)
            if (!j) c[i][j] = 1;
            else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
	//提前预处理字符串 快速记录每个字符的后面字符的位置
	for(int i = 0; i < n; ++ i ) {
		for(int j = i + 1; j < n; ++ j ) {
			for(int k = 2; k <= j - i + 1; ++ k ) {
				ret[s[i] - 'a'][s[j] - 'a'][k] = ret[s[i] - 'a'][s[j] - 'a'][k] + c[j - i + 1 - 2][k - 2] ;
				ret[s[i] - 'a'][s[j] - 'a'][k] %= mod;
			}
		}
	}
	
	int t;
	cin >> t;
	while(t--) {
		char x, y;
		int len;
		cin >> x >> y >> len;
		cout << ret[x - 'a' ][y - 'a' ][len] << endl;
	}
	return 0;
}

你可能感兴趣的:(牛客,算法)