一开始想了一个复杂度爆炸的 DP
分析
首先考察题目的性质:
方便起见,将字符看成是 \([0,25]\) 的值。
注意到操作可以等价于选择任意两个下标,然后对应的两个值一加一减或者一减一加。
这样的操作显然不会改变字符串的值和(也就是字符串中每个字符对应的值的和)
进一步地,可以发现答案就是与当前字符串值和(记为 \(val\))相等的字符串个数(当然因为当前字符串本身不计入,所以答案即为所有合法且值和为 \(val\) 的字符串个数 - 1)
这里合法字符串就是每个字符为小写字符的字符串。
考虑 DP 求解:
记长 \(i\) 个字符,值和为 \(j\) 的合法字符串有 \(f(i, j)\) 个。
那么有转移:\(f(i, j) = \sum_c f(i-1, j-c)\),其中 \(c\in [0, 25]\) 且 \(j-c \geq 0\)。
// Problem: Cipher
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF156C
// Memory Limit: 250 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define x first
#define y second
using pii = pair<int, int>;
using ll = long long;
inline void read(int &x){
int s=0; x=1;
char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
x*=s;
}
const int N=110, mod=1e9+7;
int f[N][2605];
int add(int x, int y){
return x+y>=mod? x+y-mod: x+y<0? x+y+mod: x+y;
}
void init(){
f[0][0]=1;
rep(i, 1, 100){
rep(j, 0, 2600){
rep(c, 0, 25){
if(j-c>=0) f[i][j]=add(f[i][j], f[i-1][j-c]);
}
}
}
}
void solve(){
string s; cin>>s;
int n=s.size();
int val=0;
for(auto i: s) val+=(i-'a');
cout<<add(f[n][val], -1)<<endl;
}
signed main(){
init();
int cs; cin>>cs;
while(cs--) solve();
return 0;
}
标签:ch,val,int,字符串,CF156C,DP,define
From: https://www.cnblogs.com/Tenshi/p/17151050.html