普通DP
题目
你能看得出来每个数字需要几根火柴。给你n(大于等于5小于等于500)根火柴,问能摆出几种a-b=c,其中a b c没有前导零的正整数。答案mod m
input
input
4
12 1000000007
17 1000000007
20 1000000007
147 1000000007
output:
Case #1: 1
Case #2: 5
Case #3: 38
Case #4: 815630825
12 1000000007
17 1000000007
20 1000000007
147 1000000007
output:
Case #1: 1
Case #2: 5
Case #3: 38
Case #4: 815630825
代码
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
const int N = 555;
LL dp[N][2][8];//使用了i个木棍,是否有进位,是否结束了
int num[] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
int main(){
int T, t = 0;
cin >> T;
while(T--){
int n;
LL m;
cin >> n >> m;
n -= 3;
memset(dp, 0, sizeof(dp));
dp[0][0][0] = 1;
for(int i = 0; i <= n; i++) for(int j = 0; j < 2; ++j)
for(int k = 0; k < 7; ++k) if(dp[i][j][k]){
for(int x = 0; x < 10; ++x) for(int y = 0; y < 10; y++){
if((k&1) && x) continue;
if((k&2) && y) continue;
int z = x + y + j;
if((k&4) && z) continue;
int jj = z/10;
z %= 10;
int ii = i;
if(!(k&1)) ii += num[x];
if(!(k&2)) ii += num[y];
if(!(k&4)) ii += num[z];
if(ii > n) continue;
for(int kk = 0; kk < 8; ++kk) if((k&kk) == k){
if(jj && (kk&4)) continue;
if(x==0 && !(k&1) && (kk&1)) continue;
if(y==0 && !(k&2) && (kk&2)) continue;
if(z==0 && !(k&4) && (kk&4)) continue;
dp[ii][jj][kk] += dp[i][j][k];
dp[ii][jj][kk] %= m;
}
}
}
cout << "Case #" << ++t << ": " << dp[n][0][7] << endl;
}
return 0;
}
树DP
题目
给你一个图G没有子还,里面包含一个树T,输入时有n和节点m条边,点是[1,n],输入的前n-1个边是T,后面的m-n+1个边是G里面除了T其余的边。求最少删几条边使得图不连通,其中必须刚好有一条边是T里面的。
input
1
4 5
1 2
2 3
3 4
1 3
1 4
output:
Case #1: 2
方法:
枚举每个T的边。随便设一个root,然后枚举切断这个点和父节点之间的T里面的边。
对于每个其余边,在T里面的lca节点-2;每个节点+与他相连的其余边个数。