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

第四题:观光旅行

题意:

思路:

时间: 2024-10-06 09:25:05

hihocoder 编程练习赛23的相关文章

hihocoder编程练习赛73 A 地铁站

1 /* 2 Source :hihocoder编程练习73 3 Problem :一个长度为n的串,由若干段1-a[i](假设有Y段)的序列组成,现在中间缺了K个数,问能够还原出来的方案数,需要保证还原出来的子串的个数最少,即最小Y 4 Solution :1.通过分析剩余的序列,我们可以知道原来最少的时候Y是多少,即看原来的序列有多少单调递增的子段. 5 2.进行有解的判断,假设已知序列段中每段的最大值是b[i] i=1..Y,如果sum(b[i]) > N,则说明无解,这是序列的长度一定已

【hihocoder编程练习赛9】闰秒

题目链接 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<math.h> 5 #include<iostream> 6 #include<stdlib.h> 7 #include<set> 8 #include<map> 9 #include<queue> 10 #include<vector&

hihoCoder编程练习赛70

题目1 : 数位翻转 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 n,你可以进行若干次操作,每次操作可以翻转 n 的二进制表示下的某一位,即将 0 变成 1,1 变成 0 现在小 Hi 想知道,至少需要多少次操作,才能将 n 变成 n-1 输入 一个正整数 n 1 ≤ n ≤ 109 输出 输出最少的操作次数 样例输入 10 样例输出 2 1 // 2018-07-29 2 #include <cstdio> 3 #include <cstr

hihoCoder编程练习赛69

题目1 : 偶数长度回文子串 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个小写字母字符串,请判断它是否有长度为偶数的非空连续回文子串 输入 输入包含多组数据. 每组数据包含一行一个小写字母字符串 S 1 ≤ |S| ≤ 105 输出 对于每组数据如果存在,输出YES,否则输出NO 样例输入 cabbad ababa 样例输出 YES NO 1 // 2018-07-29 2 #include <cstdio> 3 #include <cstring

hihoCoder编程练习赛72

题目1 : 玩具设计师 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho作为Z国知名玩具品牌AKIRE的首席设计师,对玩具零件的挑剔程度已经到了叹为观止的地步.所有的玩具零件均在一块由N × M个单位块组成的设计板上切割获得.每个单位块有一个耐用指数aij. 由于玩具制作安全标准要求每个零件的面积至少大于等于S,小Ho想要知道设计板上能切割出满足标准的最大耐用指数的玩具零件为多少. 输入 输入共N+1行,第一行三个整数N,M,S表示设计板的大小以及安全标准中对

hihocoder - [Offer收割]编程练习赛17

hihocoder - [Offer收割]编程练习赛17 题目1 : F1 Score 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和他的小伙伴们一起写了很多代码.时间一久有些代码究竟是不是自己写的,小Hi也分辨不出来了. 于是他实现了一个分类算法,希望用机器学习实现自动分类. 为了评价这个分类算法的优劣,他选出了N份有标记的代码作测试集,并决定用F1 Score作为评价标准. 给出N份代码的实际作者是不是小Hi以及分类算法预测的结果,请你计算F1 Sco

[.net 面向对象编程基础] (23) 结束语

[.net 面向对象编程基础] (23)  结束语 这个系列的文章终于写完了,用了半个多月的时间,没有令我的粉丝们失望.我的感觉就是一个字累,两个字好累,三个字非常累.小伙伴们看我每篇博客的时间就知道了,有多少个凌晨2.3点才完成的.其实在日常工作中用起来虽然比较容易,但要是真正的写出来,又要写的让初学者能看明白,真不是一件轻松的事情,其中里面有好多示例都要考虑如何写才能通俗易懂. 写这个系列的文章,有很多也是参考了博客园和网上的文章,没有一一列举出原作者和URL,在此表示感谢和歉意.但是我可以

HIHOcoder编程总结

[Offer收割]编程练习赛44 对于第一题题目1 : 扫雷游戏,首先要想清楚思路,虽然是暴力算法,但是这八个方向要自己把坐标写正确,不要慌乱,自己写的时候就写错了一个,第二个就是判断的时候,j + 1>=0,这种是显然的事情,应该是j +1 < N,写草稿也要认真. 还有一个非常非常大的错误. int N = 0; cin >> N; vector<string> input; input.resize(N); for (int i = 0; i < N; ++

hihocoder [Offer收割]编程练习赛18 C 最美和弦(dp)

题目链接:http://hihocoder.com/problemset/problem/1532 题解:一道基础的dp,设dp[i][j][k][l]表示处理到第几个数,当前是哪个和弦错了几次初始x值是多少.这里还要再辅助一个val[k]表示处理到当前情况只错了k次的最小值是多少因为改变的不止是和弦还有初始值,可以看一下代码理解一下. #include <iostream> #include <cstring> #include <cstdio> #include &