您的位置:首页 > 编程语言 > Go语言

Farey Polygon

2015-08-02 19:02 561 查看

题目描述:

先给出一个法雷序列:在法雷序列之前加上0/0;

F1 = {0⁄0, 0⁄1, 1⁄1}

F2 = {0⁄0, 0⁄1, 1⁄2, 1⁄1}

F3 = {0⁄0, 0⁄1, 1⁄3, 1⁄2, 2⁄3, 1⁄1}

F4 = {0⁄0, 0⁄1, 1⁄4, 1⁄3, 1⁄2, 2⁄3, 3⁄4, 1⁄1}

F5 = {0⁄0, 0⁄1, 1⁄5, 1⁄4, 1⁄3, 2⁄5, 1⁄2, 3⁄5, 2⁄3, 3⁄4, 4⁄5, 1⁄1}

F6 = {0⁄0, 0⁄1, 1⁄6, 1⁄5, 1⁄4, 1⁄3, 2⁄5, 1⁄2, 3⁄5, 2⁄3, 3⁄4, 4⁄5, 5⁄6, 1⁄1}

F7 = {0⁄0, 0⁄1, 1⁄7, 1⁄6, 1⁄5, 1⁄4, 2⁄7, 1⁄3, 2⁄5, 3⁄7, 1⁄2, 4⁄7, 3⁄5, 2⁄3, 5⁄7, 3⁄4, 4⁄5, 5⁄6, 6⁄7, 1⁄1}

F8 = {0⁄0, 0⁄1, 1⁄8, 1⁄7, 1⁄6, 1⁄5, 1⁄4, 2⁄7, 1⁄3, 3⁄8, 2⁄5, 3⁄7, 1⁄2, 4⁄7, 3⁄5, 5⁄8, 2⁄3, 5⁄7, 3⁄4, 4⁄5, 5⁄6, 6⁄7, 7⁄8, 1⁄1}

然后将这些序列按照顺序映射到二维的坐标上.

分子是y,分母是x.按照顺序将他们连在一起,最后一个连第一个点.

然后这个图形里面就严格包含了一些点.

有一个倍率放大是m.就是把每一个点都放大.

现在给出严格包含了多少个点,要求给出满足的(n,m).n尽量小,n一样的话m尽量小.

12000组数据,要求n和m都<=15000,还没找到的话就是-1.

具体题意:http://acm.bnu.edu.cn/v3/problem_show.php?pid=20856

题解:

首先格子内部的点是有一个定理:在二维的方格中,围成的面积S = I(内部) + (V(边上)/2) - 1; 我们知道的是I(内部).

其次观察面积和边上点的性质.既然给出的是一个奇怪的序列.这个序列我们第一反应是可以用phi前缀和求出它的个数.那么我们猜想S和V是否只和点的个数有关.发现还真是:V = m*(点个数), S = (点个数-2)/2;

知道了这些,我们写出公式,发现m有二次方,那么我们暴力枚举m,然后可以得到需要的phi,这一点非常重要,因为得到phi中有一个需要整除的过程,能够特别快的加速计算.然后二分查找phi.

重点:

(1)知道算内部的公式.

(2)利用phi好求个数来猜想

(3)求phi是利用整除.

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(ll i = a;i < b;i++)
#define REP_D(i, a, b) for(ll i = a;i <= b;i++)

typedef long long ll;

using namespace std;

const ll maxn = 15001 + 10;
const ll key = 15000;
ll phi[maxn];
ll p[maxn], pn, vis[maxn];
void getPhi()
{
CLR(vis);
phi[1] = 1;
pn = 0;
for(ll i = 2; i<=key; i++)
{
if(!vis[i])
{
phi[i] = i-1;
p[pn] = i;
pn++;
}
for(ll j = 0; (j<pn&&i*p[j]<=key); j++)
{
if(i%p[j])
{
phi[i*p[j]] = phi[i]*(p[j]-1);
vis[i*p[j]] = 1;
}
else
{
phi[i*p[j]] = phi[i]*(p[j]);
vis[i*p[j]] = 1;
}
}
}
for(int i = 2; i<=key; i++)
{
phi[i] += phi[i-1];
}
}
ll n, m;
ll ans;
void solve()
{
for(m = key; m>=2; m--)
{
ll X = (2*ans+2*m-2);
ll Y = (m*m-m);
if(X%Y==0)//这一点是关键.不然要T
{
X /= Y;
ll pos = lower_bound(phi + 1, phi + 1+key, X) - phi;
if(pos != (key + 1) && phi[pos] == X)
{
printf("%lld %lld\n", pos, m);
return;
}
}
}
printf("NOT FOUND\n");
}

int main()
{
// freopen("13Min.txt", "r", stdin);
//freopen("1out.txt", "w", stdout);
getPhi();
while(scanf("%lld", &ans))
{
if(ans==-1)
{
break;
}
if(ans == 0)
{
printf("1 1\n");
}
else
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: