[POI2007][对称轴osi][计算几何 + KMP]

/*
题目:对称轴osi
题目来源:POI2007
http://www.zybbs.org/JudgeOnline/problem.php?id=1100
题目内容或思路: 思路参考自:http://hi.baidu.com/nplusnplusnplu/blog/item/d260baef2e9e9c5879f055cb.html
給定一個不自交的多邊形判斷對稱軸有幾條。多邊形邊=100000。

將多邊形的角和邊字符化,假設存儲于字符串S,SS表示兩個S拼接而成的字符串,
S'表示S翻轉後的串,成那麼原文題等價于:求在字符串SS(去掉末尾字符)中S'出現
的次數。KMP、Sunday、BM什麽的都可以。
做题日期:2011.8.4
*/
#include
<iostream>
#include
<cstdio>
#include
<string>
#include
<cstring>
#include
<map>
#include
<set>
#include
<queue>
#include
<cmath>
#include
<algorithm>
using namespace std;

#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define ford(i, n) for (int i = (int)(n) - 1; i >= 0; --i)
#define clr(a, b) memset(a, b, sizeof(a))
#define SZ(a) ((int)a.size())
#define PB push_back
#define MP make_pair
#define inf 0x3f3f3f3f
typedef pair
<int, int> pii;
typedef vector
<int> vi;
typedef
long long ll;

#define sqr(x) ((x)*(x))
const int N = 100010;
int tot, n, fail[N * 2];
ll mch[N
* 4], pat[N * 2];

struct cpoint { int x, y; }p[N];

void makefail(ll *t, int lt) {
t
--;
for (int i = 1, j = 0; i <= lt + 1; ++i, ++j) {
fail[i]
= j;
while (j > 0 && t[i] != t[j]) j = fail[j];
}
}

int kmp(ll *s, int ls, ll *t, int lt) {
--s, --t; int cnt = 0;
for (int i = 1, j = 1; i <= ls; ++i, ++j) {
while (j > 0 && s[i] != t[j]) j = fail[j];
if (j == lt) {
cnt
++;
j
= fail[lt + 1] - 1;
}
}
return cnt;
}

ll dissqr(cpoint u, cpoint v) {
return sqr((ll)u.x - v.x) + sqr((ll)u.y - v.y);
}

ll cross(cpoint p0, cpoint p1, cpoint p2) {
return (ll)(p1.x - p0.x) * (p2.y - p0.y) -
(ll)(p2.x
- p0.x) * (p1.y - p0.y);
}

void solve() {
scanf(
"%d", &n);
forn (i, n) scanf(
"%d%d", &p[i].x, &p[i].y);
tot
= 0; p[n] = p[0]; p[n + 1] = p[1];
forn (i, n) {
pat[tot
++] = dissqr(p[i], p[i + 1]) | 1LL << 62;
pat[tot
++] = cross(p[i + 1], p[i], p[i + 2]);
}
memcpy(mch, pat, tot
* sizeof(pat[0]));
memcpy(mch
+ tot, pat, tot * sizeof(pat[0]));
reverse(pat, pat
+ tot);
// forn (i, tot + tot) printf("%lld ", mch[i]); puts("");
// forn (i, tot) printf("%lld ", pat[i]); puts("");
makefail(pat, tot);
int ans = kmp(mch, tot * 2 - 1, pat, tot);
printf(
"%d\n", ans);
}

int main() {
#ifdef CHEN_PC
freopen(
"in", "r", stdin);
#endif
int cas;
scanf(
"%d", &cas);
while (cas--) {
solve();
}
return 0;
}
 
   
 
   
 
  

  

你可能感兴趣的:(2007)