UVaOJ 10328 Coin Toss

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1269

题意:一共n张牌,求至少连续k张牌是正面的排列情况有多少种(1<=k<=n<=100)

思路:将至少转换为至多,所有排列情况减去至多连续k-1张牌是正面的排列情况,就可以得到至少k张连续正面的情况了

   所有排列情况好求,就是2^n,要注意到n最多为100,超过了long long的范围,可以用两个long long需要模拟一下

   至多有x张牌是正面的情况,用s[0][i]表示第i张是反面的时候,至多x张牌连续正面的情况有多少个

                 用s[1][i]表示第i张是正面的时候,至多x张牌连续正面的情况有多少个

  对于反面 s[0][i]=s[0][i-1]+s[1][i-1]   反面与限制条件无关,直接就等于之前的所有情况之和;

  对于正面 如果i<=x  s[1][i]=s[1][i-1]+s[0][i-1]    这时肯定不会出现连续的正面超过i的情况,所有也可以直接等于之前的所有情况之和;

       如果i>x  s[1][i]=s[1][i-1]+s[0][i-1]-s[0][i-k-1]    i>x的时候,第i张如果要放正面,就需要排除之前从i-1到i-k连续k张是正面的那些排列,所有需要排除的情况都在s[0][i-k-1],因为从i-1到i-k的k张连续正面一定是从一个反面(i-k的前一个i-k-1一定是反面)开始的

 1 #include<iostream>
 2 #include<string.h>
 3 #include<stdio.h>
 4 #define ll long long
 5 #define Flag 1000000000000000//大于等于的时候进位
 6 using namespace std;
 7 struct Num//用两个longlong模拟,重载了加减方便计算
 8 {
 9     ll H,L;
10     Num()
11     {
12         H=L=0;
13     }
14     void quan(int n)//求2^n,n张牌所有的排列情况
15     {
16         this->H=0;
17         this->L=1;
18         while(n--)
19         {
20             this->L<<=1;
21             this->H<<=1;
22             if(this->L>Flag)this->L-=Flag,this->H++;
23         }
24     }
25     Num operator +(const Num& b)const
26     {
27         Num tem;
28         tem.L = this->L + b.L;
29         tem.H = this->H + b.H;
30         if(tem.L>=Flag)
31         {
32             tem.H++;
33             tem.L-=Flag;
34         }
35         return tem;
36     }
37     Num operator -(const Num& b)const
38     {
39         Num tem;
40         if(this->L<b.L)
41         {
42             tem.L = this->L + Flag -b.L;
43             tem.H = this->H - b.H - 1;
44         }
45         else
46         {
47             tem.L = this->L - b.L;
48             tem.H = this->H - b.H;
49         }
50         return tem;
51     }
52     void display()//输出
53     {
54         if(this->H)
55         {
56             printf("%lld%015lld\n",this->H,this->L);
57         }
58         else
59         {
60             printf("%lld\n",this->L);
61         }
62     }
63 };
64 Num s[2][101];
65 
66 Num que(int n,int k)//求n张牌,最多k个连续正面的情况
67 {
68     s[0][0].L=1;
69     int i=1;
70     while(i<=n)
71     {
72         s[0][i]=s[0][i-1]+s[1][i-1];
73         if(i<=k)
74         {
75             s[1][i]=s[0][i-1]+s[1][i-1];
76         }
77         if(i>k)
78         {
79             s[1][i]=s[0][i-1]+s[1][i-1]-s[0][i-k-1];
80         }
81         i++;
82     }
83     return s[0][i-1]+s[1][i-1];
84 }
85 
86 int main()
87 {
88     int n,k;
89     while(cin >> n >> k)
90     {
91         Num q;
92         q.quan(n);
93         q=q-que(n,k-1);//相减得出至少k个正面的情况
94         q.display();
95     }
96     return 0;
97 }

猜你喜欢

转载自www.cnblogs.com/icfir/p/9084980.html
今日推荐