hdu 4380 Farmer Greedy && hdu 4353 Finding Mine && 4367 The war of virtual world (确定三角形内的点个数题目)

http://acm.hdu.edu.cn/showproblem.php?pid=4380

http://acm.hdu.edu.cn/showproblem.php?pid=4353

http://acm.hdu.edu.cn/showproblem.php?pid=4367

昨天第9场比赛的第一题类型据说已经出成屎了,如果不是数据出错了,做就会被轮奸的。于是就坐了坐类似的题目。

这里有一个同一的前提,不存在三点共线;

首先给出这类题目的解法AC大神:http://hi.baidu.com/aekdycoin/item/3f151dafcfcfb9ac29ce9ddc

还有一个帮助理解s[i][j]的意思:http://www.mzry1992.com/blog/miao/2012-multi-university-training-contest-7.html

4380:

题意:

给定N个房子的坐标以及M个金石头的坐标,Farmer Greedy只能选择三个房子然后形成一个三角形,三角形内会包含金石头。Farmer Greedy比较喜欢奇数,问题:求形成的三角形中包含奇数个金石头的个数;

思路:

不同的暴力方法O(N^3*M)肯定会超时,所以要优化,上边AC大神给的解法已经说了优化方法,用O(n^2 + nlogn)的复杂度初始化,O(n^3)求解:

这里s[i][j]不是表示i->j“右边”的点的数量,而是上边给的那个连接的意思。getS( i,k,j)表示求i,j,k这个角度里面的点的数量。

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))

#define N 107
#define M 1007
#define ll __int64
#define inf 0x7f7f7f7f
#define MOD 100000007
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<-----***------->")
using namespace std;

struct node
{
    double x,y;
}Nve[N],Mve[M];
int Right[N][N],s[N][N];
double save[N][N],angle[M];
int n,m;
//寻找第一个大于等于val的坐标
int bsearch(double val)
{
    int l = 0,r = m - 1;
    int mid = 0,ans = -1;
    while (l <= r)
    {
        mid = (l + r)/2;
        if (angle[mid] > val) r = mid - 1;
        else
        {
            l = mid + 1;
            ans = mid;
        }
    }
    return ans;
}
void init()
{
    int i,j;
    int pos1,pos2;
    //求出任意两点的角度(-pi,pi]
    for (i = 0; i < n; ++i)
    {
        for (j = 0; j < n; ++j)
        {
            if (i == j) continue;
            save[i][j] = atan2((Nve[j].y - Nve[i].y), (Nve[j].x - Nve[i].x));
        }
    }

    for (i = 0; i < n; ++i)
    {
        for (j = 0; j < m; ++j)//枚举i点以i点为中心按极角对m个点排序
        {
            angle[j] = atan2((Mve[j].y - Nve[i].y), (Mve[j].x - Nve[i].x));
        }
        sort(angle,angle + m);
        for (j = 0; j < n; ++j)
        {
            if (i == j) continue;
            double ang = save[i][j];
            pos1 = bsearch(ang);//寻找i->j右边的第一个点也表示1-pos1的个数
            s[i][j] = pos1;
            if (ang >= 0)
            {
                ang -= pi;
                pos2 = bsearch(ang);
                Right[i][j] = pos1 - pos2;
            }
            else
            {
                ang += pi;
                pos2 = bsearch(ang);
                Right[i][j] = m - (pos2 - pos1);
            }
        }
    }
}
int getS(int i,int k,int j)//求i,k,j这个角里面的点的个数
{
    int ang1 = save[k][i];
    int ang2 = save[k][j];
    if (ang1 > ang2)
    {
        if (ang1 - ang2 < pi) return (s[k][i] - s[k][j]);
        else  return (m - (s[k][i] - s[k][j]));
    }
    else
    {
        if (ang2 - ang1 < pi) return s[k][j] - s[k][i];
        else return (m - (s[k][j] - s[k][i]));
    }
}
int main()
{
    //freopen("din.txt","r",stdin);
    int i,j,h;
    int cas = 1;
   while (~scanf("%d%d",&n,&m))
   {
       for (i = 0; i < n; ++i) scanf("%lf%lf",&Nve[i].x,&Nve[i].y);

       for (i = 0; i < m; ++i) scanf("%lf%lf",&Mve[i].x,&Mve[i].y);

       init();

       int ans = 0;
       for (i = 0; i < n; ++i)
       {
           for (j = i + 1; j < n; ++j)
           {
               for (h = j + 1; h < n; ++h)
               {
                   int tmp = getS(i,j,h) + getS(j,h,i) + getS(h,i,j) + Right[i][j] + Right[j][h] + Right[h][i] - 2*m;
                   //printf(">>%d\n",tmp);
                   if (tmp&1) ans++;
               }
           }
       }
       printf("Case %d: %d\n",cas++,ans);
   }
    return 0;
}

 

4353:

题意:给定n个点的坐标以及m个金矿的坐标,求在n个点里面选出若干点组成一个多边形是其A/B最小。A表示多边形的面积,B表示金矿的数目。

思路:

所以如上题,我们只枚举出三角形内点个数,然后除他的面积取最小即可,代码几乎一样。

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define maxn 50004
#define N 207
#define M 507
#define ll __int64
#define inf 0x7f7f7f7f
#define MOD 100000007
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
using namespace std;

struct node
{
    double x,y;
}Nve[N],Mve[M];
int s[N][N],R[N][N];
double angle[M],save[N][N];
int n,m;

double det(double x1,double y1,double x2,double y2)
{
    return x1*y2 - x2*y1;
}
double cross(node a,node b,node c)
{
    return det(b.x - a.x,b.y - a.y,c.x - a.x,c.y - a.y);
}
double getsum(double x1,double y1,double x2,double y2,double x3,double y3)
{
    return iabs((x1*y2 - x2*y1 + x3*y1 - x1*y3 + x2*y3 - x3*y2))/2.0;
}
int bsearch(double ang)
{
    int l = 1,r = m;
    int mid = 0,ans =0;
    while (l <= r)
    {
        mid = (l + r)>>1;
        if (ang < angle[mid])
        r = mid - 1;
        else
        {
            l = mid + 1;
            ans = mid;
        }
    }
    return ans;
}
void init()
{
    int i,j,pos1,pos2;
    for (i = 1; i <= n; ++i)
    {
        for (j = 1; j <= n; ++j)
        {
            if (i == j) continue;
            save[i][j] = atan2((Nve[j].y - Nve[i].y),(Nve[j].x - Nve[i].x));
        }
    }
    for (i = 1; i <= n; ++i)
    {
        for (j = 1; j <= m; ++j)
        {
            angle[j] = atan2((Mve[j].y - Nve[i].y),(Mve[j].x - Nve[i].x));
        }
        sort(angle + 1,angle + 1 + m);
        for (j = 1; j <= n; ++j)
        {
            if (i == j) continue;
            double ang = save[i][j];
            pos1 = bsearch(ang);
            s[i][j] = pos1;
            if (ang > 0)
            {
                 ang -= pi;
                 pos2 = bsearch(ang);
                 R[i][j] = pos1 - pos2;
            }
            else
            {
                ang += pi;
                pos2 = bsearch(ang);
                R[i][j] = m - (pos2 - pos1);
            }
        }
    }
}
int getS(int i,int k,int j)
{
    double ang1 = save[k][i];
    double ang2 = save[k][j];
    if (ang1 > ang2)
    {
        if (ang1 - ang2 < pi) return s[k][i] - s[k][j];
        else return (m - (s[k][i] - s[k][j]));
    }
    else
    {
        if (ang2 - ang1 < pi) return s[k][j] - s[k][i];
        else return (m - (s[k][j] - s[k][i]));
    }
}
int main()
{
   // freopen("din.txt","r",stdin);

   int t,cas = 1;
   int i,j,h;
   scanf("%d",&t);
   while (t--)
   {
       scanf("%d%d",&n,&m);
       for (i = 1; i <= n; ++i) scanf("%lf%lf",&Nve[i].x,&Nve[i].y);

       for (i = 1; i <= m; ++i) scanf("%lf%lf",&Mve[i].x,&Mve[i].y);

       init();
       double ans = inf;
       for (i = 1; i <= n; ++i)
       {
           for (j = i + 1; j <= n; ++j)
           {
               for (h = j + 1; h <= n; ++h)
               {
                   int B = 0;
                   double are = cross(Nve[i],Nve[j],Nve[h]);
                   int tmp = getS(i,h,j) + getS(h,j,i) + getS(j,i,h);
                   if (are > 0)//正负不一样注意
                   B = tmp + R[i][j] + R[j][h] + R[h][i] - 2*m;
                   else
                   B = tmp + R[j][i] + R[h][j] + R[i][h] - 2*m;

                   if (B != 0)
                   {
                       double A =  getsum(Nve[i].x,Nve[i].y,Nve[j].x,Nve[j].y,Nve[h].x,Nve[h].y);
                       // printf("%lf %d\n",A,B);
                       ans = Min(ans,A/B);
                   }
               }
           }
       }
       printf("Case #%d: ",cas++);
       if (ans == inf) printf("-1\n");
       else printf("%.6lf\n",ans);
   }
    return 0;
}

 

4367 :

题意:

给定n个点,然后AC首先去2个点组成线段ac,然后yayamao再在剩余的点里面取两个点,AC有n*(n-1)/2中可能,ki表示在i状态下yayamao取的两个点与i状态的线段相交可能数,求

注意这里是乘法。fib是斐波那契数列

思路:

这里:http://www.mzry1992.com/blog/miao/2012-multi-university-training-contest-7.html有详细的解题思路,就是和上边几乎一样,不过这里要用到了欧拉函数降幂。

这里多谢日化的讲解:

A^x = A^(x % Phi(C) + Phi(C)) (mod C) 这是最原始公式。。

A^x = (A^(x % Phi(C)) % C) * (A^Phi(C) % C) 这个就是把上面的式子的指数给拆开

当C为素数的时候 Phi(C) = C - 1, 所以 (A^Phi(C) % C) = 1, 费马小定理
所以当C为素数的时候A^x = A^(x % Phi(C)) % C

A^x = A^( x % (C - 1) ) % C

这里就把fib降了。。

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<---------------------->")
#define ll __int64
#define inf 0x7f7f7f7f
#define MOD  1000000007
#define maxn 40004
#define N 207
#define M 507
using namespace std;


int n;
struct node
{
    double x,y;
}p[N];

double save[N][N],angle[N];
int s[N][N],R[N][N],ct;

ll f[N*N];

void initF()
{
    f[0] = f[1] = 1;
    for (int i = 2; i <= 40000; ++i)
    f[i] = (f[i - 1] + f[i - 2])%(MOD - 1) + (MOD - 1);//降幂后的写法
}
ll modexp(ll a,ll b)
{
    ll res = 1;
    while (b)
    {
        if (b&1) res = res*a%MOD;
        a = a*a%MOD;
        b >>= 1;
    }
    return res;
}
double det(double x1,double y1,double x2,double y2)
{
    return x1*y2 - x2*y1;
}
double cross(node a,node b,node c)
{
    return det(b.x - a.x,b.y - a.y,c.x - a.x,c.y - a.y);
}
int bsearch(double val)
{
    int l = 1;
    int r = ct;
    int ans = 0;
    while (l <= r)
    {
        int m = (l + r)>>1;
        if (val >= angle[m])
        {
            l = m + 1;
            ans = m;
        }
        else r = m - 1;
    }
    return ans;
}
void init()
{
    int i,j;
    int pos1,pos2;
    for (i = 1; i <= n; ++i)
    {
        for (j = 1; j <= n; ++j)
        {
            if (i == j) continue;
            save[i][j] = atan2((p[j].y - p[i].y),(p[j].x - p[i].x));
        }
    }

    for (i = 1; i <= n; ++i)
    {
        ct = 0;
        for (j = 1; j <= n; ++j)
        {
            if (i == j) continue;
            angle[++ct] = atan2((p[j].y - p[i].y),(p[j].x - p[i].x));
        }
        sort(angle + 1,angle + 1 + ct);
        for (j = 1; j <= n; ++j)
        {
             if (i == j) continue;
             double ang = save[i][j];
             pos1 = bsearch(ang) - 1;
             s[i][j] = pos1;
             if (ang >= 0)
             {
                 ang -= pi;
                 pos2 = bsearch(ang);
                 R[i][j] = pos1 - pos2;
             }
             else
             {
                 ang += pi;
                 pos2 = bsearch(ang);
                 R[i][j] = n - 1 - (pos2 - pos1);
             }
            // printf(">>%d\n",R[i][j]);
        }
    }
}
int getS(int i,int k,int j)
{
    double ang1 = save[k][i];
    double ang2 = save[k][j];
    if (ang1 > ang2)
    {
        if (ang1 - ang2 < pi) return (s[k][i] - s[k][j] - 1);
        else return (n - 3 - (s[k][i] - s[k][j] - 1));
    }
    else
    {
        if (ang2 - ang1 < pi) return (s[k][j] - s[k][i] - 1);
        else return (n - 3 - (s[k][j] - s[k][i] - 1));
    }
}

int main()
{
    //freopen("din.txt","r",stdin);
    initF();
    int i,j,h;
    while (~scanf("%d",&n))
    {
        for (i = 1; i <= n; ++i) scanf("%lf%lf",&p[i].x,&p[i].y);

        init();
       
        ll sum = 1;
        for (i = 1; i <= n; ++i)
        {
            for (j = i + 1; j <= n; ++j)
            {
                int ans = 0;
                for (h = 1; h <= n; ++h)
                {
                    if (h == i || h == j) continue;
                    double are = cross(p[i],p[j],p[h]);
                    if (are < 0) continue;//以一个方向为据准
                    int tmp = getS(i,j,h) + getS(j,h,i) + getS(h,i,j) + R[i][j] + R[j][h] + R[h][i] - 2*(n - 3);//求三角形面积
                    ans += (getS(i,h,j) - tmp);//i,h,j角度里的面积减去三角形面积
                    if (ans >= MOD) ans %= MOD;
                }

                sum *= (modexp(ans,f[ans])+ 1);
                if (sum >= MOD) sum %= MOD;
            }
        }
        printf("%I64d\n",sum);
    }
    return 0;
}

 

 

 

 

 

posted @ 2012-08-22 19:37  E_star  阅读(337)  评论(0编辑  收藏  举报