P7039题解
catandcode · · 题解
计算几何+状压,个人感觉是道好题,用最基础的奇偶变换搞人心态。
Provicy 大佬的思路非常清晰,我的对叉积的优化也来自于他,但像我这样的蒟蒻可能看不懂大佬的题解,所以我来写一篇。第一篇题解,如果有不足还请指出,欢迎 hack。
前置
本题需要运用叉积的知识。
首先是
由于题目给出全部坐标均为整点,根据叉积公式
对于输入的整点,可以直接与
这里先说一下我这里说的前缀和处理一般情况的面积的含义。
对于这样一个多边形,首先是计算
对于任意数据,由于只需要考虑奇偶两种情况,可以对叉积的运算式进行优化。
如果原点坐标(单指横坐标或纵坐标,下同)是偶数,所得向量坐标的奇偶性(相对于终点,下同)是没有改变的,若为奇数,向量的奇偶性相反,但由于是对于两个终点都取反,最后影响可以抵消。对于原公式中的加减法,奇偶相加减得奇,偶偶或奇奇相加减得偶,这恰好和异或运算的规则相同,于是公式可以更改为
同时时间复杂度的部分优化也在这里。由于我们可以剔除原点的影响,就没有必要分别计算从不同原点出发的前缀和,可以直接用一个前缀和数组表示。
这边要注意一下,原点是要从 我在这里卡了好久 qaq
特判一下整个图形面积为奇数,这种情况显然无解。
DP
由于只考虑奇偶性,我们可以定义一个三维的数组 是不是很神奇, 具体过程可以参考代码。
为了不重复计数,我们对于对角线的一般计数方式是只考虑
但在实现之后会有一个问题,测试输出与样例输出并不吻合,且刚好相差
手推一下实现过程,可以发现
最终时间复杂度
代码
冷知识:short 类型的空间占用是小于 bool 类型的。
#include<bits/stdc++.h>
#define ld long double
#define ll long long
#define pre(x) x==1?n:x-1
using namespace std;
int aa,bb;
struct point
{
short x,y;
void give(){ x=abs(aa)&1,y=abs(bb)&1; }
short operator ^(point a){ return (x*a.y)^(a.x*y); }
}p[200005];//个人习惯在结构体中初始化和重载,减少码量
int n;
short sum[200005];
ll ans,dp[2][2][2];
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin>>n;
for(int i=1;i<=n;++i)
{
cin>>aa>>bb;
p[i].give();
}
for(int i=1;i<=n;++i) sum[i]=sum[i-1]^(p[i]^p[pre(i)]);
if(sum[n]&1) { cout<<0<<endl; return 0; }
for(int i=1;i<=n;++i)
{
for(int j=0;j<=1;++j)
for(int k=0;k<=1;++k)
{
point e=(point){j,k};
short temp=sum[i]^(p[i]^e);
ans+=dp[temp][j][k];
}
++dp[sum[i]][p[i].x][p[i].y];
}
cout<<ans-n<<endl;
return 0;
}