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

迭代加深

在這裏插入圖片描述

因爲深度是loglog的,所以可以用迭代加深,每次都控制一下深度。

第一次只能遞歸1層,如果沒有搜索到,限制遞歸2層,如果還沒有搜索到,就繼續往下遞增,直到搜到爲止。

在這裏插入圖片描述

  1. 每次我們最多增大兩倍,如果增大2r還沒到就不行。
  2. 不能超過我們要找的數mm
#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%

設有nn個最終的木棒,

枚舉每一個小木棒在每一個大木棒的情況,最後checkcheck一下。

時間複雜度: 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章