uva 数学专题入门

uva 11388 - GCD LCM

描述:输入两个整数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


链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2989
描述:输入两个正整数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?

描述:求把K歌不超过N的非负整数加起来和为N的方法有多少种?(N,K∈ [1,100]), 输出结果对10^6的余数。
思路:dp问题,我自己写了个3*3矩阵就发现规律了。c[i][j] = c[i-1][j] + c[i][j-1]
 K   
N123 
1123 
2136 
31410 

#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;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PegasusWang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值