【题解】UVA10328 线性DP+大整数

29 篇文章 0 订阅
8 篇文章 0 订阅

题目链接
大整数型是NM什么鬼东西(雾)
首先是逆向思维,c[i][j]表示的是投掷i次,连续正面的个数最多不超过j次的情况有多少种,然后c[i][j] = c[i - 1][j] * 2,无非是第i次增加了两种情况,正面和反面,但是这样计算是要有些不符合条件的情况也考虑进去了,即c[i-1][j]会有说后面的j个为正面,那么在增加一个正面的话连续正面的个数就会变成j + 1个,所以要减去这种情况的个数。
投掷i - 1次的话,连续正面的个数不超过j个的话,又要说最后j个都为正面,那么第i - j - 1个就一定是反面(对应这类情况而言,并不是说i - j - 1为反面就一定不符合),那么只要满足前i - j - 2次中连续正面的个数不超过j的话,就是 要减掉的那部分。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=105;
struct bign{
    int len,sex;
    int s[2000];
    bign(){
        this->len=1;
        this->sex=0;
        memset(s,0,sizeof(s));
    }
    bign operator=(const char*number){
        int begin=0;
        len=0;
        sex=1;
        if(number[begin]=='-'){
            sex=-1;
            begin++;
        }
        else if(number[begin]=='+')
        begin++;
        for(int j=begin;number[j];j++)
        s[len++]=number[j]-'0';
    }
    bign operator=(int number){
        char string[N];
        sprintf(string,"%d",number);
        *this=string;
        return *this;
    }
    bign(int number){*this=number;}
    bign(const char*number){*this=number;}
    bign change(bign cur){
        bign now;
        now=cur;
        for(int i=0;i<cur.len;i++)
        now.s[i]=cur.s[cur.len-i-1];
        return now;
    }
    void delZore(){//删除前导0 
        bign now=change(*this);
        while(now.s[now.len-1]==0&&now.len>1)
        now.len--;
        *this=change(now);
    }
    void put(){//输出数据 
        delZore();
        if(sex<0&&(len!=1||s[0]!=0))
        cout<<"-";
        for(int i=0;i<len;i++)
        cout<<s[i];
    }
    bign operator + (const bign&cur){
        bign sum,a,b;
        sum.len=0;
        a=a.change(*this);
        b=b.change(cur);
        for(int i=0,g=0;g||i<a.len||i<b.len;i++){
            int x=g;
            if(i<a.len)x+=a.s[i];
            if(i<b.len)x+=b.s[i];
            sum.s[sum.len++]=x%10;
            g=x/10;
        }
        return sum.change(sum);
    }
    bign operator - (const bign&cur){
        bign sum,a,b;
        sum.len=len;
        a=a.change(*this);
        b=b.change(cur);
        for(int i=0;i<b.len;i++){
            sum.s[i]=a.s[i]-b.s[i]+sum.s[i];
            if(sum.s[i]<0){
                sum.s[i]+=10;
                sum.s[i+1]--;
            }
        }
        for(int i=b.len;i<a.len;i++){
            sum.s[i]+=a.s[i];
            if(sum.s[i]<0){
                sum.s[i]+=10;
                sum.s[i+1]--;
            }
        }
        return sum.change(sum);
    }
};
bign c[N][N],sum[N],tmp=1;
void init(){
    sum[0]=1;
    for(int i=1;i<=100;i++)
    sum[i]=sum[i-1]+sum[i-1];
    for(int i=0;i<=100;i++)
    c[i][0]=c[0][i]=1;
    for(int i=1;i<N;i++){
        for(int j=1;j<N;j++){
            c[i][j]=c[i-1][j]+c[i-1][j];
            if(i==j+1)
            c[i][j]=c[i][j]-tmp;
            else if(i>j+1)
            c[i][j]=c[i][j]-c[i-j-2][j];
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    init();
    int n,k;
    while(scanf("%d%d",&n,&k)==2)
    {
        bign ans=sum[n]-c[n][k-1];
        ans.put();
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值