链接
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3514
题解
把所有的边看作直线做半平面相交得到的就是多边形内核
这题的意思就是你构造的那个多边形必须内核不为空
首先
R
R
肯定比多四个,这无可厚非,因为最终方向一定是转了
360∘
360
∘
那么
R
R
就有个,
O
O
就有个
N
N
肯定是不小于的偶数,否则无解
考虑什么时候这个序列不合法:
如果有连续的
O
O
就不行,因为这样就会出现两个没有交集的半平面,也就不存在内核了,所以一定不连续
那么肯定会存在连续的
R
R
,考虑两个连续的时候,答案是合法的;连续三个
R
R
连续的时候,依然可以构造出合法图形;连续四个连续的时候,这样构造:
连续
5
5
个的时候,这样构造
所以最后就是要你把
n2−2
n
2
−
2
个
R
R
和个
O
O
排起来,使得任意两个不相邻
处理1
《算法竞赛入门经典训练指南》中给出了一个
DP
D
P
f(i,j,0/1,0/1)
f
(
i
,
j
,
0
/
1
,
0
/
1
)
表示使用
i
i
个和
j
j
个组成合法序列的个数,状态转移方程在下方程序里有,基本思路就是每次在结尾加入一个
0
0
或,分类讨论。
处理2
其实可以这样,先把
n2−2
n
2
−
2
个
0
0
排成一排,然后把插空放进去,推出来公式是:
代码1
//奇妙数学+dp
#include <bits/stdc++.h>
#define ll long long
#define maxn 1010
using namespace std;
ll N, f[maxn][maxn][2][2];
void init()
{
ll i, j;
f[1][0][0][0]=f[0][1][1][1]=1;
for(i=0;i<maxn;i++)for(j=0;j<maxn;j++)
{
if(i+j<=1)continue;
if(i)f[i][j][0][0]=f[i-1][j][0][1], f[i][j][1][0]=f[i-1][j][1][1];
if(j)f[i][j][0][1]=f[i][j-1][0][0]+f[i][j-1][0][1], f[i][j][1][1]=f[i][j-1][1][0]+f[i][j-1][1][1];
}
}
int main()
{
ll N, kase=0, a, b, ans;
init();
while(scanf("%lld",&N),N)
{
if(N<4 or N&1)ans=0;
else a=N/2-2, b=N/2+2, ans=f[a][b][0][1]+f[a][b][1][0]+f[a][b][1][1];
printf("Case %lld: %lld\n", ++kase, ans);
}
return 0;
}
代码2
//数学题
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll N;
int main()
{
ll N, kase=0, a, b, ans, n;
while(scanf("%lld",&N),N)
{
if(N<4 or N&1)ans=0;
else n=N/2+1, ans=n*(n-1)*(n-2)*(n-3)/12+n*(n-1)*(n-2)/6;
printf("Case %lld: %lld\n",++kase,ans);
}
return 0;
}