TOJ 4453
2014-03-03 20:47
309 查看
题目标题:
Cards
题目连接:
http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=4453
题目类型:
模拟
数据结构:
无
思路分析:
类似于背包问题那样
一共5种卡片, 各有无限张
需要找出N张卡( 假设其中 1 有a1张, 2 有a2 张.... )
让其平均数 ( a1 *1 + a2 * 2 + a3 * 3 ...) / ( a1 + a2 + a3 ....)
精确的等于给定的值P,
既然这个P是符合规则的实数,且可能令N非常的大
所以不能单纯用背包思路来解决
首先要做的 先要吧P转换成整数, 并且假设一个整数来表示一共的张数
只要凑齐 这N张张数 并且值等于P的整数形式的 即可
并且需要符合最少张数这个条件
假如P为4.135
则我们知道 由 a1*1 + a2 * 2 ...得到的值除以总张数N就是 4.135
所以可以表现成 ( a1*1 + a2 * 2 ... ) / ( a1 + a2 + a3 ....) = 4.135 -> ( a1*1 + a2 * 2 ... ) / N = 4.135
要让张数最小 则对这个分数进行约分即可
则变成 4135 / 1000
最后只要让 N = 1000, ( a1*1 + a2 * 2 ... ) = 4135 就可以
这里有个小技巧
就是让牌乘起来刚好要大过 4135 然后继续减掉它跟 4135的差 那必定就是答案
就比如
大过4135 的排是1000张5的牌 这样 这1000张的总值是5000 并不是4135
则我们需要保持张数 又要让值减到4135
我们只需减去5000 - 4135 就可以了
因为我们能凑出单位1的值 那就是 5-4
所以 要保持张数 又要让值减5000 - 4135
最简单的办法就是 减去 这么多张5 再加回这么多张4 就可以了
既然题目说任意一种情况即可
那这就是最简单的情况了
证明:
要从中选N张卡片 让他们的总值除以N等于P
则我们得到 总值/N = P
因为 卡的种类和张数都是整数 所以这里的总值和N也只能是整数
所以我们可以转化P = P / 1 = P * 10000000 / 10000000;
这样的话 我们就得到 一个分子分母都是整数的分式 且答案等于P
那么这样的情况N并不是最小值 则我们对其进行约分
假设最简单分数 K/N = P 那我们就知道不存在更加少的情况了
因为
K/N=P 我们另N减去一个变量Z 就得到 K / ( N - Z ) = P 分母变小 我们需要让 分子变小来保持 分式的结果等于P 则得到 ( K - Y ) / ( N - Z ) = P
如果等式成立 则 原来的等式 K/N=P 必定不是最简分式
所以此时 的N 必然是正确且最小的
源代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
typedef __int64 int64;
int64 _gcd( int64 a, int64 b )
{
if( !b )
{
return a;
}
return _gcd( b, a % b );
}
int64 _cvrt( string c )
{
int64 i, zz= 0;
string tmp = "";
for( int i = 0; i < c.length(); i ++ )
{
if( c[i] != '.' )
{
tmp += c[i];
}
}
tmp = tmp + string( 10, '0' );
for( i = 0; i < 10; i ++ )
{
zz = zz * 10 + tmp[i] - '0';
}
return zz;
}
int main()
{
int64 i;
double inp;
string str = "";
cin >> str;
int64 arr[6] = { 0 };
int64 fm = 1000000000, fz = _cvrt( str );
int64 tmp = _gcd( fm, fz );
fm /= tmp;
fz /= tmp;
for( i = 1; i <= 5; i ++ )
{
if( fm * i > fz )
{
arr[i] = fm;
break;
}
else if( fm * i == fz )
{
arr[i] = fm;
i = -1;
break;
}
}
if( i != -1 )
{
arr[i - 1] = i * fm - fz;
arr[i] -= arr[i - 1];
}
for( i = 1; i <= 5; i ++ )
{
if( i != 1 )
{
printf( " " );
}
printf( "%I64d", arr[i] );
}
printf( "\n" );
return 0;
}
注意:
这里输入的实数不能用double
因为 会产生丢失精度的情况
假设 输入4.9 则会变成4.89999999 的情况
所以只能用字符串输入 然后转换成整形
Cards
题目连接:
http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=4453
题目类型:
模拟
数据结构:
无
思路分析:
类似于背包问题那样
一共5种卡片, 各有无限张
需要找出N张卡( 假设其中 1 有a1张, 2 有a2 张.... )
让其平均数 ( a1 *1 + a2 * 2 + a3 * 3 ...) / ( a1 + a2 + a3 ....)
精确的等于给定的值P,
既然这个P是符合规则的实数,且可能令N非常的大
所以不能单纯用背包思路来解决
首先要做的 先要吧P转换成整数, 并且假设一个整数来表示一共的张数
只要凑齐 这N张张数 并且值等于P的整数形式的 即可
并且需要符合最少张数这个条件
假如P为4.135
则我们知道 由 a1*1 + a2 * 2 ...得到的值除以总张数N就是 4.135
所以可以表现成 ( a1*1 + a2 * 2 ... ) / ( a1 + a2 + a3 ....) = 4.135 -> ( a1*1 + a2 * 2 ... ) / N = 4.135
要让张数最小 则对这个分数进行约分即可
则变成 4135 / 1000
最后只要让 N = 1000, ( a1*1 + a2 * 2 ... ) = 4135 就可以
这里有个小技巧
就是让牌乘起来刚好要大过 4135 然后继续减掉它跟 4135的差 那必定就是答案
就比如
大过4135 的排是1000张5的牌 这样 这1000张的总值是5000 并不是4135
则我们需要保持张数 又要让值减到4135
我们只需减去5000 - 4135 就可以了
因为我们能凑出单位1的值 那就是 5-4
所以 要保持张数 又要让值减5000 - 4135
最简单的办法就是 减去 这么多张5 再加回这么多张4 就可以了
既然题目说任意一种情况即可
那这就是最简单的情况了
证明:
要从中选N张卡片 让他们的总值除以N等于P
则我们得到 总值/N = P
因为 卡的种类和张数都是整数 所以这里的总值和N也只能是整数
所以我们可以转化P = P / 1 = P * 10000000 / 10000000;
这样的话 我们就得到 一个分子分母都是整数的分式 且答案等于P
那么这样的情况N并不是最小值 则我们对其进行约分
假设最简单分数 K/N = P 那我们就知道不存在更加少的情况了
因为
K/N=P 我们另N减去一个变量Z 就得到 K / ( N - Z ) = P 分母变小 我们需要让 分子变小来保持 分式的结果等于P 则得到 ( K - Y ) / ( N - Z ) = P
如果等式成立 则 原来的等式 K/N=P 必定不是最简分式
所以此时 的N 必然是正确且最小的
源代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
typedef __int64 int64;
int64 _gcd( int64 a, int64 b )
{
if( !b )
{
return a;
}
return _gcd( b, a % b );
}
int64 _cvrt( string c )
{
int64 i, zz= 0;
string tmp = "";
for( int i = 0; i < c.length(); i ++ )
{
if( c[i] != '.' )
{
tmp += c[i];
}
}
tmp = tmp + string( 10, '0' );
for( i = 0; i < 10; i ++ )
{
zz = zz * 10 + tmp[i] - '0';
}
return zz;
}
int main()
{
int64 i;
double inp;
string str = "";
cin >> str;
int64 arr[6] = { 0 };
int64 fm = 1000000000, fz = _cvrt( str );
int64 tmp = _gcd( fm, fz );
fm /= tmp;
fz /= tmp;
for( i = 1; i <= 5; i ++ )
{
if( fm * i > fz )
{
arr[i] = fm;
break;
}
else if( fm * i == fz )
{
arr[i] = fm;
i = -1;
break;
}
}
if( i != -1 )
{
arr[i - 1] = i * fm - fz;
arr[i] -= arr[i - 1];
}
for( i = 1; i <= 5; i ++ )
{
if( i != 1 )
{
printf( " " );
}
printf( "%I64d", arr[i] );
}
printf( "\n" );
return 0;
}
注意:
这里输入的实数不能用double
因为 会产生丢失精度的情况
假设 输入4.9 则会变成4.89999999 的情况
所以只能用字符串输入 然后转换成整形
相关文章推荐
- 由toj“勇闯黄金十二宫-金牛宫”想到的
- toj 2843 Diamonds
- toj 2970 Hackle Number
- TOJ 1765 Longest Ordered Subsequence 最长上升子序列 DP
- TOJ 2299. Electricity【求无向图割点】
- TOJ 比赛C题 Visiting Cows (TJU 2011 Exercise Contest 04)
- TOJ 3486 SOJ 1009 母函数
- TOJ 1923
- toj 3345. Chinese Chess 关键匹配
- TOJ 4224 Cryptologist
- TOJ 2732存钱计划(三)(单源最短路)
- HDU 4453 Looploop (双向链表)
- hdu4453 伸展树
- toj 3086 Passage (不错)
- TOJ 1772
- TOJ 1981
- TOJ 4394 Rebuild Road
- TOJ 1840 Jack Straws
- TOJ 3176 Challenge from XOR
- TOJ 4289 Unrequited Love