第八届福建省赛-重现赛 【(6+3)/12】 [待补]

上来A题就崩了 上来习惯性long long 确忘了用I64d wa了4发。。
F题 一处爆int 又wa了10发。。。
L题 判断 把a[1][3]打成a[1][2]又wa了3发。。。。

果然我只是个坑队友的坑货,, ,贡献了队伍的全部罚时

1 Frog

————————————————————————————————————
传统的鸡兔同笼问题。。


a个脑袋,b条腿

青蛙个数 = b/2-a;
鸡的个数 = a-青蛙个数;

代码无

2 Triangles

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


直接枚举两个三角形,判断一个三角形的三个点 是不是都在另一个三角形里面,如果有就是包含

然后就看是不是相离的, 如果没有任何一个点在另外的三角形里就是相离,但是要注意六芒星这种情况,所以还要枚举下边 看一看有没有相交的

然后就是相交了 …


#include
#include
#include
#include 
using namespace std;
#define LL long long int

const int N = 1e5 + 7;
const int MOD = 1e9+7;

/**********************************/

struct point{
    double x,y;
};

struct trangle{
    point p[3];
}c[2];

double multi(point p1,point p2,point p0){
    return fabs((p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x));
}

double area(point a,point b,point c){
    return multi(a,b,c);
}
int sum;

// 判断c1 在不在c2 里
bool cantian(trangle c1,trangle c2){
    double ac2 =area(c2.p[0],c2.p[1],c2.p[2]);
    int t =0 ;
    for(int i=0;i<=2;i++)
        if(area(c1.p[i],c2.p[0],c2.p[1])+area(c1.p[i],c2.p[1],c2.p[2])+
           area(c1.p[i],c2.p[0],c2.p[2]) > ac2);
        else sum++,t++;
    return t==3;
}

bool IsIntersected(point s1,point e1,point s2,point e2)//两个线段相交
{
    return(max(s1.x,e1.x)>=min(s2.x,e2.x))&&
           (max(s2.x,e2.x)>=min(s1.x,e1.x))&&
           (max(s1.y,e1.y)>=min(s2.y,e2.y))&&
           (max(s2.y,e2.y)>=min(s1.y,e1.y))&&
           (multi(s1,s2,e1)*multi(s1,e1,e2)>0)&&
           (multi(s2,s1,e2)*multi(s2,e2,e1)>0);
}

bool judge(){
    if(IsIntersected(c[1].p[1],c[1].p[2],c[2].p[1],c[2].p[2]))return true;
    if(IsIntersected(c[1].p[1],c[1].p[2],c[2].p[2],c[2].p[3]))return true;
    if(IsIntersected(c[1].p[1],c[1].p[2],c[2].p[1],c[2].p[3]))return true;

    if(IsIntersected(c[1].p[3],c[1].p[2],c[2].p[1],c[2].p[2]))return true;
    if(IsIntersected(c[1].p[3],c[1].p[2],c[2].p[2],c[2].p[3]))return true;
    if(IsIntersected(c[1].p[3],c[1].p[2],c[2].p[1],c[2].p[3]))return true;

    if(IsIntersected(c[1].p[1],c[1].p[3],c[2].p[1],c[2].p[2]))return true;
    if(IsIntersected(c[1].p[1],c[1].p[3],c[2].p[2],c[2].p[3]))return true;
    if(IsIntersected(c[1].p[1],c[1].p[3],c[2].p[1],c[2].p[3]))return true;

    return false;

}

void solve(){
    sum = 0;
    if(cantian(c[0],c[1])||cantian(c[1],c[0])){
        puts("contain");
        return ;
    }
    if(sum>0||judge()){
        puts("intersect");
        return ;
    }
    puts("disjoint");
    return ;
}

int main(){
    int _ = 1,kcase = 0;
    for(scanf("%d",&_);_--;){
        for(int i=0;i<=1;i++)for(int j=0;j<=2;j++)
            scanf("%lf%lf",&c[i].p[j].x,&c[i].p[j].y);
        solve();
    }
    return 0;
}

3 DotA and LOL

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

4 Game

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

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

问你两个人最后谁赢


考虑到如果B想让两个数不等那么只能是在A中没有B的子串才行,否则A不断的翻转在除以10一定会有一个时刻和B相同,这时候无论B怎么翻转还是除10,最终的一定会有一个时刻相等,

所以只要用kmp匹配一下A的数是否有B或者翻转的B就行了

注意的是 B的数 如果翻转就相当去去掉了后面的0,所以在匹配之前除了一下B,使两端都没有0;

#include 
#include 
#include 
#include 
#include 
#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;iif(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;iif(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

————————————————————————————————————
有一个根为1的有根树

然后有两种操作
1 v x k : a[v]+=x , a[v’]+=x-k (v’是v的孩子) , a[v”]+=x-2*k (v”是v’的孩子) and so on.
2 v : 输出 a[v] mod 1000000007(10^9 + 7).


考虑单链的时候如何维护-n*k的情况,

对于⑤来讲

>>>>4k1 3k1 2k1 1k1 0k1

可以变成这样

>>>>4k1 3k2 2k3 1k4 0k5||+5k1 +5k2 +5k3 +5k4 +5k5+1k1 2k2 3k3 4k4 5k5

所以我们可以维护两个BIT,一个用来记录 ki 另一个记录 ik+i
然后翻倍相减即可,

同时在用一个维护 xi ,其实和上面的那个放一起就行了,,

考虑是在树上进行
i 对应的就是节点的深度

在加一个树剖就能做了

int n;

struct edge{
    int to,next;
}G[N<<1];

int head[N],cntG;

void add(int u,int v){
    G[cntG].to=v,G[cntG].next=head[u],head[u]=cntG++;
    G[cntG].to=u,G[cntG].next=head[v],head[v]=cntG++;
}

LL bit[N][3];
#define lowbit(x) (x&-x)
void update(int i,int v,int x){
    for(;i&&i<=n;i+=lowbit(i)){
        bit[i][x]+=v; bit[i][x]%=MOD;
    }
}
LL getSum(int i,int x){
    LL ans = 0;
    for(;i;i-=lowbit(i))
        ans+=bit[i][x];
    return ans%=MOD;
}

int dep[N],fa[N],son[N],sz[N];
void dfs(int u,int f,int d){
    dep[u]=d,fa[u]=f,son[u]=0,sz[u]=1;
    for(int i=head[u],to;i!=-1;i=G[i].next){
        to=G[i].to;
        if(to == f) continue;
        dfs(to,u,d+1);
        sz[u]+=sz[to];
        if(sz[to]>sz[son[u]]) son[u]=to;
    }
}

int top[N],tree[N],tot;
void dfs2(int u,int tp){
    tree[u]=++tot;top[u]=tp;
    if(son[u]) dfs2(son[u],tp);
    else return ;
    for(int i=head[u],to;i!=-1;i=G[i].next){
        to=G[i].to;
        if(to==fa[u]||to==son[u]) continue;
        dfs2(to,to);
    }
}

void solve(int x){
    int fx=top[x],t=dep[x];
    LL sum1 = 0,sum2 = 0,sum3 = 0;
    while(fx!=1){
        sum1 = (sum1+getSum(tree[x],0)-getSum(tree[fx]-1,0)+MOD)%MOD;
        sum2 = (sum2+getSum(tree[x],1)-getSum(tree[fx]-1,1)+MOD)%MOD;
        sum3 = (sum3+getSum(tree[x],2)-getSum(tree[fx]-1,2)+MOD)%MOD;
        x=fa[fx],fx=top[x];
    }
    sum1 = (sum1+(getSum(tree[x],0)-getSum(tree[1]-1,0))+MOD)%MOD;
    sum2 = (sum2+(getSum(tree[x],1)-getSum(tree[1]-1,1))+MOD)%MOD;
    sum3 = (sum3+(getSum(tree[x],2)-getSum(tree[1]-1,2))+MOD)%MOD;

    sum1*=t;sum1%=MOD;
    sum2-=sum1;sum2=(sum2%MOD+MOD)%MOD;
    sum2+=sum3;(sum2%=MOD);

    printf("%I64d\n",sum2);
    return ;
}

int main(){
    int _ = 1,kcase = 0;
    for(scanf("%d",&_);_--;){
        memset(head,-1,sizeof(head));
        memset(bit,0,sizeof(bit));

        n=read();cntG=0;
        for(int i=2,x;i<=n;i++){
            x=read();add(i,x);
        }

        dfs(1,0,1);
        tot=0,dfs2(1,1);

        int q,op,v,x,k;
        for(q=read();q--;){
            op=read(),v=read();
            if(1 == op){
                x=read(),k=read();
                update(tree[v],k,0);
                update(tree[v],(LL)k*dep[v]%MOD,1);
                update(tree[v],x,2);
            }
            else solve(v);
        }
    }
    return 0;
}

7 YYS

————————————————————————————————————
有n中物品,你一次只能抽取一个物品,得到每个物品的概率是1/n,然后问你凑齐n种物品的期望


考虑拿到1个物品是的期望是1

那么拿到第二个物品就是在拿到第一个的基础上再拿到一个没拿过的 ,那么概率就是 (n1)/n ,期望就是 n/(n1)

那么拿到第三个物品就是在拿到第二个的基础上再拿到一个没拿过的 ,那么概率就是 (n2)/n ,期望就是 n/(n2)

。。。

那么拿到第 n 个物品就是在拿到第 n1 个的基础上再拿到一个没拿过的 ,那么概率就是 (n2)/n ,期望就是 n/(n2)

所以结果就是 w×i=1nni=i=1nn!i

因为数据有点大 所以上高精度


#include
#include
#include
#include 
#include 
using namespace std;
#define LL long long int

const int N = 1e5 + 7;
const int MOD = 1e9+7;

/**********************************/

#define MAXN 9999
#define MAXSIZE 10
#define DLEN 4

class 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 _ = 1,n;
    for(scanf("%d",&_);_--;){
        scanf("%d",&n);
        BigNum ans = 0,t = 1;
        for(int i=1;i<=n;i++){
            t=t*i;
        }

        for(int i=1;i<=n;i++){
            ans = ans + (t/i);
        }
        ans.print();
        puts(".0");
    }
    return 0;
}

8 Cantonese

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

9 Magic

————————————————————————————————————
给你n个字符串,每个字符串有一个价值,
然后有两种操作
1 x y 将第x个字符串的价值变成y
2 x 问你以第x个字符串做为后缀的且价值小于等于第x个字符串价值的字符串有多少个

注意一个串是自身的后缀.


本以为这题另有高论, 后缀??! 后缀数组什么的…

但是没想到到啊 这个 O(nq) 都能过….

首先预处理出每个字符串后缀的hash,
然后每次暴力枚举每个字符串判断就好了.


#include
#include
#include
#include 
#include 
using namespace std;
#define LL long long int

const int N   = 1e5+7;
const int MOD = 1e9+7;

/**********************************/
char s[1111][1111];
unsigned long long int  h[1111][1111],t;
int  a[1111],len[1111];

int main(){
    int _ = 1,n,q;
    for(scanf("%d",&_);_--;){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%s %d",s[i],&a[i]);
            len[i] = strlen(s[i]);
            reverse(s[i],s[i]+len[i]);
            h[i][0]=(s[i][0]-'a'),t=29;
            for(int j=1;j1]+(s[i][j]-'a')*t;
                t=t*29;
            }
        }

        int ans ,op,x,y;
        scanf("%d",&q);
        for(int i=1;i<=q;i++){
            scanf("%d%d",&op,&x);
            if(1 == op){
                scanf("%d",&y);
                a[x]=y;
            }
            else {
                ans = 0;
                for(int i=1;i<=n;i++){
                    if(a[i]>a[x]) continue;
                    if(len[i]continue;
                    if(h[i][len[x]-1] == h[x][len[x]-1]){
                        ans++;
                    }
                }
                printf("%d\n",ans);
            }
        }

    }
    return 0;
}

10 Trades

————————————————————————————————————
开始你有m钱,有n天,有一个显卡,在每天有不同的价格,你可以在某一天买显卡,或者卖显卡,或者不买不卖,问最后你的钱最多是多少。


显然要在便宜的时候买,贵的时候卖,

然后考虑到 对于两个相邻的天,如果前一天的便宜,今天的贵那么就可以在前一天买然后在今天卖掉,这样就能赚钱了,

然后考虑 c[i1]<c[i]<c[i+1] 的时候 ,应该在 i1 天买, i+1 天卖,那么其实和在 i1 天买, i 天卖 i 天买, i+1 天卖 效果是等价的,所以只要比较两天的价格就好了,,

如果 c[i1]<c[i] 那么就在 i1 天买, i 天卖。

不知道为什么用那个C++的高精度板子,就是过不去,然后用了Java才过。。

import java.io.*;
import java.util.*;
import java.math.BigInteger;  

public class Main{
    public static void main(String args[]) throws Exception {
        Scanner cin=new Scanner(System.in);
        BigInteger t1;
        BigInteger t2;

        int t,n,k,cas,mod;
        mod = 1000000007;
        int[] c = new int[2222];
        t = cin.nextInt();
        for(cas=1;cas<=t;cas++) {
            n = cin.nextInt();
            k = cin.nextInt();
            BigInteger m = BigInteger.valueOf(k);
            int i;
            for(i=1;i<=n;i++) c[i]=cin.nextInt();

            for(i=2;i<=n;i++)
                if(c[i]>c[i-1]){
                    t1 = m.remainder(BigInteger.valueOf(c[i-1]));
                    t2 = m.divide(BigInteger.valueOf(c[i-1])).multiply(BigInteger.valueOf(c[i]));
                    m = t1.add(t2);
                }
            m = m.remainder(BigInteger.valueOf(mod));
            System.out.println("Case #"+cas+": "+m);
        }
    }
}

11 Wand

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


考虑错排,

然后将至少有k个人的k+1个人的….n个人能拿到自己物品的方案数累加就行了,

#include
#include
using namespace std;
#define LL long long int

const 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; i1]*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在下两个子的内能不能赢


考虑数据范围这么小 直接暴力枚举就好了,

首先枚举’.’ ,如果Kim下在这里就赢了 那就是Kim win
如果不是的话 要判断当前的局面 Kim是不是有大于两个地方能赢,这样才不会被另一个人扳平,

所以暴力枚举两次就行了

#include
#include
#include
using namespace std;
#define LL long long int

const int N = 1e5 + 7;
const int MOD = 1e9+7;

/**********************************/

int a[10][10];

void display(){
    for(int i=1;i<=3;i++){
        for(int j=1;j<=3;j++)
            printf("%d ",a[i][j]);
        puts("");
    }
    puts(" <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
}

bool judge(int x){
//    printf("%d\n",x);
//    display();
    if(x==a[1][1]&&a[1][1]==a[1][2]&&a[1][2]==a[1][3])return true;
    if(x==a[2][1]&&a[2][1]==a[2][2]&&a[2][2]==a[2][3])return true;
    if(x==a[3][1]&&a[3][1]==a[3][2]&&a[3][2]==a[3][3])return true;

    if(x==a[1][1]&&a[1][1]==a[2][1]&&a[2][1]==a[3][1])return true;
    if(x==a[1][2]&&a[1][2]==a[2][2]&&a[2][2]==a[3][2])return true;
    if(x==a[1][3]&&a[1][3]==a[2][3]&&a[2][3]==a[3][3])return true;

    if(x==a[1][1]&&a[1][1]==a[2][2]&&a[2][2]==a[3][3])return true;
    if(x==a[1][3]&&a[1][3]==a[2][2]&&a[2][2]==a[3][1])return true;
//    puts("--");
    return false;
}

bool Kim2(int x){
    int flag = 0;
    for(int i=1;i<=3;i++){
        for(int j=1;j<=3;j++){
            if(a[i][j]==0){
                a[i][j]=x;
                if(judge(x)) flag++;
                a[i][j]=0;
            }
        }
    }
    return flag>=2;
}

bool Kim1(int x){
    for(int i=1;i<=3;i++){
        for(int j=1;j<=3;j++){
            if(a[i][j]==0){
                a[i][j]=x;
                if(judge(x)||Kim2(x))
                    return true;
                a[i][j]=0;
            }
        }
    }
    return false;
}

char s[10];
int main(){
    int _ = 1,kcase = 0;
    for(scanf("%d",&_);_--;){

        for(int i=1;i<=3;i++){
            for(int j=1;j<=3;j++){
                scanf("%s",s);
                if(s[0]=='.') a[i][j]=0;
                else if(s[0]=='x') a[i][j]=1;
                else a[i][j]=2;
            }
        }

        scanf("%s",s);int x;
        if(s[0]=='x')   x=1;
        else            x=2;

        if(judge(3-x)) puts("Cannot win!");
        else if(judge(x)||Kim1(x))
             puts("Kim win!");
        else puts("Cannot win!");
    }
    return 0;
}

你可能感兴趣的:(套题,待补)