hihocoder 编程练习赛23
第一题:H国的身份证号码I
题意:一个N位的正整数(首位不能是0)。每位数字都小于等于K,并且任意相邻两位数字的乘积也小于等于K。按从小到大的顺序输出所有合法的N位号码,每个号码占一行。
思路:dfs
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N = 20; #define LL long long int n, k, a[N]; void dfs(int pos) { if (pos == n + 1){ for (int i = 1; i <= n; i++) printf("%d", a[i]); puts(""); return; } if (pos == 1){ for (int i = 1; i <= k; i++){ a[pos] = i; dfs(pos + 1); } } else{ for (int i = 0; i <= k; i++){ if (i * a[pos - 1] <= k){ a[pos] = i; dfs(pos + 1); } } } } int main() { while (~scanf("%d%d", &n, &k)){ dfs(1); } return 0; }
第二题:合并子目录
题意:小Hi发现其中一些子目录只包含另一个子目录,例如/hihocoder/offer22只包含一个子目录solution,/game只包含一个子目录moba,而moba也只包含一个子目录dota2。小Hi决定把这样的子目录合并成一个子目录,并且将被合并的子目录的名字用'-'连起来作为新子目录的名字。
思路:map数组记录前缀,num 数组记录节点孩子个数
mop[fa][ss] //fa表示前缀序列编号,ss为当前目录
代码:
#include<stdio.h> #include<string.h> #include<map> #include<vector> #include<string> #include<iostream> using namespace std; const int N = 5e5 + 10; typedef long long LL; int id, n, fa, num[N]; map<string, int> mop[N]; char s[N]; string ss; map<int, string> st; vector<int> a[N]; int main() { while (~scanf("%d", &n)){ id = 0; for (int i = 1; i <= n; i++){ scanf("%s", s); fa = 0; int len = strlen(s); ss = ""; s[len] = '/'; for (int j = 1; j <= len; j++){ if (s[j] == '/'){ if (mop[fa][ss] == 0){ mop[fa][ss] = ++id; num[fa] ++; // 儿子个数 } st[mop[fa][ss]] = ss; fa = mop[fa][ss]; a[i].push_back(fa); ss = ""; } else{ ss += s[j]; } } } for (int i = 1; i <= n; i++){ printf("/"); int size = a[i].size() - 1; num[a[i][size - 1]] ++; for (int j = 0; j < a[i].size() - 1; j++){ cout << st[a[i][j]]; if (num[a[i][j]] > 1) printf("/"); else printf("-"); } cout << st[a[i][size]] << endl; } } return 0; }
第三题:H国的身份证号码II
题意:第一题的扩展,对于100%的数据,1 ≤ N ≤ 1012,1 ≤ K ≤ 81,输出合法号码的总数。由于答案可能非常大,你只需要输出答案对109+7取模的结果。
思路:数位dp, 矩阵操作
f[i][j]:第一维表示位数,第二维表示目前的数字,值表示第 i 位为 j 时符合条件的总个数。
#include<stdio.h> #include<string.h> #include<map> #include<vector> #include<string> #include<iostream> #include<string> #include<algorithm> using namespace std; const int N = 10 + 10, Z = 1e9 + 7; typedef long long LL; #define ms(x, y) memset(x, y, sizeof(x)) #define mc(x, y) memcpy(x, y, sizeof(x)) struct matrix { LL v[N][N]; void O(){ ms(v, 0); }; //得到零矩阵 void E(){ ms(v, 0); for (int i = 0; i < 10; i++) v[i][i] = 1; } //得到单位矩阵 matrix operator *(const matrix &b){ //乘法 matrix c; c.O(); for (int k = 0; k < 10; k++){ for (int i = 0; i < 10; i++){ for (int j = 0; j < 10; j++){ c.v[i][j] = (c.v[i][j] + v[i][k] * b.v[k][j]) % Z; } } } return c; } matrix operator ^(LL p){ //快速幂 matrix x, y; x.E(); mc(y.v, v); while (p){ if (p & 1) x = x * y; p >>= 1; y = y * y; } return x; } }a, b; LL n; int k; int main() { while (~scanf("%lld%d", &n, &k)){ ms(a.v, 0); ms(b.v, 0); int top = min(9, k); for (int i = 1; i <= top; i++) a.v[0][i] = 1; for (int i = 0; i <= top; i++){ for (int j = 0; j <= top; j++){ if (i * j <= k) b.v[i][j] = 1; } } b = b ^ (n - 1); a = a * b; int ans = 0; for (int i = 0; i <= top; i++) ans = (ans + a.v[0][i]) % Z; printf("%d\n", ans); } return 0; }
第四题:观光旅行
题意:
思路: