NOI**简单**英文题(dfs解多元方程,整数唯一分解定理(质因子))

15 篇文章 1 订阅
11 篇文章 0 订阅


#dfs为多元一次方程分配(决策)各变量的系数

Magic Sequence

#include <iostream>
#include <string.h>
using namespace std;
const int N=15;
int a[N];
int b[N];
int n;
int flag=0;
int vis[N];
void dfs(int s1,int s2,int cnt){
	if(cnt==0){
		if(s1==0&&s2==0){	
//			flag=1;
			if(!flag){
			memset(vis,0,sizeof(vis));
			for(int i=1;i<=n;i++){
				b[i]=a[i];
				vis[b[i]]++;
			}
//			for(int i=1;i<=n;i++){
//				cout<<b[i]<<" ";
//			}
//			cout<<endl;
			int j;
			for(j=0;j<n;j++){
				if(vis[j]!=a[j+1])break;
			}
			if(j==n)flag=1;
			}
		}
		return;
	}
	for(int i=0;i<n;i++){
		if(s1>=i&&s2>=i*(cnt-1)){
			a[cnt]=i;
			dfs(s1-i,s2-i*(cnt-1),cnt-1);
		}
		else break;
	}
}
int main(){ 
	cin>>n;
	dfs(n,n,n);
	if(flag){
		for(int i=1;i<=n;i++){
				cout<<b[i]<<endl;
			}
	}
	return 0;
}

在这里插入图片描述
在这里插入图片描述
借鉴了下一题的dfs思想

能分解出n个因子的最小正整数

https://codeforces.com/problemset/problem/27/E
在这里插入图片描述

所以每个质数的系数对因子数量贡献是等价的,因此,相同的因子数要想得到尽可能小的数字,肯定是小的质数次数比较大。又由于前16个质因数相乘已经大于1e18了,所以只考虑前16个质因数即可。由于数据范围很小,直接dfs选出每个质因数的次数,筛选出最小的结果即可。
由于ans要设置得大于1e18,一定要unsigned long long

#include <iostream>
#include <math.h>
using namespace std;
typedef  unsigned long long ll;//long long 过不了 

//最坏的情况,前16个质数的幂次都为1,那前16个数相乘也将超过1e18
int p[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; 
ll ans=1e18+5;
ll n;
void dfs(ll now,ll cnt,int pos){
	if(cnt==n){
		ans=min(ans,now);
		return ;
	}
	if(pos>=16)return;
	for(int i=1;i<=60;i++){//对于每个质因数取多少次 
		now*=p[pos];
//		cnt*=(1+i);
		if(now>1e18||cnt*(1+i)>n)break;//这条路走不通了
		dfs(now,cnt*(1+i),pos+1); 
	}
}
int main(){//能分解出n个因子的最小正整数n==(1+a1)*(1+a2)……
	 cin>>n;
	 dfs(1,1,0);
	cout<<ans;
	return 0;
}

coin change

在这里插入图片描述
本来是个典型的 恰好装满型的完全背包,写法见背包问题
但可以采用dfs的思想,
在这里插入图片描述
虽然但是,代码超时了,好歹学到了这种思想

class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
//		const int inf=0x3f3f3f;//要大于最小的,初始化为正无穷大
//		INT_MAX 可以直接代替inf啦 
		int res=INT_MAX;//至少需要多少硬币 
		sort(coins.begin(),coins.end(),greater<int>());
		dfs(coins,0,amount,0,res);
//后四个参数分别为,轮到枚举coins[turn]取几枚 ,
//总共还要取多少面值 
//当下取了多少,全局最少取几枚 
		if(res==INT_MAX)return -1;
		else return res;	
}
void dfs(vector<int>& coins,int turn,int target,int ans,int& res){
	if(turn>=coins.size())return;
	//if(coins[turn]>target)return;
	if(target%coins[turn]==0){//这才是一条路的终点,比较一条路的ans获得全局最小res 
		res=min(res,ans+target/coins[turn]);
		return;
	} 
	for(int i=target/coins[turn];i>=0;i--){//最多能取几枚该硬币
//		考虑到全局最优,不一定取得越多越好,so都要遍历 
		if(ans+i>=res-1)break;//下次肯定还要至少取一个 
		//res=min(res,ans+i);	//res是各条路比较得到的一条路花的最少的硬币数ans,
//		这里还没有取到amount,这条路还没走完 
		dfs(coins,turn+1,target-i*coins[turn],ans+i,res); 
	}
}
};

思想借鉴

Grocery Problem

整数的唯一分解定理
对于正整数n,仅存在一种方式将其分解成若干个质数幂次的乘积
X= p 1 {p_1} p1^ a 1 {a_1} a1 * p 2 {p_2} p2^ a 2 {a_2} a2 * p 3 {p_3} p3 ^ a 3 {a_3} a3 * … … …… * p n {p_n} pn^ a n {a_n} an

对于这类问题,一般采用试数的方法.操作过程是:把所有限制转换成为数学条件,然后逐一猜测答案并进行验算.而第一步:
转换为数学条件,直接关系到第二步验算的复杂程度.
首先对711000000做分解素因子处理 711000000 = 2 6 ∗ 3 2 ∗ 5 6 ∗ 79 711000000=2^6 *3^2 *5^6 *79 711000000=26325679
这里最令人注目的数字莫过于79了.把79的倍数列表如下:
0 ∗ 79 = 0 , 1 ∗ 79 = 79 , 2 ∗ 79 = 158 , 3 ∗ 79 = 237 , 4 ∗ 79 = 316 , 5 ∗ 79 = 395 , 6 ∗ 79 = 474 , 7 ∗ 79 = 553 , 8 ∗ 79 = 632 , 9 ∗ 79 = 711 0*79=0,1*79=79,2*79=158,3*79=237,4*79=316, 5*79=395,6*79=474,7*79=553,8*79=632,9*79=711 079=0,179=79,279=158,379=237,479=316,579=395,679=474,779=553,879=632,979=711
由于在4种物品的价格中,必有一个物品的价格为79的倍数,也就是上表中的一个数,而和数711也为79的倍数,所以另外3种物
品的价格之和也为79的倍数.该关系表示如下:
711 = ( 9 ∗ 79 ) = M ∗ 79 + N ∗ 79 711=(9*79)=M*79+N*79 711=979=M79+N79
这 里 , M ∗ 79 是 一 种 商 品 的 价 格 , 不 妨 令 A = M ∗ 79 , N ∗ 79 是 另 3 种 商 品 价 格 之 和 , 不 妨 令 B + C + D = N ∗ 79 这里,M*79是一种商品的价格,不妨令A=M*79,N*79是另3种商品价格之和,不妨令B+C+D=N * 79 ,M79,A=M79,N793,B+C+D=N79
显然 M + N = 9 M+N=9 M+N=9
下 面 我 们 来 筛 选 一 下 M , N 的 值 , 在 上 面 79 的 倍 数 表 中 , 因 为 不 能 有 3 个 数 都 小 于 100 , 所 以 N ≠ 0 , N ≠ 1 , 这 样 M ≠ 8 , M ≠ 9 而 7 并 未 出 现 于 711000000 的 素 因 子 集 合 中 , 所 以 下面我们来筛选一下M,N的值,在上面79的倍数表中,因为不能有3个数都小于100,所以N≠0,N≠1,这样M≠8,M≠9而7并未出现 于711000000的素因子集合中,所以 M,N,79,3100,N=0,N=1,M=8,M=97711000000,M≠7,N≠2. 当 然 M ≠ 0 是 显 而 易 见 的 , 所 以 N ≠ 9. 至 此 , M 可 以 取 的 值 为 1 , 2 , 3 , 4 , 5 , 6 , 当然M≠0是显而易见的,所以N≠9.至此,M可以取的值为1,2,3,4,5,6, M=0,N=9.,M1,2,3,4,5,6,

#include <iostream>
#include <algorithm>
using namespace std;
int p[4];
int main(){ 
	for(int x=1;x<=6;x++){
		int i=79*x; 
		for(int j=1;j<711-i;j++){
			for(int k=1;k<711-(i+j);k++){
				int l=711-i-j-k;
					if(i*j*k*l==711000000){
						p[0]=i;	p[1]=j;p[2]=k;p[3]=l;
						sort(p,p+4);
						for(int s=0;s<4;s++)cout<<p[s]<<" ";
//							cout<<i<<" "<<j<<" "<<k<<" "<<l;
						return 0;
					}
			}
		}
	}
	
	return 0;
}
//1.0、 
//#include <iostream>
//using namespace std;
//int main(){ 
//	for(int i=1;i<711;i++){
//		for(int j=1;j<711;j++){
//			for(int k=1;k<711;k++){
//				for(int l=1;l<711;l++){
//					if(i+j+k+l==711&&i*j*k*l==711000000){
//						cout<<i<<" "<<j<<" "<<k<<" "<<l;
//						return 0;
//					}
//				}
//			}
//		}
//	}
//	return 0;
//}
//2.0
//#include <iostream>
//using namespace std;
//int main(){ 
//	for(int i=1;i<711;i++){
//		for(int j=1;j<711-i;j++){
//			for(int k=1;k<711-(i+j);k++){
//				int l=711-i-j-k;
//				if(i*j*k*l==711000000){
//					cout<<i<<" "<<j<<" "<<k<<" "<<l;
//						return 0;
//				}
//			}
//		}
//	}
//	return 0;
//}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值