zoukankan      html  css  js  c++  java
  • CCPC-Wannafly Winter Camp Day5 (Div2, onsite)

    Special Judge

    题目描述

     

    有一个nn个点mm条边的图画在了平面上,你想知道有多少对边之间对应的线段相交。

    特别地,对于图中的一对边,如果有公共点且只在对应的端点相交,那么我们不认为这对边相交。

     
     

    输入描述

     

    第一行两个整数n, m(1leq nleq 1000, 1leq mleq 2000)n,m(1n1000,1m2000),表示点数和边数。

    接下来mm行,每行两个整数(u,v)(u,v)表示一条uu与vv之间的无向边,保证图中没有重边和自环。

    接下来nn行,每行两个整数x_i, y_i (0leq x_i, y_ileq 10^9)xi,yi(0xi,yi109)表示图中第ii个顶点的坐标,保证所有的坐标两两不同。

    输出描述

     

    输出一个整数,表示答案。

    样例输入 1 

    4 6
    1 2
    1 3
    1 4
    2 3
    2 4
    3 4
    0 0
    0 1
    1 1
    1 0
    

    样例输出 1

    1

    计算几何,先判是在同一边,再判不严格相交,注意叉积相乘会爆long long
    #include <bits/stdc++.h>
    #define maxn 1005
    #define db double
    using namespace std;
    int n,m;
    const db EPS=1e-9;
    bool Mp[maxn][maxn];
    vector<pair<int,int>> f;
    typedef long long ll;
    struct P
    {
        ll x,y;
        int id;
        P(){}
        P(ll _x,ll _y):x(_x),y(_y) {}
        P operator +(P p)
        {
            return {x+p.x,y+p.y};
        }
        P operator -(P p)
        {
            return {x-p.x,y-p.y};
        }
        P operator *(ll d)
        {
            return {x*d,y*d};
        }
        P operator /(ll d)
        {
            return {x/d,y/d};
        }
        ll dot(P p)
        {
            return x*p.x+y*p.y;
        }
        ll det(P p)
        {
            return x*p.y-y*p.x;
        }
    }pos[maxn];
    ll cross(P p1,P p2,P p3)
    {
        return ((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y));
    }
    ll sign(ll x,ll y)
    {
        if(x<0&&y>0) return -1;
        else if(x>0&&y<0) return -1;
        else if(x==0||y==0) return 0;
        return 1;
    }
    bool intersect(ll l1,ll r1,ll l2,ll r2)
    {
        if(l1>r1) swap(l1,r1);
        if(l2>r2) swap(l2,r2);
        return !(r1<l2||r2<l1);
    }
    bool isSS(P p1,P p2,P q1,P q2)
    {
        return intersect(p1.x,p2.x,q1.x,q2.x)&&intersect(p1.y,p2.y,q1.y,q2.y)&&sign(cross(p1,p2,q1),cross(p1,p2,q2))<=0&&sign(cross(q1,q2,p1),cross(q1,q2,p2))<=0;
    }
    bool check(int xx,int yy,int zz,int dd)
    {
        if(xx==zz||xx==dd) return true;
        if(yy==zz||yy==dd) return true;
        return false;
    }
    bool Onseg(P p1,P p2,P q)
    {
        ll tmp=(q.x-p1.x)*(p2.y-p1.y)-((p2.x-p1.x)*(q.y-p1.y));
        if(tmp==0)
        {
            ll min_x=min(p1.x,p2.x);
            ll max_x=max(p1.x,p2.x);
            ll min_y=min(p1.y,p2.y);
            ll max_y=max(p1.y,p2.y);
            if(min_x<=q.x&&q.x<=max_x&&min_y<=q.y&&q.y<=max_y) return true;
        }
        return false;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;++i)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            Mp[u][v]=Mp[v][u]=true;
            f.push_back(make_pair(u,v));
        }
        //if(Onseg(temp,tempp,zz)) cout<<"QAQ"<<endl;
        for(int i=1;i<=n;++i)
        {
            scanf("%lld%lld",&pos[i].x,&pos[i].y);
        }
        int cnt=0;
        for(int i=0;i<f.size();++i)
        {
            for(int j=i+1;j<f.size();++j)
            {
                P p_1=pos[f[i].first];
                P p_2=pos[f[i].second];
                P p_3=pos[f[j].first];
                P p_4=pos[f[j].second];
                int u_1=f[i].first;
                int v_1=f[i].second;
                int u_2=f[j].first;
                int v_2=f[j].second;
                if(Onseg(p_1,p_2,p_3)&&Onseg(p_1,p_2,p_4))
                {
                    cnt++;
                }
                else if(Onseg(p_3,p_4,p_1)&&Onseg(p_3,p_4,p_2)) cnt++;
                else if(check(u_1,v_1,u_2,v_2)) continue;
                else if(isSS(p_1,p_2,p_3,p_4)) ++cnt;
            }
        }
        cout<<cnt<<endl;
        return 0;
    }
    

      Kropki

    题目描述

     

    你有一个11到nn的排列p_1, p_2, dots, p_np1,p2,,pn,对于所有的i (1leq ileq n-1)i(1in1),如果p_ipip_{i+1}pi+1中,有一个数是另一个的两倍,那么会在这两个数之间画上一个点,否则不会。

    现在你把所有数字都擦掉了,只剩下了这些点,请问有多少种11到nn的排列满足条件。

     
     

    输入描述

     

    第一行一个正整数n (2leq nleq 15)n(2n15)。

    接下来一行一个长度为n-1n1的0101串,其中第ii个字符为11表示第ii个数与第i+1i+1个数之间有点,否则没有。

    输出描述

     

    输出一个答案,由于答案可能很大,对10^9+7109+7取模。

    样例输入 1 

    4
    001
    

    样例输出 1

    6

    Div2 版本,状压即可。 dp[i][j]表示已经用了哪些数,最后一位数是什么,根据定义转移即可。(两种情况,最后一位是0,最后一位不是0)
    #include <bits/stdc++.h>
    #define maxn 20
    using namespace std;
    typedef long long ll;
    char s[maxn];
    int Mp[maxn][maxn];
    ll dp[1<<20][maxn];
    const ll mod=1e9+7;
    int main()
    {
        int n;
        scanf("%d",&n);
        scanf("%s",s+1);
        for(int i=0;i<(1<<n);++i)
        {
            int len=0;
            for(int j=0;j<n;++j)
            {
                if(i&(1<<j)) ++len;
            }
            if(len==1)
            {
                for(int j=0;j<n;++j)
                {
                    if(i&(1<<j))
                    {
                        dp[i][j+1]=1;
                    }
                }
            }
        }
        for(int i=1;i<(1<<n);++i)
        {
            int len=0;
            for(int j=0;j<n;++j)
            {
                if(i&(1<<j)) ++len;
            }
            if(len==1)
            {
                continue;
            }
            len--;
            if(s[len]=='0')
            {
                for(int j=0;j<n;++j)
                {
                    if(i&(1<<j))
                    {
                        for(int k=0;k<n;++k)
                        {
                            if((j+1)==2*(k+1)||(k+1)==2*(j+1)) continue;
                            if((i&(1<<k))&&k!=j)
                            {
                                dp[i][j+1]=(dp[i][j+1]+dp[i^(1<<j)][k+1])%mod;
                            }
                        }
                    }
                }
            }
            else
            {
                for(int j=0;j<n;++j)
                {
                    if(i&(1<<j))
                    {
                      for(int k=0;k<n;++k)
                      {
                          if(k==j) continue;
                          if(i&(1<<k))
                          {
                              if((k+1)==2*(j+1)||(j+1)==2*(k+1))
                              {
                                  dp[i][j+1]=(dp[i][j+1]+dp[i^(1<<j)][k+1])%mod;
                              }
                          }
                      }
                    }
                }
            }
        }
        ll ans=0;
        for(int i=1;i<=n;++i)
        {
            ans=(ans+dp[(1<<n)-1][i])%mod;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

      

  • 相关阅读:
    mac 修改Python版本
    idea 系列破解
    史上最完全Mac安装Scrapy指南
    mac下brew安装mysql
    IOS: 网络图片缓存
    欢迎访问我的git
    学习笔记
    2019-2020-1 20191327《信息安全专业导论》第十二周学习总结
    2019-2020学年 20191327《信息安全专业导论》第十一周学习总结
    2019-2020学年 20191327《信息安全专业导论》第十周学习总结
  • 原文地址:https://www.cnblogs.com/zyf3855923/p/10346303.html
Copyright © 2011-2022 走看看