题意:抛出n次硬币(有顺序),求至少k个以上的连续正面的情况的种数。

思路:转换成求抛n个硬币,至多k-1个连续的情况种数,用所有可能出现的情况种数减去至多k-1个的情况,就得到答案了。此题涉及大数加减。

分析:

(1)假设n=k,那么只有一种情况。

(2)假设n=k+1,那么有3种情况,包含k个的两种,k+1个的一种。

(3)假设k=1,那么只有无正面这一种的情况不能被考虑,其他都能算,那么就是(1<<n)-1种。(n个硬币有2^n种结果)

(4)其他情况考虑递推。先把问题的规模降低,最小就是1了,再逐渐增大,每次规模增加1,直到n为止。用dp[n+1]这么大的数组就够了,而dp[n]表示从第1个硬币到第n个硬币中最多出现k-1个连续正面的情况种数。到这步,可以直接将拿到的k自减一,假设结果为t。那么问题转成求抛第i个硬币时,它和它前面不能超过t个正面。

(5)基于上面第4步的分析。可以看出,在抛第t个之前(包括第t个),最多就出现t个正面,不可能超过抛的次数的。那么dp[0~k]可以一次性初始化为1<<i,也就是有这么多抛法其结果都不会超过t个正面啦。

(6)考虑在抛第k+1个的情况,顶多也就一种不合法,也就是全面都是正面,那么种数就是(1<<k+1)-1。

(7)考虑在抛大于第k+2的情况,不妨设为dp[k+2]=dp[k+1]*2,但是这里面包含了大于t个的情况,只可能出现这样的情况:第k+2个刚好抛到正面,如果其前面与其连续的刚好有t个正面,那么就会造成连续t+1个正面,非法!但是不可能出现多于t+2个连续的可能,如果多于t+2,那么假设当前为正面,其前面必须有t+1个连续,而dp[k+1]中不会记录有非法的情况,所以不考虑。那么出现与第k+2个刚好连起来是t+1个连续的情况会有多少种?(k+2)-t-1这个位置肯定是反面的,不然就会造成连续t+2个了,那么在k+2-t-2及其之前所有不超过t个连续的情况种数就是出现“与k相连t+1个正面”的情况种数,减去这个数量即可。

总之,对于i大于k+2的,dp[i]=dp[i-1]*2-dp[i-t-2]。推到dp[n]时,所有可能都出来了。用所有可能数减去此数:答案= (1<<n)-dp[n]。

 #include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
int n, k;
long long a[];
vector<string> ans;
vector<string> pre; bool comp(string num1,string num2)
{
int leng=num1.length(),i;
for(i=;i<leng;i++){if(num1[i]!='')break;}
num1=num1.substr(i,leng);
if(num1.length()==)num1=""; leng=num2.length();
for(i=;i<leng;i++){if(num2[i]!='')break;}
num2=num2.substr(i,leng);
if(num2.length()==)num2=""; if(num1.length()>num2.length())return true;
else if(num1.length()==num2.length())
{
if(num1>=num2)return true;
else return false;
}
else return false;
}
string _minus(string num1,string num2)
{
string result;
if(comp(num2,num1)){string ss=num1;num1=num2;num2=ss;}
reverse(num1.begin(),num1.end());
reverse(num2.begin(),num2.end()); result=""; int i;
for(i=;i<int(num1.length())&&i<int(num2.length());i++)
{
char c=num1[i]-num2[i]+;
result=result+c;
}
if(i<int(num1.length()))
for(;i<int(num1.length());i++)
result=result+num1[i]; int jiewei=;
for(i=;i<int(result.length());i++)
{
int zhi=result[i]-+jiewei;
if(zhi<) {zhi=zhi+;jiewei=-;}
else jiewei=;
result[i]=(char)(zhi+);
} for(i=result.length()-;i>=;i--)
if(result[i]!='')
break; result=result.substr(,i+);
reverse(result.begin(),result.end());
if(result.length()==)result="";
return result;
}
string sum(string s1,string s2)
{
if(s1.length()<s2.length())
{
string temp=s1;
s1=s2;
s2=temp;
}
int i,j;
for(i=s1.length()-,j=s2.length()-;i>=;i--,j--)
{
s1[i]=char(s1[i]+(j>=?s2[j]-'':)); //注意细节
if(s1[i]-''>=)
{
s1[i]=char((s1[i]-'')%+'');
if(i) s1[i-]++;
else s1=''+s1;
}
}
return s1;
} void cal64()
{
ans[]="";
for(int i=; i<=k; i++)
ans[i]=pre[i];
string tmp= sum(ans[k], ans[k]);
ans[k+]=_minus(tmp,""); for(int i=k+; i<=n; i++)
{
tmp=sum( ans[i-], ans[i-] );
ans[i]=_minus(tmp,ans[i-k-]);
}
cout<<_minus(pre[n], ans[n])<<endl; } void cal63()
{
a[]=;
for(int i=; i<=k; i++) //小于k的情况,直接2^k
a[i]=a[i-]+a[i-]; a[k+]=a[k]+a[k]-;
for(int i=k+; i<=n; i++)
a[i] = a[i-]-a[i-k-]+a[i-]; cout<<((long long)<<n)-a[n]<<endl;
}
void init()
{
string tmp;
ans.resize(,tmp);
pre.resize(,tmp);
pre[]="";
for(int i=; i<; i++)
pre[i]=sum(pre[i-], pre[i-]);
}
int main()
{
//freopen("input.txt","r",stdin);
init();
while(cin>>n>>k)
{ if(n==k)
{
cout<<""<<endl;
continue;
}
if(n==k+)
{
cout<<""<<endl;
continue;
}
if(k==)
{
cout<<_minus(pre[n],"")<<endl;
continue;
}
k--;
if(n<) //这里对抛62次以下的情况用longlong直接干掉。
cal63();
else //大于62就用大数来算
cal64(); }
return ;
}

AC代码

uva 10328 - Coin Toss 投硬币(dp递推,大数)的更多相关文章

  1. UVA 10328 - Coin Toss dp+大数

    题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_proble ...

  2. UVA 10328 Coin Toss

    Coin Toss Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVA. Original ID: ...

  3. UVa 10328 - Coin Toss (递推)

    题意:给你一个硬币,抛掷n次,问出现连续至少k个正面向上的情况有多少种. 原题中问出现连续至少k个H的情况,很难下手.我们可以试着将问题转化一下. 设dp[i][j]表示抛掷i个硬币出现连续至多j个H ...

  4. UVa 10328 Coin Toss(Java大数+递推)

    https://vjudge.net/problem/UVA-10328 题意: 有H和T两个字符,现在要排成n位的字符串,求至少有k个字符连续的方案数. 思路:这道题目和ZOJ3747是差不多的,具 ...

  5. hdu2089(数位DP 递推形式)

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  6. UVA 674 Coin Change 换硬币 经典dp入门题

    题意:有1,5,10,25,50五种硬币,给出一个数字,问又几种凑钱的方式能凑出这个数. 经典的dp题...可以递推也可以记忆化搜索... 我个人比较喜欢记忆化搜索,递推不是很熟练. 记忆化搜索:很白 ...

  7. UVA 10559 Blocks(区间DP&&递推)

    题目大意:给你玩一个一维版的消灭星星,得分是当前消去的区间的长度的平方,求最大得分. 现在分析一下题目 因为得分是长度的平方,不能直接累加,所以在计算得分时需要考虑前一个状态所消去的长度,仅用dp[l ...

  8. 紫书 例题 9-9 UVa 10003 (区间dp+递推顺序)

    区间dp,可以以一个区间为状态,f[i][j]是第i个切点到第j个切点的木棍的最小费用 那么对于当前这一个区间,枚举切点k, 可以得出f[i][j] = min{dp(i, k) + dp(k, j) ...

  9. hdu 2604 Queuing(dp递推)

    昨晚搞的第二道矩阵快速幂,一开始我还想直接套个矩阵上去(原谅哥模板题做多了),后来看清楚题意后觉得有点像之前做的数位dp的水题,于是就用数位dp的方法去分析,推了好一会总算推出它的递推关系式了(还是菜 ...

随机推荐

  1. VR虚拟现实眼镜那些事

    今天是2014.3.20,笔者从oculus官网订了DK2(第二代开发版) 评测视频http://v.youku.com/v_show/id_XNjg3NTUzOTk2.html 想想从哪说起呢... ...

  2. Windows下caffe安装详解(仅CPU)

    本文大多转载自 http://blog.csdn.net/guoyk1990/article/details/52909864,加入部分自己实战心得. 1.环境:windows 7\VS2013 2. ...

  3. Ubuntu&nbsp;12.04&nbsp;Eclipse设…

    Ubuntu 12.04 Eclipse设置(黑色背景解决) 分类: ubuntu2012-11-21 10:47 252人阅读 评论(0) 收藏 举报 eclipseEclipseubuntuUbu ...

  4. 在Spring环境下存取properties文件…

    Spring中PropertyPlaceholderConfigurer的使用 (1) 基本的使用方法是 classpath:/spring/include/dbQuery.properties 其中 ...

  5. day4 函数重载

    函数的重载 1.函数重载的定义:在同一个类中,有一个以上的同名函数,只要函数的参数列表或参数类型不一样即可,与返回值无关, 这些统称为方法的重载. 2.函数的重载存在的原因:为了增强方法的阅读性,优化 ...

  6. JAVA学习笔记——(四)

    今日内容介绍 1.流程控制语句switch 2.数组 3.随机点名器案例 01switch语句解构 * A:switch语句解构 * a:switch只能针对某个表达式的值作出判断,从而决定程序执行哪 ...

  7. 写守护进程时碰到open函数的参数,没记住

    今天写一个最简单的守护进程, 要成为一个守护进程,其实很简单了.主要步骤就4步: 1,创建进程. 2,父进程退出. 3,成为会话的头领进程. 4,将工作目录改成根目录,并把标准输入输出重定向到空设备. ...

  8. python 学习笔记8 (模块)

    Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句. 模块让你能够有逻辑地组织你的 Python 代码段. 把相关的代码 ...

  9. C#中异步及winform中界面假死

    c#中可以用BeginInvoke去启动异步调用,但是有两个BeginInvoke一个是controller的BeginInvoke还有一个是委托的BeginInvoke. 主要区别是controll ...

  10. null, undefined 和布尔值

    说明:此类博客来自以下链接,对原内容做了标注重点知识,此处仅供自己学习参考! 来源:https://wangdoc.com/javascript/basic/introduction.html 1.n ...