1. 程式人生 > >P1066 2^k進制數

P1066 2^k進制數

ica -h size space 滿足 9.1 vertica long long 十進制數

題目描述

r是個2k 進制數,並滿足以下條件:

(1)r至少是個2位的2k 進制數。

(2)作為2k 進制數,除最後一位外,r的每一位嚴格小於它右邊相鄰的那一位。

(3)將r轉換為2進制數q後,則q的總位數不超過w

在這裏,正整數k(1≤k≤9)w(k<W≤30000)是事先給定的。

問:滿足上述條件的不同的r共有多少個?

我們再從另一角度作些解釋:設S是長度為w 的01字符串(即字符串Sw個“0”或“1”組成),S對應於上述條件(3)中的q。將S從右起劃分為若幹個長度為k的段,每段對應一位2k進制的數,如果S至少可分成2段,則S所對應的二進制數又可以轉換為上述的2k

進制數r

例:設k=3,w=7。則r是個八進制數(23=8)。由於w=7,長度為701字符串按3位一段分,可分為3段(即1,3,3,左邊第一段只有一個二進制位),則滿足條件的八進制數有:

2位數:
高位為16個(即12,13,14,15,16,17),
高位為2:5個,
…,
高位為6:1個(即67)。
6+5+…+1=216+5+…+1=216+5++1=21個。

3位數:
高位只能是1
2位為25個(即123,124,125,126,127),
2位為3:4個,
…,
2位為61個(即167)。

5+4+…+1=15個。

所以,滿足要求的r共有36個。

輸入輸出格式

輸入格式:

2個正整數,用一個空格隔開:

kW

輸出格式:

1個正整數,為所求的計算結果,即滿足條件的不同的r的個數(用十進制數表示),要求最高位不得為0,各數字之間不得插入數字以外的其他字符(例如空格、換行符、逗號等)。

(提示:作為結果的正整數可能很大,但不會超過200位)

輸入輸出樣例

輸入樣例#1:
3 7
輸出樣例#1:
36

說明

NOIP 2006 提高組 第四題

Solution:

  本題DP+高精。

  DP比較明顯,定義狀態$f[i][j]$表示第$i$位為$j$的方案數,則$f[i][j]=\sum f[i-1][k],k<j$。

  首先第一維是可以滾掉的,然後轉移時不需要枚舉$k$,我們直接改下狀態$f[i][j]$表示第$i$位$\leq j$的方案數,每次轉移時改為維護前綴和,就能做到$O(w)$轉移($\frac{w}{k}\times k=w$)。

  那麽再在DP的基礎上寫個高精就好了。

代碼:

/*Code by 520 -- 9.14*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=55,Base=1e5;
int n,m;
struct node{
    int a[N],len;
    il void Clr(){memset(a,0,sizeof a),len=0;}
    il void Push(int x){a[len=1]=1;}
    node operator + (const node &x) const{
        node tp;tp.Clr();tp.len=max(len,x.len)+5;
        For(i,1,tp.len)
            tp.a[i]+=a[i]+x.a[i],
            tp.a[i+1]+=tp.a[i]/Base,
            tp.a[i]%=Base;
        For(i,1,tp.len) tp.a[i+1]+=tp.a[i]/Base,tp.a[i]%=Base;
        while(tp.len&&!tp.a[tp.len]) tp.len--;
        return tp;
    }
    il void Output(){
        printf("%d",a[len]);
        Bor(i,1,len-1) printf("%05d",a[i]);
    }
}ans,f[2][520];

int main(){
    cin>>n>>m;
    int pos=m/n,rest=m%n;
    int minn=(1<<rest)-1,maxn=(1<<n)-1;
    if(!rest) minn=maxn,pos--;
    Bor(i,1,maxn) f[0][i].Push(1);
    Bor(i,1,maxn) f[0][i]=f[0][i]+f[0][i+1];
    int tag=0;
    For(i,1,pos-1){
         Bor(j,1,maxn) f[tag^1][j]=f[tag^1][j]+f[tag^1][j+1]+f[tag][j+1],f[tag][j+1].Clr();
         f[tag][1].Clr();
         tag^=1,ans=ans+f[tag][1];
    }
    Bor(j,1,minn) f[tag^1][j]=f[tag^1][j]+f[tag^1][j+1]+f[tag][j+1];
    ans=ans+f[tag^1][1];
    ans.Output();
    return 0;
}

P1066 2^k進制數