其他分享
首页 > 其他分享> > 6/23~6/24

6/23~6/24

作者:互联网

1.除法uva725

题面:输入正整数n,按从小到大顺序输出所有形如abcde/fghij=n的表达式,其中aj恰好为09的一个排列,可以有前导零

注意点:

  1. 前导零只可能出现在除数中,即被除数为和除数最多为五位数

  2. 通过对除数进行dfs枚举,并记录该枚举方案是否有前导零,计算得到被除数,再检验每一个数字是否存在即可

#include<bits/stdc++.h>
using namespace std;
int n;
bool vis[10],flag;
int v[10];
int check(int a,int b){
	memset(v,0,sizeof v);
	int m;
	if(((a / 100000) > 0) || ((b / 100000) > 0))return 0;
	while(a){
		m = a % 10;
		a /= 10;
		v[m] += 1;
	}
	while(b){
		m = b % 10;
		b /= 10;
		v[m] += 1;
	}
	if(v[0] > 1)return 0;
	for(int i = 1; i <= 9; i++){
		if(v[i] != 1)return 0;
	}
	if(v[0] == 0)return 2;
	return 1;
}
void dfs(int cnt,int tot,int now){
	if(cnt >= tot){
		int m = n * now;
		if(check(m,now)){
			if(check(m,now) == 1)printf("%d / %d = %d\n",m,now,n);
			else printf("%d / 0%d = %d\n",m,now,n);
			flag = 1;
		}
		return;
	}
	for(int i = 0; i <= 9; i++){
		if(cnt == 0 && i == 0)continue;
		if(!vis[i]){
			now *= 10;
			now += i;
			vis[i] = 1;
			dfs(cnt + 1,tot,now);
			vis[i] = 0;
			now /= 10;
		}
	}
}
int main(){
	int cnt = 1;
	while(cin >> n){
		if(n == 0){
			break;
		}
		if(cnt != 1)puts("");
		flag = 0;
		for(int i = 1; i <= 5; i++){
			dfs(0,i,0);
		}
		cnt++;
		if(!flag)printf("There are no solutions for %d.\n",n);
	}
} 

2.分数拆分uva10976

题面:输入正整数k,找到所有正整数x >= y,使1/k = 1/x + 1/y

  1. 初看此题,容易直接将分数运算转换为浮点运算,然而限于精度等问题,这种思路是行不通的,因此,可以尝试通过枚举x或y与k通分进行运算,并检查是否符合题意即可
  2. 枚举x还是y?由关系式可以得到,2y<=k,因此y的范围可以很好确定,然而x不好确定其上界,因此选择y进行枚举
  3. 进行检验时,只需要检查一下算出的分数是否可以化简成1/x的形式即可,这里采用辗转相除法来计算最大公倍数
#include<bits/stdc++.h>
using namespace std;
int k;
const int MAXN = 10000;
int find(int a,int b){
	if(b == 0){
		return a;
	}
	int c = a % b;
	return find(b,c);
}
int get(int a,int b){
	int s = find(a,b);
	int num = (a / s) * (b / s) * s;
	return num;
}
struct item{
	int k,x,y; 
}w[MAXN]; 
int main(){
	freopen("B.out","w",stdout);
	while(cin >> k){
		int cnt = 0;
		for(int y = k + 1; y <= 2 * k; y++){
			int s = get(y,k);
			int a = s / k;
			int b = s / y;
			int m = a - b;
			if(s % m == 0){
				s /= m;
				cnt++;
				w[cnt].k = k;
				w[cnt].x = s;
				w[cnt].y = y;
			}
		}
		cout << cnt << endl;
		for(int i = 1; i <= cnt; i++){
			printf("1/%d = 1/%d + 1/%d\n",w[i].k,w[i].x,w[i].y);
		}
	}
}

3.邮票面值设计洛谷p1021

如题:给定一个信封,最多只允许粘贴 N 张邮票,计算在给定 K(N+K≤15)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值 MAX,使在 1 至 MAX 之间的每一个邮资值都能得到。

破题:设计邮票的面值 = 枚举邮票的面值 确定MAX = 根据所枚举出来的邮票来计算所能取到的最大的值

  1. 一个小细节:既然要求能够满足1—MAX之间的组合,这就意味着1必将是所取的邮票面值的一个
  2. 枚举的上界如何确定?这也是此题的一个难点之一,确定好了就过,否则TLE。
    由于要求可以组合成的面额必须连续,因此,如果本次枚举的面额过于大,则必然不能连续。易知,若面额max > n + 1,则无法构成连续组合!,因此,枚举的上界得以确定,该题结束一半。
  3. 确定MAX,自然想到通过动态规划来确定每种面额至少需要多少张邮票来组成(面额最大为n*(n + 1)),若张数大于最多的个数,则无法做到连续。(完)
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
int dp[MAXN],m,n,k,ans,mon[20],an[20];
int cal(int x){
	int ma = 0;
	ma = n * x;
	memset(dp,0x3f,sizeof dp);
	dp[0] = 0;
	for(int i = 1; i <= k; i++){
		for(int j = mon[i]; j <= ma; j++){
			dp[j] = min(dp[j],dp[j - mon[i]] + 1);
		}
	}
	for(int i = 1; i <= ma; i++){
		if(dp[i] > n)return i - 1;
	}
	return ma;
}
void dfs(int cnt,int last,int last1){
	if(cnt > k){
		int sum = cal(mon[k]);
//		cout << last << "**" << sum << endl; 
//		for(int i = 1; i <= k; i++){
//			cout << mon[i] << " "; 
//		}
//		puts("");
		if(ans < sum){
			ans = sum;
			for(int i = 1; i <= k; i++){
				an[i] = mon[i];
			}
		}
		return; 
	}
	for(int i = last + 1; i <= last1 + 1; i++){
		mon[cnt] = i;
		int x = cal(i);
		dfs(cnt + 1,i,x); 
		mon[cnt] = 0; 
	}
}
int main(){
	cin >> n >> k;
	m = (n + 1) * n;
	mon[1] = 1;
	dfs(2,1,n);
	for(int i = 1; i <= k; i++){
		cout << an[i] << " ";
	}
	puts("");
	printf("MAX=%d\n",ans);
}

4.洛谷p1118

  1. 杨辉三角加dfs,较轻松

标签:24,邮票,return,23,int,枚举,now,10
来源: https://www.cnblogs.com/CZ-9/p/16410394.html