uva 10328 Coin Toss

原题:
Toss is an important part of any event. When everything becomes equal toss is the ultimate decider.
Normally a fair coin is used for Toss. A coin has two sides head(H) and tail(T). Superstition may work
in case of choosing head or tail. If anyone becomes winner choosing head he always wants to choose
head. Nobody believes that his winning chance is 50-50. However in this problem we will deal with a
fair coin and n times tossing of such a coin. The result of such a tossing can be represented by a string.
Such as if 3 times tossing is used then there are possible 8 outcomes.

HHH HHT HTH HTT THH THT TTH TTT

As the coin is fair we can consider that the probability of each outcome is also equal. For simplicity
we can consider that if the same thing is repeated 8 times we can expect to get each possible sequence
once.
In the above example we see 1 sequence has 3 consecutive H, 3 sequence has 2 consecutive H and 7
sequence has at least single H. You have to generalize it. Suppose a coin is tossed n times. And the
same process is repeated 2^n times. How many sequence you will get which contains a sequence of H of
length at least k.
Input
The input will start with two positive integer, n and k (1 ≤ k ≤ n ≤ 100). Input is terminated by
EOF.
Output
For each test case show the result in a line as specified in the problem statement.
Sample Input
4 1
4 2
4 3
4 4
6 2
Sample Output
15
8
3
1
43

中文:
输入n,k,表示一个硬币连续抛n此得到的结果序列有2^n种,这其中有多少种含有连续至少k个正面?

#include <bits/stdc++.h>
using namespace std;
const int maxn=200;/*精度位数*/
/*(必选)类与基础功能定义,用法类似于unsigned(非负)*/
class bign
{
    friend istream& operator>>(istream&,bign&);/*输入运算符友元*/
    friend ostream& operator<<(ostream&,const bign&);/*输出运算符友元*/
    friend bign operator+(const bign&,const bign&);/*加号运算符友元*/
    friend bign operator*(const bign&,const bign&);/*乘号运算符友元*/
    friend bign operator*(const bign&,int);/*高精度乘以低精度乘法友元*/
    friend bign operator-(const bign&,const bign&);/*减号运算符友元*/
    friend bign operator/(const bign&,const bign&);/*除法运算符友元*/
    friend bign operator%(const bign&,const bign&);/*模运算符友元*/
    friend bool operator<(const bign&,const bign&);/*逻辑小于符友元*/
    friend bool operator>(const bign&,const bign&);/*逻辑大于符友元*/
    friend bool operator<=(const bign&,const bign&);/*逻辑小于等于符友元*/
    friend bool operator>=(const bign&,const bign&);/*逻辑大于等于符友元*/
    friend bool operator==(const bign&,const bign&);/*逻辑等符友元*/
    friend bool operator!=(const bign&,const bign&);/*逻辑不等符友元*/
private:
    int len,s[maxn];
public:
    bign(){memset(s,0,sizeof(s));len=1;}
    bign operator=(const char* num)
    {
        int i=0,ol;
        ol=len=strlen(num);
        while(num[i++]=='0'&&len>1)
        len--;
        memset(s,0,sizeof(s));
        for(i=0;i<len;i++)
        s[i]=num[ol-i-1]-'0';
        return *this;
    }
    bign operator=(int num)
    {
        char s[maxn];
        sprintf(s,"%d",num);
        *this=s;
        return *this;
    }
    bign(int num){*this=num;}
    bign(const char* num){*this=num;}
    string str() const
    {
        int i;
        string res="";
        for(i=0;i<len;i++)res=char(s[i]+'0')+res;
        if(res=="")res="0";
        return res;
    }
};
/*(可选)基本逻辑运算符重载*/
bool operator<(const bign& a,const bign& b)
{
    int i;
    if(a.len!=b.len)return a.len<b.len;
    for(i=a.len-1;i>=0;i--)
        if(a.s[i]!=b.s[i])
    return a.s[i]<b.s[i];
    return false;
}
bool operator>(const bign& a,const bign& b){return b<a;}
bool operator<=(const bign& a,const bign& b){return !(a>b);}
bool operator>=(const bign& a,const bign& b){return !(a<b);}
bool operator!=(const bign& a,const bign& b){return a<b||a>b;}
bool operator==(const bign& a,const bign& b){return !(a<b||a>b);}
/*(可选)加法运算符重载*/
bign operator+(const bign& a,const bign& b)
{
    int i,max=(a.len>b.len?a.len:b.len),t,c;
    bign sum;
    sum.len=0;
    for(i=0,c=0;c||i<max;i++)
    {
        t=c;
        if(i<a.len)t+=a.s[i];
        if(i<b.len)t+=b.s[i];
        sum.s[sum.len++]=t%10;
        c=t/10;
    }
    return sum;
}
/*(可选)乘法运算符重载(高精度乘高精度)*/
bign operator*(const bign& a,const bign& b)
{
    int i,j;
    bign res;
    for(i=0;i<a.len;i++)
    {
        for(j=0;j<b.len;j++)
        {
            res.s[i+j]+=(a.s[i]*b.s[j]);
            res.s[i+j+1]+=res.s[i+j]/10;
            res.s[i+j]%=10;
        }
    }
    res.len=a.len+b.len;
    while(res.s[res.len-1]==0&&res.len>1)res.len--;
    if(res.s[res.len])res.len++;
    return res;
}
/*高精度乘以低精度(注意:必须是bign*int顺序不能颠倒,要么会与高精度乘高精度发生冲突*/
bign operator*(const bign& a,int b)
{
    int i,t,c=0;
    bign res;
    for(i=0;i<a.len;i++)
    {
        t=a.s[i]*b+c;
        res.s[i]=t%10;
        c=t/10;
    }
    res.len=a.len;
    while(c!=0)
    {
        res.s[i++]=c%10;
        c/=10;
        res.len++;
    }
    return res;
}
/*(可选)减法运算符重载*/
bign operator-(const bign& a,const bign& b)
{
    bign res;
    int i,len=(a.len>b.len)?a.len:b.len;
    for(i=0;i<len;i++)
    {
        res.s[i]+=a.s[i]-b.s[i];
        if(res.s[i]<0)
        {
            res.s[i]+=10;
            res.s[i+1]--;
        }
    }
    while(res.s[len-1]==0&&len>1)len--;
    res.len=len;
    return res;
}
/*(可选)除法运算符重载(注意:减法和乘法运算和>=运算符必选)*/
bign operator/(const bign& a,const bign& b)
{
    int i,len=a.len;
    bign res,f;
    for(i=len-1;i>=0;i--)
    {
        f=f*10;
        f.s[0]=a.s[i];
        while(f>=b)
        {
            f=f-b;
            res.s[i]++;
        }
    }
    while(res.s[len-1]==0&&len>1)len--;
    res.len=len;
    return res;
}
/*(可选)模运算符重载(注意:减法和乘法运算和>=运算符必选)*/
bign operator%(const bign& a,const bign& b)
{
    int i,len=a.len;
    bign res,f;
    for(i=len-1;i>=0;i--)
    {
        f=f*10;
        f.s[0]=a.s[i];
        while(f>=b)
        {
            f=f-b;
            res.s[i]++;
        }
    }
    return f;
}
/*(可选)X等运算符重载(注意:X法必选)*/
bign& operator+=(bign& a,const bign& b)
{
    a=a+b;
    return a;
}
bign& operator-=(bign& a,const bign& b)
{
    a=a-b;
    return a;
}
bign& operator*=(bign& a,const bign& b)
{
    a=a*b;
    return a;
}
bign& operator/=(bign& a,const bign& b)
{
    a=a/b;
    return a;
}
/*可选前缀++/--与后缀++/--(注意:加法必选)*/
bign& operator++(bign& a)
{
    a=a+1;
    return a;
}
bign& operator++(bign& a,int)
{
    bign t=a;
    a=a+1;
    return t;
}
bign& operator--(bign& a)
{
    a=a-1;
    return a;
}
bign& operator--(bign& a,int)
{
    bign t=a;
    a=a-1;
    return t;
}
istream& operator>>(istream &in,bign& x)
{
    string s;
    in>>s;
    x=s.c_str();
    return in;
}
ostream& operator<<(ostream &out,const bign& x)
{
    out<<x.str();
    return out;
}
bign f[101][101];
bign pow2[201];
bign solve(int n,int k)
{
    bign ans=pow2[n-k];
    for(int i=2;i<=n-k+1;i++)
    {
        ans+=(pow2[n-k-1]-pow2[n-i-k+1]*f[i-2][k]);
    }
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    pow2[0]=1;
    for(int i=1;i<=200;i++)
        pow2[i]=pow2[i-1]*2;
    for(int i=0;i<=100;i++)
        f[0][i]=0;
    f[1][1]=1;
    for(int i=2;i<=100;i++)
    {
        for(int j=1;j<=i;j++)
            f[i][j]=solve(i,j);
    }
    int n,k;
    while(cin>>n>>k)
    {
        cout<<f[n][k]<<endl;
    }
    return 0;
}

解答:

想做会这道题,想要看此题
二者,差不多。

设f[n][k]表示抛n次硬币,得到至少k个连续个正面方案数。
那么,设置第一个连续的k个正面的位置在i,i+1,i+2,….i+k-1,在i的左侧,也就是1到i-2这些序列形成的方案不能包含大于等于k个连续的正面(范围是i到i-2的原因是第i-1个必须为反面)。设为g[n][k],表示抛n次得到的序列,其中不存在连续k个正面的方案数。
在i+k-1的右侧,也就是i+k到n这些,随意取正反面,有2^n-i-k+1种结果。
其中g[n][k]=2^n-f[n][k]

得到公式
f(n,k)=2nk+nk+1i2g(i2,k)2nik+1
第一个 2nk 表示连续k个正面从序列开头算起的情况,也就是i等于1时的值
g(n,k)=2nf(n,k)
将第二个公式代入第一个中得到
f(n,k)=nk+1i=22nk12nik+1f(i2,k)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值