Evanyou Blog 彩带

P1066 2^k进制数

题目描述

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

 

posted @ 2018-09-15 17:14  five20  阅读(360)  评论(0编辑  收藏  举报
Live2D