【日常训练】【CF】20200604_子串_CF360C_数位dp

题面

题解

现场得分:100/100

这是一道比较简单的题目

下发题解

我的做法

  • 我是从后往前扫的。
  • (f_{i,j,0/1/2})表示当前从后往前弄到第(i)位,第(i)位及以后的位置为开头的区间已经有(j)个比较大了,当前这一位(T_i)(S_i)的大小关系((T_i<S_i)为0,等于为1,大于为2)。
  • 转移显然。

代码

题解

# include <bits/stdc++.h>
using namespace std;
namespace Base{
	# define mr make_pair
	typedef long long ll;
	typedef double db;
	const int inf = 0x3f3f3f3f, INF = 0x7fffffff;
	const ll  infll = 0x3f3f3f3f3f3f3f3fll, INFll = 0x7fffffffffffffffll;
	template<typename T> void read(T &x){
    	x = 0; int fh = 1; double num = 1.0; char ch = getchar();
		while (!isdigit(ch)){ if (ch == '-') fh = -1; ch = getchar(); }
		while (isdigit(ch)){ x = x * 10 + ch - '0'; ch = getchar(); }
	    if (ch == '.'){
	    	ch = getchar();
	    	while (isdigit(ch)){num /= 10; x = x + num * (ch - '0'); ch = getchar();}
		}
		x = x * fh;
	}
	template<typename T> void chmax(T &x, T y){x = x < y ? y : x;}
	template<typename T> void chmin(T &x, T y){x = x > y ? y : x;}
}
using namespace Base;

const int N = 2010, P = 1e9 + 7;
int f[N][N], n, m, q[N], g[N][N];
char s[N];
int main(){
	freopen("string.in", "r", stdin);
	freopen("string.out", "w", stdout); 
	read(n); read(m);
	scanf("
%s", s + 1);
	for (int i = 1; i <= n; i++) s[i] = 'z' - s[i];
	f[0][0] = 1;
	for (int k = 0; k <= m; k++)
		for (int i = 1; i <= n; i++){
			bool fg = false;
			f[k][i] = (f[k][i] + (f[k][i - 1] + g[k][i - 1]) * (26ll - s[i] - 1)) % P;
			g[k][i] = (1ll * g[k][i] + f[k][i - 1] + g[k][i - 1]) % P;
			for (int j = i; j <= n; j++){
				int ex = (j - i + 1) * (n - j + 1);
				if (ex + k > m){
					fg = true;
					break;
				}
				f[k + ex][j] = (f[k + ex][j] + 1ll * f[k][i - 1] * s[j]) % P;
			}
			if (fg == true){
				for (int j = n; j >= i; j--){
					int ex = (j - i + 1) * (n - j + 1);
					if (ex + k > m){
						fg = true;
						break;
					}
					f[k + ex][j] = (f[k + ex][j] + 1ll * f[k][i - 1] * s[j]) % P;
				}
			}
		}
	printf("%d
", (f[m][n] + g[m][n]) % P);
	return 0;
}

我的

#include<bits/stdc++.h>
#define LL long long
#define MOD 1000000007
#define MAXN 2010
using namespace std;
template<typename T>void Read(T &cn)
{
	char c; int sig = 1;
	while(!isdigit(c = getchar())) if(c == '-') sig = -1; cn = c-48;
	while(isdigit(c = getchar())) cn = cn*10+c-48; cn*=sig;
}
template<typename T>void Write(T cn)
{
	if(cn < 0) {putchar('-'); cn = 0-cn; }
	int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
	while(cn) wei++, cm = cm*10+cn%10, cn/=10;
	while(wei--) putchar(cm%10+48), cm /= 10;
	putchar(cx+48);
}
template<typename T>void Max(T &cn, T cm) {cn = cn < cm ? cm : cn; }
template<typename T>void Min(T &cn, T cm) {cn = cn < cm ? cn : cm; }
int n, k;
char c[MAXN+1];
LL f[MAXN+1][MAXN+1][3];
LL lei[MAXN+1];
void getit(char c[], int &clen)
{
	while(!isalpha(c[1] = getchar())); clen = 1;
	while(isalpha(c[++clen] = getchar())); clen--;
}
signed main()
{
//	freopen("string.in","r",stdin);
//	freopen("string.out","w",stdout);
	Read(n); Read(k);
	getit(c, n);
	for(int i = 0;i<=n+1;i++) for(int j = 0;j<=k;j++) f[i][j][0] = f[i][j][1] = f[i][j][2] = 0;
	for(int i = 1;i<=n+1;i++) f[i][0][1] = 1;
	memset(lei,0,sizeof(lei));
	for(int i = n;i>=1;i--) for(int j = 0;j<=k;j++)
	{
		f[i][j][0] = 1ll*(c[i]-'a')*(f[i+1][j][0] + f[i+1][j][1] + f[i+1][j][2])%MOD;
		f[i][j][1] = (lei[j] + f[i][j][1])%MOD;
		int lin = j-(n-i+1);
		if(lin>=0) {
			f[i][j][2] = 1ll*('z'-c[i])*(f[i+1][lin][0] + f[i+1][lin][1] + f[i+1][lin][2])%MOD;
			for(int ij = i-1, ik = j+(n-i+1);ij>=1 && ik <= k;ij--, ik = ik+(n-i+1)) f[ij][ik][1] = (f[ij][ik][1] + f[i][j][2])%MOD;
		}
		lei[j] = (lei[j] + f[i][j][0])%MOD;
	}
//	for(int i = n;i>=1;i--) for(int j = 0;j<=k;j++) printf("f[%d][%d] : %d %d %d
",i,j,f[i][j][0],f[i][j][1],f[i][j][2]);
	Write((f[1][k][0] + f[1][k][1] + f[1][k][2])%MOD); puts(""); 
	return 0;
}
原文地址:https://www.cnblogs.com/czyarl/p/13043924.html