[题解]GYM 100506C Cutting Banknotes
题意
给定一个数 ,以及 种不同面值的钞票 。(其中 可能是一个小数,但是 一定是整数)
你可以将 除以 ,得到新的面值。
如果你能通过这种方式,能够凑出 ,输出 yes
,否则输出 no
。
思路
首先,有一个显然的结论:如果 不是形如 的数,那么一定无解。
剩下的我的第一反应是一个完全背包。
首先将 一直除以 ,直到不能被 整除,再除以 。
这样一定能保证新的 能够取若干个得到原来的 ,使得结果不变。
但是,这样的处理会产生小数,所以用了一个 unordered_map
来搞。
显然,这样时间复杂度为错。
那么考虑将原本的 乘上 ,这样能保证结果不变,且时间复杂度少 。
但是,有一组 hack。
这组数据明显是输出 yes
,因为 , 能够通过一直除以 得到 。但是,按照这种思路会输出 no
。
那么,我们将值域开大一点,改为 就行。
Code
#include <bits/stdc++.h>
#define re register
using namespace std;
const int N = 1010,M = 1e6 + 10;
const double eps = 1e-6;
int T,n,m;
int arr[N];
bool dp[M];
double x;
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}
inline bool cmp(double a,double b){
return (fabs(a - b) <= eps);
}
inline bool check(double x){
int A = x;
double B = x - A;
return (cmp(B,0.0) || cmp(B,0.25) || cmp(B,0.5) || cmp(B,0.75));
}
int main(){
T = read();
while (T--){
memset(dp,false,sizeof(dp));
dp[0] = true;
scanf("%lf",&x);
n = read();
m = x * 64;
if (!check(x)){//特判无解
puts("no");
for (re int i = 1;i <= n;i++) arr[i] = read();
continue;
}
for (re int i = 1;i <= n;i++){
arr[i] = read();
while (!(arr[i] & 1)) arr[i] >>= 1;//处理新的值
}
sort(arr + 1,arr + n + 1);
int nn = unique(arr + 1,arr + n + 1) - arr - 1;//离散化,经试验在一般情况下能将 n 个元素降低为 n / 2 个元素
for (re int i = 1;i <= nn;i++){//完全背包
for (re int j = arr[i];j <= m;j++) dp[j] |= dp[j - arr[i]];
if (dp[m]) break;
}
if (dp[m]) puts("yes");
else puts("no");
}
return 0;
}
作者:WaterSun
出处:https://www.cnblogs.com/WaterSun/p/18268785
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】