【ACM】2022.07.10训练赛

魔法宝石

点击查看题目

题目来源

计蒜客 - T1702 链接
VJ 链接

题目描述

Bessie 去珠宝商店想要买一些魔法宝石。商店里有 nn 个宝石,每个宝石的重量为 wi,幸运值为 vi。Bessie 的购物车只能装重量之和不超过 m 的商品,现在她想知道如何选择宝石,能让购买的幸运值之和最大。

输入格式

第一行两个整数 n,m,表示宝石的数量和购物车的承重能力。
接下来 n 行,每行两个整数 wi,vi,表示每个宝石的重量和幸运值。

输出格式

输出一个整数,表示幸运值之和最大值。

数据范围

1 <= n <= 3000 , 1 <= m <= 10000 , 1 <= wi,vi <= 100

样例输入

4 6
1 4
2 6
3 12
2 7

样例输出

23

代码思路

标准的01背包问题。
刚开始用二维过不去,优化到一维。

代码

点击查看代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 10010;

int n , m;
int f[N];
int w[N] , v[N];

int main()
{
	cin >> n >> m;
	
	for(int i = 1;i <= n;i ++)
		cin >> v[i] >> w[i];
	
	for(int i = 1;i <= n;i ++)
		for(int j = m;j >= v[i];j --)
			f[j] = max(f[j] , f[j-v[i]]+w[i]);
	
	cout << f[m] << endl; 
	
	return 0;
}

DD 爱数数

点击查看题目

题目来源

计蒜客 - T3004 链接
Vj 链接

题目描述

DD 在数学课上学习了素数,在信息课上学习了回文数,她现在很想知道,对于区间 [L,R],其中有多少个数既是素数又是回文数。

输入格式

第一行两个整数分别表示 L,R

输出格式

一个整数表示有多少个数满足条件

数据范围

对于 20% 的数据, L=R
对于 50% 的数据, L <= R <= 10^3
对于 100% 的数据,L <= R <= 10^6

样例输入

7 11

样例输出

2

代码思路

先用 埃氏筛法 筛出从1到R的所有素数,然后再从L开始遍历到R,找出即是素数又是回文数。
判断一个数是回文数:

bool is_hui(int x)
{
	int s = x ;
	int y = 0 ;
	while(s > 0){
		y = y*10 + s%10;
		s = s/10;
	}
	
	if(y == x)
		return true;
	
	return false;
}

代码

点击查看代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

const int N = 1e6+10;

int l , r;
int cnt = 0;
bool prime[N] , hui[N];
char a[N] , b[N];

void init_prime(int x)
{
	prime[0] = prime[1] = true;
	
	for(int i = 2;i <= x;i ++)
	{
		if(prime[i]) continue;
		for(int j = i+i;j <= x;j += i)
			prime[j] = true;
	}
}

bool is_hui(int x)
{
	int s = x ;
	int y = 0 ;
	while(s > 0){
		y = y*10 + s%10;
		s = s/10;
	}
	
	if(y == x)
		return true;
	
	return false;
}

int main()
{
	cin >> l >> r;
	
	init_prime(r);
	
	for(int i = l;i <= r;i ++)
	{
		if(!prime[i] && is_hui(i))
			cnt ++;
	}
	
	cout << cnt << endl;
	
	return 0;
}

自然数拆分

点击查看题目

题目来源

计蒜客 - T1248 链接
Vj 链接

题目描述

对于任意大于 1 的自然数 n,总是可以拆分成若干个小于 n 的自然数之和。

现请你编写程序求出 n 的所有拆分。

输入格式

输入文件共一行,包含一个自然数,即要拆分的自然数 n(1≤n≤20)。

输出格式

输出文件有若干行,每行包含一个等式,即代表一种可行的拆分(格式与顺序参见样例)。

样例输入

5

样例输出

5=1+1+1+1+1
5=1+1+1+2
5=1+1+3
5=1+2+2
5=1+4
5=2+3

代码思路

对于每一个数来说,有两个选择,要么选,要么不选。根据这一特性,选择DFS。

代码

点击查看代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

const int N = 25;
int num[N];
int n;

void dfs(int x,int sum,int len)//开始 总和 长度 
{
	if(sum == n)
	{
		cout << n << "=" ;
		for(int i = 0;i < len;i ++)
		{
			cout << num[i] ;
			if(i != len-1) cout << "+";
		}
		cout << endl;
		
		return;
	}
	
	for(int i = 1;i < n;i ++)
	{
		if(i >= x && sum+i <= n)
		{
			num[len] = i;
			len ++;
			dfs(i,sum+i,len);
			len --;
		}
	}
}

int main()
{
	cin >> n;
	
	dfs(1,0,0);
	
	return 0;
}

数列分段【补】

点击查看题目

题目来源

计蒜客 - T1877 链接
Vj 链接

题目描述

image

输入格式

第 1 行包含两个正整数 N,M(1 ≤ M ≤ N ≤ 10^5)。
第 2 行包含 N 个空格隔开的正整数Ai(1 ≤ Ai ≤ 10^4) 含义如题目所述。

输出格式

一个正整数,即每段和最大值最小为多少。

输入样例

5 3
4 2 4 5 1

输出样例

6

代码思路

找到最大值最小,就用二分
其中l是输入数据的最大值,r是输入数据的总和sum。
答案肯定在l和r之间。

代码

点击查看代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;

const int N = 1e5+10;
const int INF = 0x3f3f3f3f;

int n , m;
int a[N];
int ma = -INF , sum = 0;

int check(int x)
{
	int res = 0;
	int sum = 0;
	
	for(int i = 1;i <= n;i ++)
	{
		if(sum + a[i] >= x)
		{
			sum = a[i];
			res ++;
		}
		else
			sum += a[i];
	}
	
	return res;
}

int main()
{
	cin >> n >> m;
	
	for(int i = 1;i <= n; i++)
	{
		cin >> a[i];
		ma = max(ma , a[i]);
		sum += a[i];
	}
	
	int l = ma , r = sum;
	while(l <= r)
	{
		int mid = (l+r) >> 1;
		
		if(check(mid) < m) r = mid - 1;
		else l = mid + 1;
	}
	
	cout << r << endl;
	return 0;
}

数1的个数

点击查看题目

题目来源

计蒜客 - T1086 链接
Vj 链接

题目描述

蒜头君给了一个十进制正整数 n,让你帮忙写下从 1 到 n 的所有整数,然后数一下其中出现的数字1的个数。

例如当 n=2 时,写下 1,2 这样只出现了 1 个 1;
n=12 时,写下 1,2,3,4,5,6,7,8,9,10,11,12,这样出现了 5 个1。

输入格式

正整数 n。 1 ≤ n ≤ 10000

输出格式

一个正整数,即1的个数。

输入样例

12

输出样例

5

代码思路

暴力破解,循环找出1的个数

代码

点击查看代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

int main()
{
	int n;
	cin >> n;
	
	int cnt = 1;
	for(int i = 2;i <= n;i ++)
	{
		int num = i;
		while(num)
		{
			int x = num % 10;
			num /= 10;
			if(x == 1) cnt ++;
		}
	}
	
	cout << cnt << endl;
	
	return 0;
}

Buying a TV Set【补】

点击查看题目

题目来源

CodeForces - 1041B 链接
Vj 链接

题目描述

image

输入格式

image

输出格式

image

样例输入 && 样例输出

1

输入:17 15 5 3
输出:3

2

输入:14 16 7 22
输出:0

3

输入:4 2 6 4
输出:1

4

输入:1000000000000000000 1000000000000000000 999999866000004473 999999822000007597
输出:1000000063

Note

image

题目翻译

给出a , b , x , y四个数,找出有几个数存在以下条件:
image

代码思路

将x和y化为最简分数,答案就是a/x 和 b/y的最小值

代码

点击查看代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

typedef long long ll;

ll gcd(ll a ,ll b)
{
	if(a%b==0) return b;
	else return gcd(b,a%b);
}

int main()
{
	ll a , b , x ,  y;
	cin >> a >> b >> x >> y;
	
	ll g = gcd(x , y);
	
	x /= g;
	y /= g;
	
	cout << min((a/x) , (b/y)) << endl;;
	return 0;
}

Visiting a Friend【补】

点击查看题目

题目来源

CodeForces - 902A 链接
Vj 链接

题目描述

image

输入格式

image

输出格式

image

输入样例 && 输出样例

1
输入:

3 5
0 2
2 4
3 5

输出:YES
输入:

3 7
0 4
2 5
6 7

输出:NO

题目翻译

给出总共的长度,以及每个传送点的起始位置和传送长度,只能在传送点上移动,判断最终是否能到达终点。

代码思路

先判断起始位置中是否有0,如果没有则表示无法从0开始走,即无法到达终点
再判断最终的长度是否达到要求。
至于实现,只要维护一个目前能达到的最远距离就好。

代码

点击查看代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

int main()
{
	int n , m;
	cin >> n >> m;
	
	bool flag = false;
	int a , b , r = 0;
	
	for(int i = 0;i < n;i ++)
	{
		cin >> a >> b;
		
		if(a == 0) flag = true;
		if(a <= r)
			r = max(r , b);	
	}
	
	if(r < m)	flag = false;
	
	if(flag == true)
		cout << "YES" << endl;
	else
		cout << "NO" << endl;
		
	return 0;
}
posted @ 2022-07-11 10:34  HeyStar  阅读(68)  评论(0)    收藏  举报