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);
}