// uva live 4123 Glenbow Museum 数学递推 // // 题目大意: // // 对于一个边平行于坐标轴的多边形,我们可以用一个序列来描述,R和O,R表示 // 该顶点的角度为90度,O表示该定点的角度为270.给定序列的长度.问能由这些RO序 // 列组成的星型多边形(内部存在一个点可以看到所有的节点的多边形)的方法数有多少. // // 解题思路: // // 顶点数一定是序列的长度.n小于4无法组成多边形.n为奇数的时候也不行.设R的个数有 // x个,O的个数有y个.则90 * x + 270 * y = 180 * (n-2).解得 x = (n + 4) / 2; // y = (n - 4) / 2;这样n必为偶数,否则x,y就不是整数了.好的,这样,就可以看到一丝的曙光 // 啦. // // 方法一 // // 令f(i,j,k,l)表示i个R,j个O,以R(k==0)或O(k==1)开头,以R(l==0)或O(l==1)结尾的合法方案数 // 则递推方程为 // f(i,j,k,0) = f(i-1,j,k,1) + f(i-1,j,k,0);(可在...R后加R,可在....O后加R); // f(i,j,k,1) = f(i-1,j,k,0); // // 边界为f(i,0,0,0) = f(0,1,1,1) = 1; // 最后f(R,O,0,0) + (R,O,1,0) + f(R,O,0,1)就是最后的答案(R,O表示R和O的个数) // // 方法二 // // 令f(i,j,k)表示有i个R,j对R相邻,以R(k==0)或O(k==1)开头的合法方案数,对于j>5的情况 // 对于答案是没有贡献的.因为我们知道有4对相邻的R就一定可以组成星型多边形. // 递推方程为: // f(i,j,k) = f(i-1,j,k) + f(i-1,j-1,k)(首先都是从k开头递推的,这个可以肯定之后,我们 // 可以在现有的...R后有两种选择,一种+OR 对应的是第一项,另一种+R对应的是第二项) // 边界条件:f(1,0,0) = f(1,0,1) = 1第一个表示R,第二个表示OR. // // 方法三: // // 组合数学.R的个数有x = (n+4)/2; O的个数有y = (n-4)/2.则问题转化为在x中插入y使得没有两个 // O相邻.捆绑法,令R在O的左边: // 1.序列以R开头,这样就是在x中选择y个O与R结成一对.一共C(x,y) = C(x,x-y) = C(x,4) // 2.序列以O开头,R结尾,这样就是在x-1中选择y-1个O与R组成一队.一共C(x-1,y-1) = C(x-1,4) // 最后结果为两项之和。 // // 感悟: // // 这道题差不多是在6月份的时候通读训练指南基础篇的时候,看到的这题。当时的自己真的很菜啊。 // 连R和O的个数都要推半天。自己的几何方面实在是太弱了。现在看,虽然能理解。但是不是能立马就能 // 写下状态和转移方程的。自己的递推能力实在太菜了。而且,边界的处理也是有些模糊。可以说是差极了 // 比如在方法一中。我只想到了f(1,0,0,0) = f(0,1,1,1)的状态.却忽视了f(i,0,0,0)=1,其中也是有些转移 // 必须要的.结果自己纠结了半天,还是看到的大牛的题解才恍然大悟.而在看到方法三的时候,顿时不禁眼前一亮 // 这种方法真的太奇妙了.这就是组合数学的奇妙之处.认真体会,发现真的其妙无穷.虽然自己不会写这题,但是 // 看到各位前辈的方案,顿时眼前的思路开阔了一些.一些体会无法用语言形容.继续加油,继续徜徉在这神奇的 // 问题之旅,加油~~~FIGHTING! #include <cstdio> #include <algorithm> #include <iostream> #include <cstring> using namespace std; typedef long long ll; ll d[1008][1008][2][2]; void init(){ memset(d,0,sizeof(d)); d[1][0][0][0] = 1; d[0][1][1][1] = 1; for (int i=1;i<=1000;i++) d[i][0][0][0] = 1; for (int k=0;k<2;k++){ for (int i=1;i<=1000;i++) for(int j=1;j<=1000;j++){ d[i][j][k][0] = d[i-1][j][k][0] + d[i-1][j][k][1]; d[i][j][k][1] = d[i][j-1][k][0]; } } } int main(){ init(); int n; freopen("1.txt","r",stdin); ios::sync_with_stdio(false); int kase = 1; while(cin>>n){ if (!n) break; cout << "Case " << kase++ << ": "; if (n<4 || (n&1)){ cout << 0 << endl; continue; } int a = (n+4)/2; int b = (n-4)/2; ll ans = d[a][b][0][0] + d[a][b][0][1]+d[a][b][1][0]; cout<< ans << endl; } return 0; } #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; typedef long long ll; ll d[1008][8][2]; void init(){ memset(d,0,sizeof(d)); d[1][0][0] = 1; d[1][0][1] = 1; for (int k=0;k<2;k++) for (int i=2;i<=1000;i++) for (int j=0;j<5;j++){ d[i][j][k] = d[i-1][j][k]; if (j>0) d[i][j][k] += d[i-1][j-1][k]; } } int main(){ init(); ios::sync_with_stdio(false); int n; int kase = 1; while(cin>>n){ if (!n) break; cout << "Case " << kase++ << ": "; if (n < 4 || (n&1)){ cout << 0 << endl; continue; } int a = (n+4)>>1; ll res = d[a][4][0] + d[a][4][1] + d[a][3][1]; cout << res << endl; } } #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; int main(){ ll n; ios::sync_with_stdio(false); int kase = 1; while(cin>>n){ if (!n) break; cout << "Case " << kase++ << ": "; if (n<4 || (n & 1)){ cout << 0 << endl; continue; } ll r = (n+4)/2; ll ans1 = r * (r-1) * (r-2) * (r-3) / 24; r--; ll ans2 = r * (r-1) * (r-2) * (r-3) / 24; cout << ans1 + ans2 << endl; } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-29 19:12:09