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表示金矿的数目。

思路:

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

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

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;

}

 

 

 

 

 

你可能感兴趣的:(virtual)