暑假集训日记——8.18(codeforce)

本篇文章都是复制粘贴的…不想自己做

D. Shortest Cycle
题意:一个环至少有 3 3 3个点, a a a& b ! b! b!= 0 0 0 的两个点间有一条边,求最小环
题解:
f l o y e d floyed floyed求解最小环 O ( n 3 ) O(n^3) O(n3)

emmm想到了范围问题,然后就使劲考虑怎么建环,emmm赛后发现有现成的模板…其实就是DP。

#include
#define mp make_pair
#define se second
#define fi first
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;

const int N=5e5+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const double eps=0.0000001;
const ll mod=1e9+7;
int n,m,x,y,z,k,cnt,t,len;
ll a[N];
ll dp[305][305],ans[305][305];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    if(n>=300)
        return printf("3\n"),0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            ans[i][j]=dp[i][j]=INF;
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j) continue;
            if((a[i]&a[j])!=0) dp[i][j]=ans[i][j]=1;
        }
    }

    ll cnt=INF;
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(i==j||j==k||k==i) continue;
                cnt=min(cnt,dp[i][k]+dp[k][j]+ans[i][j]);
                ans[i][j]=min(ans[i][j],ans[i][k]+ans[k][j]);
            }
        }
    }
    if(cnt!=INF)
        printf("%lld\n",cnt);
    else printf("-1\n");
}

E. Let’s Go Rolling!
题意:
数轴上有 n n n个质点,第 i i i个质点的坐标为 x i x_i xi,花费为 c i c_i ci,现在要选择其中一些点固定,代价为这些点的花费,固定的点不动,不固定的点会向左移动直至遇到固定的点,代价是这两点的距离,如果左边没有固定的点则花费为正无穷,问最小代价。

题解:动态规划
d p [ i ] [ j ] dp[i][j] dp[i][j] i i i 表示第 i i i个小球; j j j 代表被固定的隔板;

#include
#define mp make_pair
#define se second
#define fi first
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;

const int N=5e5+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const double eps=0.0000001;
const ll mod=1e9+7;
ll n,m,x,y,z,k,cnt,t,len;

ll dp[3010][3010];

struct node
{
    ll x,y;
}a[5000];

bool cmp(node a,node b)
{
    return a.x<b.x;
}

int main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&a[i].x,&a[i].y);
    }
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            dp[i][j]=INF64;
    dp[1][1]=a[1].y;
    for(int i=1;i<n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            dp[i+1][j]=min(dp[i+1][j],dp[i][j]+a[i+1].x-a[j].x);
            dp[i+1][i+1]=min(dp[i+1][i+1],dp[i][j]+a[i+1].y);
        }
    }
    ll  ans=INF64;
    for(int i=1;i<=n;i++)
        ans=min(ans,dp[n][i]);
   printf("%lld\n",ans);

}

B - Triangles
题意:判断两个三角形的关系
题解:详细题解
三角形的叉积
我特别想知道谁给我的勇气刚这道题…关键还没刚出来…

#include
#include
#include
#include
#define eps 1e-8
#define zero(x) (((x)>0?(x):(-x))
 
using namespace std;
 
struct point{double x,y;};
struct triangle{point a,b,c;};
 
///计算叉积
/**
设向量A=p1-p0,B=p2-p0;
    |     i           j       k   |
AxB=| p1.x-p0.x   p1.y-p0.y   0   |
    | p2.x-p0.x   p2.y-p0.y   0   |
*/
 
double xmult(point p1,point p2,point p0){
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
 
///判断三点共线
/**
若三点共线 设向量A=p1-p0,B=p2-p0;
|AxB|=|A||B|sin,又三点共线,所以=0,所以|AxB|=0;
*/
int dots_inline(point p1,point p2,point p3){
    return zero(xmult(p1,p2,p3));
}
///判断两点在线段同侧
/**
设向量 A=l2-l1,B=p2-l1,C=p1-l1;
由右手定则可以得出,若p1,p2两点同侧,则|AxB|与|AxC|同正负;
若p1或p2在线段上,则|AxC|或|AxB|等于0
*/
int same_side(point p1,point p2,point l1,point l2){
    return xmult(l1,p1,l2) * xmult(l1,p2,l2) > eps;
}
///判断点是否在线上,包括端点
/**
1.先判三点共线;
2.再判点是否在线段上,如果在,则两个端点的横坐标与该点的横坐标(纵坐标)之差的积小于或者等于零;
*/
int dot_online_in(point p,point l1,point l2){
    return zero(xmult(p,l1,l2))&&(l1.x-p.x)*(l2.x-p.x) < eps && (l1.y-p.y)*(l2.y-p.y) < eps;
}
 
///判断两线相交,包括部分重合和点重合
/**
1.先判是否共线,如果不共线,看其中一条边的两个端点是否在另一条线段的两侧;
2.判断点是否在线段上;
*/
int intersect_in(point u1,point u2,point v1,point v2){
    if(!dots_inline(u1,u2,v1)||!dots_inline(u1,u2,v2))
        return !same_side(u1,u2,v1,v2) && !same_side(v1,v2,u1,u2);
    return dot_online_in(u1,v1,v2)||dot_online_in(u2,v1,v2)||dot_online_in(v1,u1,u2)||dot_online_in(v2,u1,u2);
}
 
///计算面积
/**
S=|AxB|/2;
*/
double area_triangle(point p1,point p2,point p3){
    return fabs(xmult(p1,p2,p3))/2;
}
///判断点是否包含在三角形内部,包括三条边上
/**
大三角形与三个小三角形的面积之差是否为零
*/
int dot_triangle_in(triangle p1,point p0){
    return fabs(area_triangle(p1.a,p1.b,p1.c)-area_triangle(p1.a,p1.b,p0)-area_triangle(p1.a,p0,p1.c)-area_triangle(p0,p1.b,p1.c))<eps;
}
 
void solve_question(){
    point a[3],b[3];
    triangle A,B;
    for(int i=0;i<3;i++)
        cin >> a[i].x >> a[i].y;
    for(int i=0;i<3;i++)
        cin >> b[i].x >> b[i].y;
    A = (triangle){a[0],a[1],a[2]};
    B = (triangle){b[0],b[1],b[2]};
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            if(intersect_in(a[i],a[(i+1)%3],b[j],b[(j+1)%3])) { printf("intersect\n");return;}
    if(dot_triangle_in(A,b[0]) || dot_triangle_in(B,a[0]))
        printf("contain\n");
    else
        printf("disjoint\n");
 
}
 
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        solve_question();
    }
}
#include
using namespace std;
char MAP[5][5];
bool judge(char c)//判断c是否已经成功
{
    if(MAP[1][1]==c&&MAP[1][2]==c&&MAP[1][3]==c) return 1;
    if(MAP[2][1]==c&&MAP[2][2]==c&&MAP[2][3]==c) return 1;
    if(MAP[3][1]==c&&MAP[3][2]==c&&MAP[3][3]==c) return 1;
    if(MAP[1][1]==c&&MAP[2][1]==c&&MAP[3][1]==c) return 1;
    if(MAP[1][2]==c&&MAP[2][2]==c&&MAP[3][2]==c) return 1;
    if(MAP[1][3]==c&&MAP[2][3]==c&&MAP[3][3]==c) return 1;
    if(MAP[1][1]==c&&MAP[2][2]==c&&MAP[3][3]==c) return 1;
    if(MAP[1][3]==c&&MAP[2][2]==c&&MAP[3][1]==c) return 1;
    return 0;
}
bool win(char c)//Kim是否能有两个以上赢面
{
    if(judge(c))
        return 1;
    int num=0;
    for(int i=1; i<=3; i++)
    {
        for(int j=1; j<=3; j++)
        {
            if(MAP[i][j]=='.')
            {
                MAP[i][j]=c;
                if(judge(c))
                    num++;
                MAP[i][j]='.';
            }
        }
    }
    if(num>=2)
        return 1;
    return 0;
}
bool win1(char c)//对方是否能1步走赢
{
    if(judge(c))
        return 1;
    int num=0;
    for(int i=1; i<=3; i++)
    {
        for(int j=1; j<=3; j++)
        {
            if(MAP[i][j]=='.')
            {
                MAP[i][j]=c;
                if(judge(c))
                    num++;
                MAP[i][j]='.';
            }
        }
    }
    if(num)
        return 1;
    return 0;
}
int main()
{
    std::ios::sync_with_stdio(0);
    int t;
    char c1,c2;
    cin>>t;
    while(t--)
    {
        for(int i=1; i<=3; i++)
        {
            for(int j=1; j<=3; j++)
            {
                cin>>MAP[i][j];
            }
        }
        cin>>c1;
        if(c1=='x')
            c2='o';
        else
            c2='x';
        int flag=0;
        for(int i=1; i<=3; i++)
        {
            for(int j=1; j<=3; j++)
            {
                if(MAP[i][j]=='.')//枚举所有Kim可以放的点
                {
                    MAP[i][j]=c1;//走该步的话,现在该c2走了
                    if(win(c1)&&!win1(c2))//一定要c2一步赢不了的情况下c1一定要有至少2个赢面才算真正的赢
                    {
                        flag=1;
                        goto label;
                    }
                    MAP[i][j]='.';//恢复原状
                }
            }
        }
        label:
        if(flag)
            cout<<"Kim win!"<<endl;
        else
            cout<<"Cannot win!"<<endl;
    }
    return 0;
}

你可能感兴趣的:(暑假集训,Codeforces,DP动态规划)