錯排問題
N個有序元素打亂,不在原來的位置上,求方案總數。
將n號球放入k號箱子,則第k號球可放入n號箱子(+Dn-2),也可以不放入n號箱子(+Dn-1).
k可取(n-1)次
Dn = (n-1)(Dn-2+Dn-1)
一道規律題
問題 B: cb的小心心卡牌
時間限制: 1 Sec 內存限制: 128 MB
題目描述
cb是一個非常優秀的學長,他擁有一套自己心儀的卡牌,他將其命名爲“小心心”卡牌。
cb的卡牌很獨特,卡牌的面值都是2的次冪,比如1、2、4、8、16…等,你可以認爲每個2的次冪的面值cb都有,並且每個面值的卡牌都只有2張。
現在cb得到了一項任務,他被要求用“小心心”卡牌來拼湊出總面值爲n的卡牌集合。cb想知道他有多少種方法可以得到總面值爲n。
輸入
第一行一個整數T (0<T<1000)
接下來每行一個數字n (0<n<1000000)
輸出
輸出T行,每行爲湊出n的方法總數
樣例輸入
2
1
2
樣例輸出
1
2
提示
第一個樣例1只有一種拼湊方法,即 1
第二個樣例2有兩種拼湊方法,即2 與 1,1
Solution:用2的次冪湊數,也就是用二進制表示數。每兩個低次冪的數的和即爲高進制數:1+1=2,2+2=4,4+4=8。如果數字爲16,即10000,則組合的方式爲16,8+8,8+4+4,8+4+2+2,8+4+2+1+1,這五種寫法;同時推到其他數字,如果1010,即10這個數字,二進制表示方法爲8+2,所以我們將8與2的組合方式求出即可,注意處理8與2表示方法重合的部分,即如果8表示爲4+2+2,則2只能爲1+1。
//std
#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
int sum=0;//用sum來處理方案重疊的方法,並且sum記錄的是不含當前位置爲1的方案數的總和
int Max=1;//Max記錄爲已經處理過的以1開頭的方案數
while(n)
{
if(n%2==0)
sum+=Max;
else
Max+=sum;
n/=2;
}
printf("%d\n",Max);
}
return 0;
}
dp做法:
dp[1]=1;
dp[2]=2;
for (int j=3;j<=1000000;j++)
{
if (j%2!=0)//j爲奇數
dp[j]=dp[j-1]-dp[j-2];
else//j爲偶數
dp[j]=dp[j-1]+dp[j/2];
}