ABC211


C

题意:给你一个串S,从里面选8个字符,问有多少种选法,使得从左到右读起来是chokudai

方法:dp

状态:\(f(i, j)\)表示在S的前i个字符中选j个字符,和chokudai的前j个字符一样的选法总数

状态计算:

\[f(i, j)= \begin{cases} 0 & i 0\\ f(i - 1, j) + 1 & s[i] = c[j]\and j = 0\\ \end{cases} \]

初始条件:如果s[0] = c[0], 那么\(f(0, 0) = 1\)

#include
#include
#include
#include

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
#include
#include

using namespace std;

const int N = 2e5 + 10, mod = 1e9 + 7;

int n, m;

vector 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 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];
}