CCPC-Wannafly Winter Camp Day5 (Div2, onsite)

Special Judge

题目描述

 

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

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

 

 
 

输入描述

 

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

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

接下来nn行,每行两个整数x_i, y_i (0\leq x_i, y_i\leq 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 (1\leq i\leq n-1)i(1in1),如果p_ipip_{i+1}pi+1中,有一个数是另一个的两倍,那么会在这两个数之间画上一个点,否则不会。

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

 

 
 

输入描述

 

第一行一个正整数n (2\leq n\leq 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\n",ans);
    return 0;
}

  

posted @ 2019-02-01 16:45  行远山  阅读(219)  评论(0编辑  收藏  举报