第八届福建省大学生程序设计竞赛(部分题解)

A - Frog
鸡兔同笼问题

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#define max(a,b)   (a>b?a:b)
#define min(a,b)   (a<b?a:b)
#define swap(a,b)  (a=a+b,b=a-b,a=a-b)
#define memset(a,v)  memset(a,v,sizeof(a))
#define X (sqrt(5)+1)/2.0  //Wythoff
#define Pi acos(-1)
#define e  2.718281828459045
#define eps 1.0e-8
using namespace std;
typedef long long int LL;
typedef pair<int,int> pa;
const LL MAXL(1e6);
const int INF(0x7f7f7f7f);
const LL mod(1e9+7);
int dir[4][2]= {{-1,0},{1,0},{0,1},{0,-1}};
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        LL n,m;
        cin>>n>>m;
        LL x=(4*n-m)/2;
        LL y=(m-2*n)/2;
        cout<<y<<" "<<x<<endl;
    }
}

B - Triangles

一共给了六个点,前三个点是第一个三角形,后三个点是第二个三角形。
题意:判断两个三角形的关系,相交,内含或相离

对第一个三角形的每一条边和第二个三角形的每一条边分别判断是否相交,如果不相交,再判断是否包含,如果不包含,那么就剩相离的情况了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define eps 1e-8
#define zero(x) ((x>0? x:-x)<eps)
#define _sign(x) ((x)>eps?1:((x)<-eps?2:0))
using namespace std;
typedef long long int LL;
const int MAXL(1e5);
const int INF(0x7f7f7f7f);
const int mod(1e9+7);
int dir[4][2]= {{-1,0},{1,0},{0,1},{0,-1}};
struct point
{
    double x,y;
};
struct line
{
    point a,b;
};
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);
}
int dots_inline(point p1,point p2,point p3)
{
    return zero(xmult(p1,p2,p3));
}
int same_side(point p1,point p2,point l1,point l2)
{
    return xmult(l1,p1,l2)*xmult(l1,p2,l2)>eps;
}
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;
}
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);
}
int inside_convex_v2(point q,int n,point *p)
{
    int i,s[3]={1,1,1};
    for(i=0;i<n&&s[0]&&s[1]|s[2];i++)
    {
        s[_sign(xmult(p[(i+1)%n],q,p[i]))]=0;
    }
    return s[0]&&s[1]|s[2];
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {

        point p1[4],p2[4];
        for(int i=0; i<3; i++)
            cin>>p1[i].x>>p1[i].y;
        for(int i=0; i<3; i++)
            cin>>p2[i].x>>p2[i].y;
        int flag[10]= {0};
        /*判断相交的情况*/
        flag[1]=intersect_in(p1[0],p1[1],p2[0],p2[1]);
        flag[2]=intersect_in(p1[0],p1[1],p2[1],p2[2]);
        flag[3]=intersect_in(p1[0],p1[1],p2[0],p2[2]);
        flag[4]=intersect_in(p1[1],p1[2],p2[0],p2[1]);
        flag[5]=intersect_in(p1[1],p1[2],p2[1],p2[2]);
        flag[6]=intersect_in(p1[1],p1[2],p2[0],p2[2]);
        flag[7]=intersect_in(p1[0],p1[2],p2[0],p2[1]);
        flag[8]=intersect_in(p1[0],p1[2],p2[1],p2[2]);
        flag[9]=intersect_in(p1[0],p1[2],p2[0],p2[2]);
        int logo=0;
        for(int i=1; i<=9; i++)
        {
            if(flag[i]==1)
            {
                logo=1;
                break;
            }
        }
        if(logo)
        {
            cout<<"intersect"<<endl;
            continue;
        }
        int log[10]={0};
        int len=0;
        for(int i=0;i<3;i++)
        {
            log[len++]=inside_convex_v2(p1[i],3,p2);
            //判断第一个三角形是否在第二个三角形内
        }
        for(int i=0;i<3;i++)
        {
            log[len++]=inside_convex_v2(p2[i],3,p1);
            //判断第二个三角形是否在第一个三角形内
        }
        int temp=0;
        for(int i=0;i<6;i++)
        {
            if(log[i]==0)
                temp++;
        }
        if(temp==6)//如果不包含 则相离
            cout<<"disjoint"<<endl;
        else
            cout<<"contain"<<endl;
    }
}

D - Game

判断第二个串是否是第一个串的子串。
然后第一个串反转,在判断第二个串是否是第一个串的子串。
KMP搞一搞。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<algorithm>
#define max(a,b)   (a>b?a:b)
#define min(a,b)   (a<b?a:b)
#define memset(a,v)  memset(a,v,sizeof(a))
#define X (sqrt(5)+1)/2.0  //Wythoff
#define Pi acos(-1)
#define e  2.718281828459045
#define eps 1.0e-8
using namespace std;
typedef long long int LL;
const int MAXL(1e5);
const int INF(0x7f7f7f7f);
const int mod(1e9+7);
int dir[4][2]= {{-1,0},{1,0},{0,1},{0,-1}};
char s[MAXL+50],t[MAXL+50];
int Next[MAXL+50];
void Getnext()
{
    int i=0,j=-1;
    Next[0]=-1;
    int len=strlen(t);
    while(i<len)
    {
        if(j==-1||t[i]==t[j])
        {
            Next[++i]=++j;
            if(t[i]==t[j])
                Next[i]=Next[j];
        }
        else
            j=Next[j];
    }
}
int index_KMP()
{
    memset(Next,0);
    Getnext();
    int i=0,j=0;
    int len1=strlen(s),len2=strlen(t);
    while(i<len1&&j<len2)
    {
        if(j==-1||s[i]==t[j])
        {
            i++;
            j++;
        }
        else
        {
            j=Next[j];
        }
    }
    if(j>=len2)
        return 1;
    else
        return -1;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        getchar();
        scanf("%s%s",s,t);
        if(t[0]=='0')
        {
            cout<<"Alice"<<endl;
            continue;
        }
        int temp1=0,temp2=0;
        temp1=index_KMP();
        int len=strlen(s);
        for(int i=0; i<=(len-1)/2; i++)
            swap(s[i],s[len-i-1]);
        temp2=index_KMP();
        if(temp1!=-1||temp2!=-1)
            cout<<"Alice"<<endl;
        else
            cout<<"Bob"<<endl;

    }
}

G - YYS

队友推的公式
n!/n + n!/(n-1)+…..+n!/1

java写
一开始用BigDecimal超时了。
但是因为n!总是能整除分母的数字,所以用BigInteger写就可以
最后加个 .0

import java.util.*;
import java.math.*;
public class Main  
{  
    public static BigInteger factorial(BigInteger n)
    {  
        BigInteger bd1 = new BigInteger("1");
        BigInteger bd2 = new BigInteger("2");
        BigInteger result = bd1;
        while(n.compareTo(bd1) > 0)
        {
            result = result.multiply(n.multiply(n.subtract(bd1)));  
            n = n.subtract(bd2); 
        }   
        return result;   
    }  
    public static void main(String args[])  
    {  
        Scanner cin = new Scanner(System.in);
        int T;
        T=cin.nextInt();
        for(int t=1;t<=T;t++)
        {
            BigInteger n;
            n=cin.nextBigInteger();
            BigInteger fac;
            fac=factorial(n);
            BigInteger sub=new BigInteger("1");
            BigInteger ans=new BigInteger("0");
            for(BigInteger i=n;i.compareTo(sub)>=0;i=i.subtract(sub))
            {
                ans=ans.add(fac.divide(i));
            }
            System.out.println(ans+".0");
        }
    }
 }

J - Trades

算是属于贪心。
每次维护前面的最小值,如果对于当前的点,它大于等于前面的点并且小于等于后面的点,那么就在此点以维护的最小值的价格买入G货币,然后在这个点换成RMB
最后再特判一下最后一个点。

由于值巨大,计算的时候会超long long,所以还是用java搞一搞
(小插曲,因为Case全都写成了大写,WA了两发。。最后才找出错)

import java.util.*;
import java.math.*;
public class Main  
{  
    public static void main(String args[])  
    {  
        Scanner cin=new Scanner(System.in);
        BigInteger mod1= new BigInteger("1000000007");
        int T;
        BigInteger a[] = new BigInteger[2050];
        T=cin.nextInt();
        int CASE=1;
        for(int test=1;test<=T;test++)
        {
            int n;
            BigInteger rmb;
            n=cin.nextInt();
            rmb=cin.nextBigInteger();
            for(int i=1;i<=n;i++)
                a[i]=cin.nextBigInteger();
            BigInteger mi=a[1];
            BigInteger t;
            for(int i=2;i<n;i++)
            {
                if(a[i].compareTo(mi)<0)    
                    mi=a[i];
                if(a[i].compareTo(a[i-1])>=0&&a[i].compareTo(a[i+1])>0)
                {
                    if(rmb.compareTo(mi)>=0)
                    {
                        t=rmb.divide(mi);
                        rmb=rmb.subtract(t.multiply(mi));
                        rmb=rmb.add(t.multiply(a[i]));
                        mi=a[i];
                    }
                }
            }
            if(a[n].compareTo(a[n-1])>=0)
            {
                if(rmb.compareTo(mi)>=0)
                {
                    t=rmb.divide(mi);
                    rmb=rmb.subtract(t.multiply(mi));
                    rmb=rmb.add(t.multiply(a[n]));
                }
            }
            System.out.print("Case #"+CASE+": ");
            System.out.println(rmb.mod(mod1));
            CASE++;
        }
    }  
}  

K - Wand

错排:f (1)=0,f ( 2 )=1 ; f ( i )= ( i - 1) * ( f( i - 1 )+f( i - 2) );
因为是至少k个人要拿到数组自己的帽子,所以从k遍历到n
求 C(n,k)*f(n-k)
当k==n-1的时候,只剩下一个人,拿的肯定是自己的帽子,所以方案数为0。
当k==n的时候,所有人都拿自己的帽子,方案数为1。
(原题说的好像不是帽子。。是棍子。。)

求解的过程中用到费马小定理求逆元。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#define max(a,b)   (a>b?a:b)
#define min(a,b)   (a<b?a:b)
#define swap(a,b)  (a=a+b,b=a-b,a=a-b)
#define memset(a,v)  memset(a,v,sizeof(a))
#define X (sqrt(5)+1)/2.0  //Wythoff
#define Pi acos(-1)
#define e  2.718281828459045
#define eps 1.0e-8
using namespace std;
typedef long long int LL;
const int MAXL(1e4);
const int INF(0x7f7f7f7f);
const int mod(1e9+7);
int dir[4][2]= {{-1,0},{1,0},{0,1},{0,-1}};
LL f[MAXL+50];
LL fac[MAXL+50];
void init()
{
    f[1]=0,f[2]=1;
    for(LL i=3;i<=MAXL;i++)
        f[i]=((i-1)*(f[i-1]+f[i-2]))%mod;
    fac[0]=fac[1]=1;
    for(LL i=2; i<=MAXL; i++)
        fac[i]=fac[i-1]*i%mod;
}
LL fast_pow(LL a,LL b,LL c)
{
    LL ans=1;
    a=a%c;
    while(b)
    {
        if(b&1)
            ans=a*ans%c;
        a=a*a%c;
        b>>=1;
    }
    return ans%c;
}
LL niYuan(LL a, LL b)
{
    return fast_pow(a, b - 2, b);
}
LL C(LL a, LL b)
{
    return fac[a]*niYuan(fac[b],mod)%mod*niYuan(fac[a-b],mod)%mod;
}

int main()
{
    init();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,k;
        scanf("%d%d",&n,&k);
        LL ans=1;
        for(int i=k;i<=n-1;i++)
        {
            ans=(ans+(C(n,i)*f[n-i])%mod)%mod;
        }
        cout<<ans%mod<<endl;
    }
}

L - Tic-Tac-Toe

模拟题- - ( 不是我写的代码

#include<stdio.h>
#include<string.h>
char mapp[5][10],s[3],c;
int main()
{
    int T,i,j,s0,flag,k,o,t,x,y;
    scanf("%d",&T);
    s[0]='o';
    s[1]='x';
    while(T--)
    {
        getchar();
        for(i=1; i<=3; i++)
            gets(mapp[i]);
        scanf("%c",&c);
        if(c=='o')
            s0=0;
        else
            s0=1;
        flag=0;
        for(i=1; i<=3; i++)
        {
            for(j=0; j<=5; j+=2)
            {
                if(mapp[i][j]=='.')
                {
                    t=0;
                    mapp[i][j]=s[s0];
                    for(k=1; k<=3; k++)
                    {
                        x=y=0;
                        for(o=0; o<=5; o+=2)
                        {
                            if(mapp[k][o]==s[s0])
                                x++;
                            if(mapp[k][o]=='.')
                                y++;
                        }
                        if(x==3)
                            flag=1;
                        if(x==2&&y==1)
                            t++;
                    }
                    for(k=0; k<=5; k+=2)
                    {
                        x=y=0;
                        for(o=1; o<=3; o++)
                        {
                            if(mapp[o][k]==s[s0])
                                x++;
                            if(mapp[o][k]=='.')
                                y++;
                        }
                        if(x==3)
                            flag=1;
                        if(x==2&&y==1)
                            t++;
                    }
                    x=y=0;
                    if(mapp[1][0]==s[s0])
                        x++;
                    if(mapp[1][0]=='.')
                        y++;
                    if(mapp[2][2]==s[s0])
                        x++;
                    if(mapp[2][2]=='.')
                        y++;
                    if(mapp[3][4]==s[s0])
                        x++;
                    if(mapp[3][4]=='.')
                        y++;
                    if(x==3)
                        flag=1;
                    if(x==2&&y==1)
                        t++;
                    x=y=0;
                    if(mapp[1][4]==s[s0])
                        x++;
                    if(mapp[1][4]=='.')
                        y++;
                    if(mapp[2][2]==s[s0])
                        x++;
                    if(mapp[2][2]=='.')
                        y++;
                    if(mapp[3][0]==s[s0])
                        x++;
                    if(mapp[3][0]=='.')
                        y++;
                    if(x==3)
                        flag=1;
                    if(x==2&&y==1)
                        t++;
                    mapp[i][j]='.';
                    if(t==2)
                        flag=1;
                }
            }
        }
        if(flag==1)
            printf("Kim win!\n");
        else
            printf("Cannot win!\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值