uva 11388 - GCD LCM
链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2383
描述:输入两个整数G,L [1, 2^31],找出两个正整数a和b,使得二者最大公约数为G,最小公倍数为L。若有多解,输出a<=b且a最小的解。无解输出-1.
思路:设a=n1*G, b=n2*G, (n1,n2>=1)因为a*b=G*L, 代入得n1*n2*G=L,所以L是G的倍数,若L%G != 0,无解。
否则只要n1=1可以让a最小,所以b就等于L。
#include <iostream>
#include <cstdio>
using std::cin;
using std::endl;
using std::cout;
typedef long long LL;
LL gcd(LL a, LL b)
{
return b == 0 ? a : gcd(b, a % b);
}
int main()
{
int T;
scanf("%d", &T);
LL g, l;
while (T--)
{
cin >> g >> l;
if (l % g != 0)
{
cout << -1 << endl;
continue;
}
cout << g << " " << l << endl;
}
return 0;
}
Uva 11889 - Benefit
描述:输入两个正整数A和C,(A,C∈[1,10^7]), 求最小的整数B使得lcm(A, B)=C.无解输出NO SOLUTION
思路:A*B / gcd(a,b) = C,所以1/gcd(a,b) * B = C/A,所以枚举C/A的倍数就可以了。
#include <iostream>
#include <cstdio>
int gcd(int a, int b)
{ return b == 0 ? a : gcd(b, a % b); }
int main()
{
int T;
scanf("%d", &T);
int a, c;
while (T--)
{
scanf("%d %d", &a, &c);
if (c % a != 0)
{
printf("NO SOLUTION\n");
continue;
}
int step = c / a;
for (int i = step; i <= c; i += step) //注意i要从从c/a开始
if (i / gcd(a, i) == step)
{
printf("%d\n", i);
break;
}
}
return 0;
}
Uva 10943 - How do you add?
链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1884
描述:求把K歌不超过N的非负整数加起来和为N的方法有多少种?(N,K∈ [1,100]), 输出结果对10^6的余数。
思路:dp问题,我自己写了个3*3矩阵就发现规律了。c[i][j] = c[i-1][j] + c[i][j-1]
K | ||||
N | 1 | 2 | 3 | |
1 | 1 | 2 | 3 | |
2 | 1 | 3 | 6 | |
3 | 1 | 4 | 10 |
#include <iostream>
#include <cstdio>
#include <cstring>
const int MOD = 1000000, M = 110;
int c[M][M];
void init()
{
memset(c, 0, sizeof(c));
for (int i = 1; i < M; ++i)
c[i][1] = 1, c[1][i] = i;
for (int i = 2; i < M; ++i)
for (int j = 2; j < M; ++j)
c[i][j] = (c[i][j-1] + c[i-1][j]) % MOD;
}
int main()
{
int n, k;
init();
while (scanf("%d %d", &n, &k) && n && k)
{
printf("%d\n", c[n][k]);
}
return 0;
}
uva 11076 - Add Again
描述:输入n[1,12]个0到9的数字,这些数字任何一种排列都是一个整数。求出所有这些整数之和。
思路:多重集的排列问题:令S是一个多重集,有k个不同类型的元素,各元素分别有n1,n2......nk个。令S的大小为n=n1+n2+......nk,则S的排列数等于
n!/(n1!*n2*...nk!) .模拟的话肯定会超时,所以分别考虑每一个数字。对于每个数字,它可以放在个位,十位一直到第n位。
对于1 2 3三个数:
1可以放在第一个,第二个,第三个位置,总和是100+10+1 = 111,这时候剩下的数字有(3-1)! / ( (1-1)! *1!*1!) = 2种排列,所以结果是111*2 = 222. (0!=1)
同理可以求得2和3放置得到的和为222*2,333*2。结果就是111*2 + 222*2 + 333*2 = 1332.
实际上就是多重集的排列公式,放置每个数还剩n-1个,用n-1的阶乘除以所有数字个数的阶乘之积,如果放置的此数字有多个,当然分子里也要有该数字个数-1的阶乘。对应上面公式的(1-1)!。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ULL;
ULL sum(int a, int n) //求一个数字放在各个位置的总和
{
ULL t = 0;
for (int i = 0; i < n; ++i)
t = t * 10 + a;
return t;
}
ULL fac(ULL t) //求t的阶乘t!
{
ULL res = 1;
for (ULL i = 1; i <= t; ++i)
res *= i;
return res;
}
int main()
{
int n;
while (scanf("%d", &n) != EOF && n)
{
int a[n];
int cnt[11] = {0};
for (int i = 0; i < n; ++i)
{
scanf("%d", &a[i]);
++cnt[a[i]]; //cnt记录每个数字出现次数
}
ULL ans = 0;
for (int i = 0; i < 10; ++i)
{
if (cnt[i])
{
ULL t = fac(n-1) / fac(cnt[i]-1); //求多重集的排列
for (int j = 0; j < 10; ++j)
if (i != j && cnt[j])
t /= fac(cnt[j]);
ans += t * sum(i, n);
}
}
printf("%llu\n", ans);
}
return 0;
}