jzoj2019.03.09【NOIP提高組】模擬 B組 快速冪+狀壓搜索+輾轉相除

T1單峯

在這裏插入圖片描述在這裏插入圖片描述
可以發現,峯頂一定是n,因此考慮1~n-1 分別放在n 的左邊還是右邊,一一得出相應的唯一方案。所以答案就是2^(n-1)
再由數據範圍可知用快速冪即可
快速冪就是求x^n時,每逢n的二進制位爲1時才操作答案。在快速冪中可以隨時%

#include <cstdio>

using namespace std;

const long long mo=1e9+7;
long long n,ans;

void ksm(long long x,long long y){
	ans=1;
	while (x){
		if (x&1==1) {					
			ans=(ans*y)%mo;							
		}
		y=(y*y)%mo;
		x>>=1;
	}
}

int main(){
	scanf("%lld",&n);
	ksm(n-1,2);
	printf("%lld",ans);
}

T2積木

題目描述
數據描述
那麼,由n的數量之少以及狀態之多可知用狀態壓縮

對於狀態壓縮有

取出第i位 第i位賦爲1
x&(1<<i) x or (1<<i)

顯然是狀態壓縮DP。設計狀態f[S][i][0/1/2] 表示已經⽤了集合S 內的積⽊,最頂上是編
號爲i 的積⽊,它的哪個⾯朝上。轉移時枚舉不在S 內的積⽊,以及朝上的⾯判斷即可。時間
複雜度O(2n*(3n)^2)。
然後利用狀態壓縮進行記憶化搜索也行
剪枝方式有
1.用狀態壓縮表示第i塊積木是否已用;
2.將a,b,c簡單排序,可以規定長是較小的而寬則爲較大的,如此則枚舉每一塊積木時只需找a,b,c分別做爲高度的情況,因爲長寬的順序是 已固定的,且這種固定對答案不會有影響;

#include <cstdio>
#include <algorithm>

using namespace std;

int n,ans;
int a[20],b[20],c[20];

void dfs(int dep,int h,int ch,int k,long long x){
	if (dep>n) return;
	for (int i=1;i<=n;i++)
	if ((x&(1<<i))==0){
		if (a[i]<=ch){
			if (b[i]<=k){
				dfs(dep+1,h+c[i],a[i],b[i],x|1<<i);
			}
			if (c[i]<=k){
				dfs(dep+1,h+b[i],a[i],c[i],x|1<<i);
			}
		}
		if ((b[i]<=ch)&&(c[i]<=k)){
			dfs(dep+1,h+a[i],b[i],c[i],x|1<<i);
		}
	}
	if (h>ans) ans=h;
}

int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++){
		scanf("%d%d%d",&a[i],&b[i],&c[i]);
		if (a[i]>b[i]) swap(a[i],b[i]);
		if (a[i]>c[i]) swap(a[i],c[i]);
		if (b[i]>c[i]) swap(b[i],c[i]);
	}
	dfs(0,0,1e8,1e8,0);
	printf("%d",ans);
}

T3看電影

聽說NOIP2016大家都考得不錯,於是CCF獎勵省常中了 K 張變形金剛5的電影票獎勵OI隊的同學去看電影。可是省常中OI隊的同學們共有 N(N >= K)人。於是機智的你想到了一個公平公正的方法決定哪K人去看電影。
N個人排成一圈,按順時針順序標號爲1 - N,每次隨機一個還存活的人的編號,將這個人踢出。繼續上述操作,直到剩下K個人。
但這樣顯然太無聊了,於是小S又想出一個牛逼的方法。
N個人排成一圈,按順時針順序標號爲1 - N,每次隨機一個1 - N的編號,假設隨機到的編號是X,如果編號爲X人還未踢出,則將這個人踢出,否則看編號爲X % N + 1(即順時針順序下一個編號)的人是否存活,如果還未踢出則將他踢出,否則繼續看編號(X + 1)% N +1的人,如果已被踢出看順時針的下一個…………,以此類推,直到踢出一個人爲止。重複上述操作,直到剩下K個人。
已知小S的編號是Id,問按照小S的方法來他有多少的概率可以不被踢出,成功得到看電影的機會。

由於每次隨機到每個人的機率是固定的,所以每次每個人被踢出的概率都相等
可得無論Id值幾何,概率都是k/n,結果是k/n化爲最簡分數
這時可以用輾轉相除求出k,n的最大公因數

#include <cstdio>
#include <iostream>

using namespace std;

int n,k,id,c;

int gcd(int a,int b){
	if (b==0) return a;
		else return gcd(b,a%b);
}

int main(){
	scanf("%d%d%d",&n,&k,&id);
	if (k==n) printf("1/1"); else
	if (k==0) printf("0/1"); else
	if (k==1) printf("1/%d",n); else{
		c=gcd(n,k);
		printf("%d/%d",k/c,n/c);
	}
	cout<<(4&2);
}

冠蓋滿京華,斯人獨憔悴

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章