2018提高组模拟16

——————————————————————————————————20181101

2592 cost数
2107 某种密码
3749 递增数列
3207 木棒分组

【以上题目均出自WOJ】



T1 cost数

容斥原理

数学推理

GCD【最大公因数】

LCM【最小公倍数】
在这里插入图片描述

20%

直接暴力

60%

根据容斥原理,三个的时候很好推

在这里插入图片描述

在这里插入图片描述

100%

容斥原理可以加到n

  • 这时我们需要用个dfs枚举每个ai选与不选,
  • 若选出k个数,且k为奇数,则ans加上m/LCM(选出的数),若为偶数ans减去m/LCM(选出的数)。
  • 当然,还要加上优化,包括可行性剪枝(选出的数的LCM要小于等于m。由于ai>17ai>17,该剪枝十分有效)、优化搜索顺序(先搜大数)。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m,a[40],ans=0;
int gcd(int x,int y){
	int t;
	if(x<y)t=y,y=x,x=t;
	while(y){
		t=x%y;
		x=y;
		y=t;
	}
	return x;
}
ll lcm(int x,int y){
	return 1ll*x/gcd(x,y)*y;
}
void dfs(int pos,ll l,int k){
	if(l>m)return;
	if(pos>n){
		if(k%2){
			ans+=m/l;
		}
		else if(k)ans-=m/l;
		return;
	}
	dfs(pos+1,l,k);
	ll r=lcm(l,a[pos]);
	if(r<=m)dfs(pos+1,r,k+1);
}
inline int Sort(int x,int y){
	return x>y;
}
int main(){
	scanf("%d%d",&n,&m);
	m-=17;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	sort(a+1,a+n+1,Sort);
	dfs(1,1,0);
	printf("%d",ans+1);
	return 0;
}

T2 某种密码

DFS

折半搜索

STL

在这里插入图片描述

60%

直接暴力每一个选不选

100%

其实这道题是一个01背包,但容积太大,无法开数组,时间也受不了。

看在物品少,只有40的情况下,就只有暴搜了。

先将物品分为两半A,B,按 60% 的方法搜索,并记录。

对集合A暴力枚举其所有子集中元素和并存入哈希表(可重集),

再对集合B暴力枚举每个子集的元素和s,

同时查找哈希表中值为(key−s)的元素个数并计数。

时间复杂度为O(2n/2)。

如果用STL的话,可以用

#include<tr1/unordered_map>
using namespace tr1;
tr1::unordered_map<long long,int>Map;

比较快。


#include<bits/stdc++.h>
#include<tr1/unordered_map>
using namespace std;
using namespace tr1;
#define ll long long
int n,a[50];
ll k,ans=0;
tr1::unordered_map<ll,int>s;
void dfs1(int pos,int mx,ll sum){
	if(pos>mx){
		s[sum]++;
		return;
	}
	dfs1(pos+1,mx,sum+a[pos]);
	dfs1(pos+1,mx,sum);
}
void dfs2(int pos,int mx,ll sum){
	if(pos>mx){
		if(s.find(k-sum)!=s.end())ans+=s[k-sum];
		return;
	}
	dfs2(pos+1,mx,sum+a[pos]);
	dfs2(pos+1,mx,sum);
}
int main(){
	scanf("%d%lld",&n,&k);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	dfs1(1,n/2,0);
	dfs2(n/2+1,n,0);
	printf("%lld",ans);
	return 0;
}

T3 递增数列

DFS

迭代加深

在这里插入图片描述

因为深度是 l o g log log的,所以可以用迭代加深,每次都控制一下深度。

第一次只能递归1层,如果没有搜索到,限制递归2层,如果还没有搜索到,就继续往下递增,直到搜到为止。

在这里插入图片描述

  1. 每次我们最多增大两倍,如果增大2r还没到就不行。
  2. 不能超过我们要找的数 m m m
#include<bits/stdc++.h>
using namespace std;
int m,h,ans[1000];
bool dfs(int x,int dep){
	if(dep>h)return 0;
	if(x<<(h-dep)<m)return 0;
	if(x>m)return 0;
	if(x==m)return 1;
	ans[dep]=x;
	for(int i=dep;i>=0;i--)
		if(dfs(x+ans[i],dep+1))return 1;
	return 0;
}
int main(){
	scanf("%d",&m);
	for(h=0;;h++){
		if(dfs(1,0))break;
	}
	printf("%d\n",h+1);
	for(int i=0;i<h;i++)
		printf("%d ",ans[i]);
	printf("%d",m);
	return 0;
}

T4 木棒分组

DFS

搜索剪枝

洛谷【有点不同】

在这里插入图片描述

70%

设有 n n n个最终的木棒,

枚举每一个小木棒在每一个大木棒的情况,最后 c h e c k check check一下。

时间复杂度: O ( nn )

100%

题解: * _ *

#include<bits/stdc++.h>
using namespace std;
int a[60],n,mx=0,all=0,cnt,len,vis[60];
inline int Sort(int x,int y){
	return x>y;
}
bool dfs(int use,int cab,int pos){
	//多少个已拼好  当前根拼了多少  上一次用的什么
	if(use>cnt)return 1;
	if(cab==len)return dfs(use+1,0,1);
	int last=0;
	for(int i=pos;i<=n;i++){
		if(!vis[i]&&cab+a[i]<=len&&last!=a[i]){
			vis[i]=1;
			if(dfs(use,cab+a[i],i+1))return 1;
			last=a[i];
			vis[i]=0;
			if(!cab||cab+a[i]==len)return 0;
		}
	} 
	return 0;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		if(a[i]>mx)mx=a[i];
		all+=a[i]; 
	}
	sort(a+1,a+n+1,Sort);
	for(len=mx;len<=all/2;len++){
		if(all%len)continue;
		cnt=all/len;//cnt根 
		memset(vis,0,sizeof(vis));
		if(dfs(1,0,1)){
			printf("%d",len);
			return 0;
		}
	}
	printf("%d",all);
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值