BestCoder Round #80小结

比赛传送门

CA娘出一场比赛就身败名裂….

第一题:给定一个数集,如果能使用其中的数相加得到任意自然数(每一个数可以使用多次),输出”YES”,否则输出”NO”。

大水题…
直接判断是否有 1 就行了啊…
然后交一发,WA辣…
然后一看300多次提交一个过的都木有…然后在Discuss中说道0也是自然数…那么再多判一个 0 就行了啊…

第二题:对于一条x+y=q的直线,求它和坐标轴在第一象限围成了一个三角形中有多少个整点,并对 p 取余。

一开始以为是类欧几里得算法(ps:本弱不会写),然后仔细一看,这个三角形难道不是一个等腰直角三角形吗?╮(╯_╰)╭
整点个数:(q2)(q1)2
由于 p,q 的范围太大,所以我们要用快速乘来计算。

吐槽:我真是醉了,这种题都有人不写long long,然而窝却和他不在同一个房间…

#include <iostream>
#include <cstdio>
#define LL long long int
using namespace std;

LL q, p;
LL mul(LL a,LL pos)
{
    //由于没写a%=p,本辣鸡就终测挂辣
    a%=p;
    LL ans=0;
    for(;pos;pos>>=1)
    {
        if(pos&1)
        {
            ans+=a;
            if(ans>=p)ans-=p;
        }
        a+=a;
        if(a>=p)a-=p;
    }
    return ans;
}

int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        cin>>q>>p;
        p*=2;
        q-=2;
        cout<<mul(q+1,q)/2 <<endl;
    }
    return 0;
}

第三题:
这里写图片描述

fn 肯定是 a 的若干次幂,所以首先特判a p 的倍数。
单独观察指数。
于是很容易就得到一个递推式:

gn=cgn1+gn2+b

这不就是矩阵快速幂吗?
由于 p 是素数,所以在指数上的模数就是p1(根据费马小定理)

然而本辣鸡被卡常数,终测TLE辣…

#include <iostream>
#include <cstdio>
#include <cstring>
#define LL long long int
using namespace std;

LL n, a, b, c, mod, mod2;

LL power(LL a,LL pos)
{
    LL ans=1;
    for(;pos;pos>>=1, a=a*a%mod)
        if(pos&1)ans=ans*a%mod;
    return ans;
}

struct mat
{
    int num[15][15],h,l;
    void init(){h=l=0, memset(num,0,sizeof(num));}
    mat operator * (const mat &a) const
    {
        mat b;b.init();
        b.h=h,b.l=a.l;
        for(int i=1;i<=h;++i)
            for(int j=1;j<=a.l;++j)
                for(int k=1;k<=l;++k)
                    b.num[i][j]=(b.num[i][j]+num[i][k]*a.num[k][j])%mod2;
        return b;
    }
}temp,tmp;

mat cal(mat &a,LL pos)
{
    mat ans=a;
    for(;pos;pos>>=1, a=a*a)
        if(pos&1)ans=ans*a;
    return ans;
}

LL solve(LL n)
{
    tmp.init();
    tmp.h=3, tmp.l=1, tmp.num[1][1]=0, tmp.num[2][1]=b, tmp.num[3][1]=b;
    temp.init();
    temp.h=temp.l=3;
    temp.num[1][2]=temp.num[2][1]=temp.num[2][3]=temp.num[3][3]=1, temp.num[2][2]=c;
    tmp=cal(temp,n-3)*tmp;
    return tmp.num[2][1];
}

int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        cin>>n>>a>>b>>c>>mod;
        mod2=mod-1;
        if(n==1)puts("1");
        else if(n==2)cout<<power(a,b)<<endl;
        else if(a%mod==0)puts("0");
        else cout<<power(a,solve(n))<<endl;
    }
    return 0;
}

第四题: Fye找到了 n 个同学,把他们围成一个圈,让他们做约瑟夫游戏,然后她得到了一个同学们出圈的编号序列。游戏是这样进行的:以同学1为起点,开始计数,计数到第 k 个同学,该同学出圈。出圈的同学将不参与之后的计数。
如今Fye找到了你,她想让你告诉他满足已知出圈序列的最小的k,如果你回答不上来,她就会很生气然后把你吊打一顿。

很容易就得到了 n <script type="math/tex" id="MathJax-Element-2027">n</script>个同余方程组,然而模数并不是两两互质的,即普通的中国剩余定理是用不上的了…
所以上另一个解同余方程的模板吧…

后记:由于出题人题意不清,导致众多选手WA了无数发…

#include <iostream>
#include <cstdio>
#define LL long long int
using namespace std;

void exgcd(LL a,LL b,LL &d,LL &x,LL &y)
{
    if(!b)d=a, x=1, y=0;
    else
    {
        exgcd(b,a%b,d,y,x);
        y-=a/b*x;
    }
}

void solve(LL b[],LL n[],int num)
{
    bool flag=0;
    LL n1=n[0], n2, b1=b[0], b2, bb, d, t, k, x, y;
    for(int i=1;i<num;++i)
    {
        n2=n[i], b2=b[i], bb=b2-b1;
        exgcd(n1,n2,d,x,y);
        if(bb%d){flag=1;break;}
        k=bb/d*x, t=n2/d;
        if(t<0)t=-t;
        k=(k%t+t)%t;
        b1+=n1*k, n1=n1/d*n2;
    }
    b1%=n1;
    if(flag){puts("Creation August is a SB!");return;}
    else if(b1==0)b1=n1;
    cout<<b1<<endl;
}

LL b[105], mod[105];
int a[105], l[105], r[105], c[105];
int main()
{
    int cas, n;
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&c[i]);
            a[c[i]]=i;
        }

        for(int j=2;j<=n;++j)l[j]=j-1;
        l[1]=n;
        for(int j=1;j<n;++j)r[j]=j+1;
        r[n]=r[0]=1;
        int now=0;
        for(int i=1;i<=n;++i)
        {
            mod[i-1]=n-i+1;
            int cnt=0;
            while(now!=a[i])
                now=r[now], ++cnt;
            b[i-1]=cnt;
            l[r[now]]=l[now];
            r[l[now]]=r[now];
        }
        solve(b,mod,n);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值