第八届福建省赛训练总结 【6/12】

来源:互联网 发布:查看linux内核 编辑:程序博客网 时间:2024/05/10 09:20


这场6题,不过罚时有点炸,不符合我们的队以往的作风。。剩下的题有点算法有点涉及到我们的盲区了...继续努力把~

1 Frog

———————————————————————————————————— 

2 Triangles

———————————————————————————————————— 
给你两个三角形,问你这两个三角形是包含的,还是相交的,还是相离的。

这题我敲的, 感觉很水很水, 挺有信心的,结果最后wa3, 这是全场第二题, 我们第六题才出。。我们队只有我会点计算几何, 结果相当有信心的wa了3发, 原来想的是,直接判断三个点,如果有一个三角形三个点都在另一个里面,就是包含, 如果都在外面,就是分离, 其余的自然就是相交的, 但最后只剩这题的时候,给队友讲到一半,发现六角形的情况没考虑。。。为了图省事。。结果。。。相交要暴力判断两个线段是否相交~

其实是一个jianda

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <cmath>#include <map>using namespace std;const double eps = 1e-6;int sgn(double x){    if(fabs(x) < eps)return 0;    if(x < 0)return -1;    else return 1;}struct Point{    double x,y;    Point(){}    Point(double _x,double _y)    {        x = _x;y = _y;    }    Point operator -(const Point &b)const    {        return Point(x - b.x,y - b.y);    }    double operator ^(const Point &b)const    {        return x*b.y - y*b.x;    }    double operator *(const Point &b)const    {        return x*b.x + y*b.y;    }    void transXY(double B)    {        double tx = x,ty = y;        x = tx*cos(B) - ty*sin(B);        y = tx*sin(B) + ty*cos(B);    }};struct Line{    Point s,e;    Line(){}    Line(Point _s,Point _e)    {        s = _s;e = _e;    }    pair<int,Point> operator &(const Line &b)const    {        Point res = s;        if(sgn((s-e)^(b.s-b.e)) == 0)        {            if(sgn((s-b.e)^(b.s-b.e)) == 0)                return make_pair(0,res);            else return make_pair(1,res);        }        double t = ((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));        res.x += (e.x-s.x)*t;        res.y += (e.y-s.y)*t;        return make_pair(2,res);    }};bool inter(Line l1,Line l2){    return    max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) &&    max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) &&    max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) &&    max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) &&    sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e)) <= 0 &&    sgn((l1.s-l2.e)^(l2.s-l2.e))*sgn((l1.e-l2.e)^(l2.s-l2.e)) <= 0;}bool OnSeg(Point P,Line L){    return    sgn((L.s-P)^(L.e-P)) == 0 &&    sgn((P.x - L.s.x) * (P.x - L.e.x)) <= 0 &&    sgn((P.y - L.s.y) * (P.y - L.e.y)) <= 0;}int inConvexPoly(Point a,Point p[],int n){    for(int i = 0;i < n;i++)    {        if(sgn((p[i]-a)^(p[(i+1)%n]-a)) < 0)return -1;        else if(OnSeg(a,Line(p[i],p[(i+1)%n])))return 0;    }    return 1;}int inPoly(Point p,Point poly[],int n){    int cnt;    Line ray,side;    cnt = 0;    ray.s = p;    ray.e.y = p.y;    ray.e.x = -100000000000.0;    for(int i = 0;i < n;i++)    {        side.s = poly[i];        side.e = poly[(i+1)%n];        if(OnSeg(p,side))return 0;        //如果平行轴则不考虑        if(sgn(side.s.y - side.e.y) == 0)            continue;        if(OnSeg(side.s,ray))        {            if(sgn(side.s.y - side.e.y) > 0)cnt++;        }        else if(OnSeg(side.e,ray))        {            if(sgn(side.e.y - side.s.y) > 0)cnt++;        }        else if(inter(ray,side))            cnt++;    }    if(cnt % 2 == 1)return 1;    else return -1;}int main(){    int t;    cin >> t;    int x1, x2, x3, x4, x5, x6, y1,y2,y3,y4,y5,y6;    while(t--)    {        scanf("%d%d%d%d%d%d", &x1, &y1, &x2, &y2, &x3, &y3);        scanf("%d%d%d%d%d%d", &x4, &y4, &x5, &y5, &x6, &y6);        Point p1[10], p2[10];//        if(x1 > x2) swap(x1, x2);//        if(y1 > y2) swap(y1, y2);//        if(x1 > x3) swap(x1, x3);//        if(y1 > y3) swap(y1, y3);//        if(x2 > x3) swap(x2, x3);//        if(y2 > y3) swap(y2, y3);        p1[0] = Point(x1, y1);        p1[1] = Point(x2, y2);        p1[2] = Point(x3, y3);//        if(x4 > x5) swap(x4, x5);//        if(y4 > y5) swap(y4, y5);//        if(x4 > x6) swap(x4, x6);//        if(y4 > y6) swap(y4, y6);//        if(x5 > x6) swap(x5, x6);//        if(y5 > y6) swap(y5, y6);        p2[0] = Point(x4, y4);        p2[1] = Point(x5, y5);        p2[2] = Point(x6, y6);        int flag = 0;        if(inPoly(p1[0], p2, 3) == 1 &&  inPoly(p1[1], p2, 3) == 1 && inPoly(p1[2], p2, 3) == 1)            flag = 1;        if(inPoly(p2[0], p1, 3) == 1 &&  inPoly(p2[1], p1, 3) == 1 && inPoly(p2[2], p1, 3) == 1)            flag = 1;        for(int i = 0; i < 3; i++)        {            for(int j = i; j < 3; j++)            {                Line l1 = Line(p1[i], p1[j]);                for(int x = 0; x < 3; x++)                {                    for(int y = x; y < 3; y++)                    {                        Line l2 = Line(p2[x], p2[y]);                        if(inter(l1, l2))                            flag = 2;                    }                }            }        }        if(flag == 1)            puts("contain");        else if(flag == 2)            puts("intersect");        else            puts("disjoint");    }    return 0;}/*104 3 7 3 7 65 2 5 10 6 10*/

3 DotA and LOL

————————————————————————————————————

4 Game

———————————————————————————————————— 

给你两个大数,(不含前导零), 
两个人轮流操作自己的数,可以除以10(向下取整,没有小数.)或者翻转过去,(翻转之后要去掉前导0).

当有一时刻两个数相等则A赢,否则B赢,所以A想要将两个数变得相同,B想讲两个数变得不同.

问你两个人最后谁赢?

水题,注意下b最后是0的情况, 另外b只是一个0的情况,kmp就行

可以考虑一下,因为每一轮每人必须要对自己的数进行一次操作,直到最后为0,也一直在进行,一直是0了.

所以我们可以想到,如果当前B不能在A中正着匹配,或者反着匹配,那么无论A怎么变我B就一直翻转我的数,那你永远

也别想赢.否则如果A中有B的子串,那你B无论怎么办,总有一个A==B  ,上面也说了即使除到0,最后就真的一直是0

俩人都是0也匹配了.

另外需要注意,如果一开始B后面有0,需要将B中的后缀0 全部去掉,在跟A进行匹配.但是A中后面的0对结果无影响.

举例: 1235 120 

#include <iostream>#include <algorithm>#include <stdio.h>#include <string.h>#include <queue>#define maxs 2020202#define mme(i,j) memset(i,j,sizeof(i))using namespace std;char s[1000005],s2[1000005];int nexts[maxs];void getn(){    int len=strlen(s2);    int i=0,j;    j=nexts[0]=-1;    for(i=0;i<len;)    {        if(j==-1 || s2[i]==s2[j])            nexts[++i]=++j;        else            j=nexts[j];    }}bool kmp(){    getn();    int len1=strlen(s),len2=strlen(s2);    int i=0,j=0;    for(i=0;i<len1;)    {        if(j==-1||s[i]==s2[j])        {            i++;            j++;        }        else            j=nexts[j];        if(j>=len2)            return 1;    }    if(j>=len2)        return 1;    return 0;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%s%s",s,s2);        int flag = 1;        for(int i=0;s2[i];i++){            if(s2[i]=='0') continue;            flag = 0 ;break;        }        int l2 = strlen(s2);        for(int i=l2-1;i>=0;i--){            if(s2[i]=='0')                s2[i]='\0';            else break;        }//        puts(s2);        if(flag||kmp())        {            printf("Alice\n");        }        else        {            reverse(s2,s2+strlen(s2));            if(kmp())            {                printf("Alice\n");            }            else printf("Bob\n");        }    }}

5 Doctor

————————————————————————————————————

6 Change

———————————————————————————————————— 

7 YYS

————————————————————————————————————

就是有一个人,要集齐n张卡,每个卡出现的概率都为1/n,他每隔w天可以买一次卡,问你集齐所有卡片的期望是多少.


期望是常规期望,我第一次的期望题就是这个- -,点我 

主要是数太大了- -,最后化简是 n!/i, i 从1 到 n, 找了一大堆大数模板,最后才找到一个不错的,概率dp+大数把

#include <iostream>#include <cstdio>#include <algorithm>#include <string>#include <cmath>#include <stack>#include <cstring>using namespace std;//const int maxn = 1e6;  //大数位数#define MAXN 9999#define MAXSIZE 10#define DLEN 4class BigNum{private:    int a[MAXN];    //可以控制大数的位数    int len;       //大数长度public:    BigNum(){ len = 1;memset(a,0,sizeof(a)); }   //构造函数    BigNum(const int);       //将一个int类型的变量转化为大数    BigNum(const char*);     //将一个字符串类型的变量转化为大数    BigNum(const BigNum &);  //拷贝构造函数    BigNum &operator=(const BigNum &);   //重载赋值运算符,大数之间进行赋值运算    friend istream& operator>>(istream&,  BigNum&);   //重载输入运算符    friend ostream& operator<<(ostream&,  BigNum&);   //重载输出运算符    BigNum operator+(const BigNum &) const;   //重载加法运算符,两个大数之间的相加运算    BigNum operator-(const BigNum &) const;   //重载减法运算符,两个大数之间的相减运算    BigNum operator*(const BigNum &) const;   //重载乘法运算符,两个大数之间的相乘运算    BigNum operator/(const int   &) const;    //重载除法运算符,大数对一个整数进行相除运算    BigNum operator^(const int  &) const;    //大数的n次方运算    int    operator%(const int  &) const;    //大数对一个int类型的变量进行取模运算    bool   operator>(const BigNum & T)const;   //大数和另一个大数的大小比较    bool   operator<(const BigNum & T) const;    bool   operator==(const BigNum & T) const;    bool   operator>(const int & t)const;      //大数和一个int类型的变量的大小比较    bool   operator<(const int &t) const;    bool   operator==(const int &t) const;    void print();       //输出大数};bool BigNum::operator==(const BigNum & T) const {    return !(*this > T) && !(T > *this);}bool BigNum::operator==(const int &t) const {    BigNum T = BigNum(t);    return *this == T;}bool BigNum::operator<(const BigNum & T) const {    return T > *this;}bool BigNum::operator<(const int &t) const {    return BigNum(t) > *this;}BigNum::BigNum(const int b)     //将一个int类型的变量转化为大数{    int c,d = b;    len = 0;    memset(a,0,sizeof(a));    while(d > MAXN)    {        c = d - (d / (MAXN + 1)) * (MAXN + 1);        d = d / (MAXN + 1);        a[len++] = c;    }    a[len++] = d;}BigNum::BigNum(const char*s)     //将一个字符串类型的变量转化为大数{    int t,k,index,l,i;    memset(a,0,sizeof(a));    l=strlen(s);    len=l/DLEN;    if(l%DLEN)        len++;    index=0;    for(i=l-1;i>=0;i-=DLEN)    {        t=0;        k=i-DLEN+1;        if(k<0)            k=0;        for(int j=k;j<=i;j++)            t=t*10+s[j]-'0';        a[index++]=t;    }}BigNum::BigNum(const BigNum & T) : len(T.len)  //拷贝构造函数{    int i;    memset(a,0,sizeof(a));    for(i = 0 ; i < len ; i++)        a[i] = T.a[i];}BigNum & BigNum::operator=(const BigNum & n)   //重载赋值运算符,大数之间进行赋值运算{    int i;    len = n.len;    memset(a,0,sizeof(a));    for(i = 0 ; i < len ; i++)        a[i] = n.a[i];    return *this;}istream& operator>>(istream & in,  BigNum & b)   //重载输入运算符{    char ch[MAXSIZE*4];    int i = -1;    in>>ch;    int l=strlen(ch);    int count=0,sum=0;    for(i=l-1;i>=0;)    {        sum = 0;        int t=1;        for(int j=0;j<4&&i>=0;j++,i--,t*=10)        {            sum+=(ch[i]-'0')*t;        }        b.a[count]=sum;        count++;    }    b.len =count++;    return in;}ostream& operator<<(ostream& out,  BigNum& b)   //重载输出运算符{    int i;    cout << b.a[b.len - 1];    for(i = b.len - 2 ; i >= 0 ; i--)    {        cout.width(DLEN);        cout.fill('0');        cout << b.a[i];    }    return out;}BigNum BigNum::operator+(const BigNum & T) const   //两个大数之间的相加运算{    BigNum t(*this);    int i,big;      //位数    big = T.len > len ? T.len : len;    for(i = 0 ; i < big ; i++)    {        t.a[i] +=T.a[i];        if(t.a[i] > MAXN)        {            t.a[i + 1]++;            t.a[i] -=MAXN+1;        }    }    if(t.a[big] != 0)        t.len = big + 1;    else        t.len = big;    return t;}BigNum BigNum::operator-(const BigNum & T) const   //两个大数之间的相减运算{    int i,j,big;    bool flag;    BigNum t1,t2;    if(*this>T)    {        t1=*this;        t2=T;        flag=0;    }    else    {        t1=T;        t2=*this;        flag=1;    }    big=t1.len;    for(i = 0 ; i < big ; i++)    {        if(t1.a[i] < t2.a[i])        {            j = i + 1;            while(t1.a[j] == 0)                j++;            t1.a[j--]--;            while(j > i)                t1.a[j--] += MAXN;            t1.a[i] += MAXN + 1 - t2.a[i];        }        else            t1.a[i] -= t2.a[i];    }    t1.len = big;    while(t1.a[t1.len - 1] == 0 && t1.len > 1)    {        t1.len--;        big--;    }    if(flag)        t1.a[big-1]=0-t1.a[big-1];    return t1;}BigNum BigNum::operator*(const BigNum & T) const   //两个大数之间的相乘运算{    BigNum ret;    int i,j,up;    int temp,temp1;    for(i = 0 ; i < len ; i++)    {        up = 0;        for(j = 0 ; j < T.len ; j++)        {            temp = a[i] * T.a[j] + ret.a[i + j] + up;            if(temp > MAXN)            {                temp1 = temp - temp / (MAXN + 1) * (MAXN + 1);                up = temp / (MAXN + 1);                ret.a[i + j] = temp1;            }            else            {                up = 0;                ret.a[i + j] = temp;            }        }        if(up != 0)            ret.a[i + j] = up;    }    ret.len = i + j;    while(ret.a[ret.len - 1] == 0 && ret.len > 1)        ret.len--;    return ret;}BigNum BigNum::operator/(const int & b) const   //大数对一个整数进行相除运算{    BigNum ret;    int i,down = 0;    for(i = len - 1 ; i >= 0 ; i--)    {        ret.a[i] = (a[i] + down * (MAXN + 1)) / b;        down = a[i] + down * (MAXN + 1) - ret.a[i] * b;    }    ret.len = len;    while(ret.a[ret.len - 1] == 0 && ret.len > 1)        ret.len--;    return ret;}int BigNum::operator %(const int & b) const    //大数对一个int类型的变量进行取模运算{    int i,d=0;    for (i = len-1; i>=0; i--)    {        d = ((d * (MAXN+1))% b + a[i])% b;    }    return d;}BigNum BigNum::operator^(const int & n) const    //大数的n次方运算{    BigNum t,ret(1);    int i;    if(n<0)        exit(-1);    if(n==0)        return 1;    if(n==1)        return *this;    int m=n;    while(m>1)    {        t=*this;        for( i=1;i<<1<=m;i<<=1)        {            t=t*t;        }        m-=i;        ret=ret*t;        if(m==1)            ret=ret*(*this);    }    return ret;}bool BigNum::operator>(const BigNum & T) const   //大数和另一个大数的大小比较{    int ln;    if(len > T.len)        return true;    else if(len == T.len)    {        ln = len - 1;        while(a[ln] == T.a[ln] && ln >= 0)            ln--;        if(ln >= 0 && a[ln] > T.a[ln])            return true;        else            return false;    }    else        return false;}bool BigNum::operator >(const int & t) const    //大数和一个int类型的变量的大小比较{    BigNum b(t);    return *this>b;}void BigNum::print()    //输出大数{    int i;    printf("%d", a[len-1]);    for (int i = len-2; i >= 0; --i) {        printf("%04d", a[i]);    }}int main(){    int t, n;    cin >> t;    while(t--)    {        scanf("%d", &n);        BigNum cnt = 1, ans = 0;        for(int i = 1; i <= n; i++)        {            cnt = cnt * i;        };        for(int i = 1; i <= n; i++)        {            ans = ans + cnt/i;;            BigNum tmp = (cnt/i);        }        ans.print();        printf(".0\n");    }    return 0;}


8 Cantonese

————————————————————————————————————

9 Magic

————————————————————————————————————

10 Trades

————————————————————————————————————

11 Wand

———————————————————————————————————— 
有n个人,每个人有一个物品,问你打乱这些物品后至少有K个人还拿到自己的物品的可能数


水题, 但是我tm还是wa了一发。。 爆了long long;

枚举k, 然后剩下的错排就好了, 这题应该n再大一点2e7左右, 因为k就100, 很明显暗示我们要将“至少“转化...可是这题没卡

代码转自tabris

#include<stdio.h>#include<string.h>using namespace std;#define LL long long intconst int N = 1e5 + 7;const int MOD = 1e9+7;/**********************************/LL qmod(LL a,LL b) {    LL res = 1ll;    while(b) {        if(b&1) res=res*a%MOD;        b>>=1,a=a*a%MOD;    }    return res;}LL dp[N];LL fac[N],inv[N];void init() {    fac[0]=1;    for(LL i=1; i<N; i++) fac[i]=(fac[i-1]*i)%MOD;    inv[N-1] = qmod(fac[N-1],MOD-2);    for(LL i=N-2; i>=0; i--) inv[i]=(inv[i+1]*(i+1))%MOD;}LL C(int n,int m) {    return fac[n]*inv[m]%MOD*inv[n-m]%MOD;}int main() {    init();    dp[0]=1;    dp[1]=0;    for(LL i=1; i<=10000; i++) {        dp[i]=(i-1)*(dp[i-1]+dp[i-2]);        dp[i]%=MOD;    }    int t;    int n,kk;    scanf("%d",&t);    while(t--) {        scanf("%d%d",&n,&kk);        LL output=0;        for(int k=kk; k<=n; k++) {            output+=C(n,k)*dp[n-k]%MOD;            output%=MOD;        }        printf("%I64d\n",output%MOD);    }    return 0;}


12 Tic-Tac-Toe

———————————————————————————————————— 
两个人下井字棋,现在轮到Kim下,问你Kim在下两个子的内能不能赢

思路:暴力枚举。。。第一次直接赢, 跟第二次能有两个以上位置让他直接赢,就一定可以

阅读全文
1 0
原创粉丝点击