题意:抛出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. 浅谈HTML移动Web开发(转)

    一.响应式Web设计 PC端常用的两种布局方式就是固定布局和弹性布局,前者设置一个绝大多数电脑能征服显示的固定宽度居中显示,后者则采用百分百. 响应式布局意味着媒体查询,响应式web设计并非新的技术, ...

  2. petrozavodsk1

    A 转化模型和相当于求解小于n/2的最大的和n互质的数字, 显然可以证明所求和n/2相距 O(logn) ,从 n/2 开始向下枚举然后判定即可. B 上下界网络流? C 从底层开始向上走贪心选下层节 ...

  3. .Net锦囊-C#,.Net发送邮件三种方法…

    最近公司由于一个R&I项目的需要,用户要求在购买产品或出货等一些环节,需要发送邮件提醒或者说每周一让系统自动采集数据发送一封E-mail,因此我也就找来相关资料,写了一个Demo分享给大家,大 ...

  4. 《Java多线程编程核心技术》读后感(二)

    方法内的变量为线程安全 package Second; public class HasSelfPrivateNum { public void addI(String username) { try ...

  5. 自己在项目中写的一个Jquery插件和Jquery tab 功能

    后台查询结果 PDFSearchResult实体类: [DataContract(Name = "PDFSearchResult")] public class PDFSearch ...

  6. Javascript实现页面左边的菜单选中项高亮显示

    在项目开发过程中,遇到一个问题 在一个模板页面中,Layout.cshtml,页面左边放了一个菜单项menu,每一项都是一个链接到一个新的页面.但所有页面都是用这个模板Layout.cshtml.需要 ...

  7. 12. nc/netcat 用法举例

    nc命令用法举例 什么是nc nc是netcat的简写,有着网络界的瑞士军刀美誉.因为它短小精悍.功能实用,被设计为一个简单.可靠的网络工具 nc的作用 (1)实现任意TCP/UDP端口的侦听,nc可 ...

  8. POJ 2348 Euclid's Game (博弈)

    题意:给定两个整数,两个人轮流操作,每次可以用较大数减去较小数的整数倍,当一个数变成0时,则结束,问谁会胜. 析:很明显如果 a == b 那么就可以直接结束了,那么如果 a > b我们可以交换 ...

  9. ASP.NETCORE MVC模块化

    ASP.NETCORE MVC模块化编程 前言 记得上一篇博客中跟大家分享的是基于ASP.NETMVC5,实际也就是基于NETFRAMEWORK平台实现的这么一个轻量级插件式框架.那么今天我主要分享的 ...

  10. unity update优化

    http://forum.china.unity3d.com/thread-13968-1-1.html Unity有个消息系统,它可以在运行中当发生指定事件时调用你在脚本中定义的那些魔术方法.这是个 ...