【ACM】2022.07.10训练赛
魔法宝石
点击查看题目
题目来源
题目描述
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 爱数数
点击查看题目
题目来源
题目描述
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;
}
自然数拆分
点击查看题目
题目来源
题目描述
对于任意大于 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;
}
数列分段【补】
点击查看题目
题目来源
题目描述

输入格式
第 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的个数
点击查看题目
题目来源
题目描述
蒜头君给了一个十进制正整数 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【补】
点击查看题目
题目来源
题目描述

输入格式

输出格式

样例输入 && 样例输出
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

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

代码思路
将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【补】
点击查看题目
题目来源
题目描述

输入格式

输出格式

输入样例 && 输出样例
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;
}

浙公网安备 33010602011771号