C
题意:给你一个串S,从里面选8个字符,问有多少种选法,使得从左到右读起来是chokudai
方法:dp
状态:\(f(i, j)\)表示在S的前i个字符中选j个字符,和chokudai
的前j个字符一样的选法总数
状态计算:
\[f(i, j)= \begin{cases} 0 & i<j\\ f(i - 1, j) & s[i] \ne c[j]\\ f(i - 1, j) + f(i - 1, j - 1) & s[i] = c[j]\and j > 0\\ f(i - 1, j) + 1 & s[i] = c[j]\and j = 0\\ \end{cases} \]初始条件:如果s[0] = c[0], 那么\(f(0, 0) = 1\)
#include<iostream>
#include<vector>
#include<queue>
#include<string>
using namespace std;
const int N = 1e5 + 10, mod = 1e9 + 7;
string s, c = "chokudai";
int f[N][8];
int main(){
cin >> s;
if(s[0] == c[0]) f[0][0] = 1;
for(int i = 1; i < s.size(); i ++)
for(int j = 0; j < 8; j ++){
if(i < j) break;
f[i][j] = f[i - 1][j];
if(s[i] == c[j]){
if(!j) f[i][j] = (f[i][j] + 1) % mod;
else f[i][j] = (f[i][j] + f[i - 1][j - 1]) % mod;
}
}
cout << f[(int) s.size() - 1][7];
}
D
题意:一个图,N个顶点,M条边,每条边长度为1,问从1到N有多少条最短路
方法:令\(f(i)\)表示从1到i的最短路个数,那么\(f(i) = \sum f(j)\), j可以直接到i,那么,可以从1开始bfs,记录每一个点到1的最短距离dist,在bfs过程中,如果再次访问到了某一个点k(由h访问到),dist[h] + 1和已知的dist[k]是否相等,如果相等,令f[k] += f[h],最后答案就是f[n]
注意:由于使用的是bfs,只有前面结点的f值更新完了才回去更新后面的f值
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int N = 2e5 + 10, mod = 1e9 + 7;
int n, m;
vector<int> v[N];
int f[N], dist[N];
int st[N];
int main(){
cin >> n >> m;
while(m --){
int a, b;
cin >> a >> b;
v[a].push_back(b);
v[b].push_back(a);
}
queue<int> q;
q.push(1);
st[1] = 1;
dist[1] = 0;
f[1] = 1;
while(q.size()){
int h = q.front();
q.pop();
for(int i = 0; i < v[h].size(); i ++){
int j = v[h][i];
int d = dist[h] + 1;
if(st[j]){
if(d == dist[j]) f[j] = (f[j] + f[h]) % mod;
continue;
}
st[j] = 1;
dist[j] = d;
f[j] = f[h];
q.push(j);
}
}
cout << f[n];
}