牛客OI赛制测试赛3游记

A - 数字权重

题目大意:

一个(n)位的数字。设第(i)位的数为(a_i),其中(a_1)为最高位,(a_n)为最低位,(k)为给定的数字。求同时满足满足以下两个条件的数的个数:

  1. 不含前导(0)
  2. (sum_{i=2}^n(a_i-a_{i-1})=k)

(n,|k|le10^{13})

思路:

对和式稍加变形得(a_n-a_1=k),因此我们只需要考虑(a_1)(a_n),其余数位(0sim 9)随便放即可。

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
using int64=long long;
inline int64 getint() {
    register char ch;
    register bool neg=false;
    while(!isdigit(ch=getchar())) neg|=ch=='-';
    register int64 x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return neg?-x:x;
}
constexpr int mod=1e9+7;
inline int power(int a,int64 k) {
    int ret=1;
    for(;k;k>>=1) {
        if(k&1) ret=(int64)ret*a%mod;
        a=(int64)a*a%mod;
    }
    return ret;
}
int main() {
    const int64 n=getint(),k=getint();
    if(std::abs(k)>9) {
        puts("0");
        return 0;
    }
    int ans=power(10,n-2);
    if(k>=0) ans=ans*(9-k)%mod;
    if(k<0) ans=ans*(10+k)%mod;
    printf("%d
",ans);
    return 0;
}

B - 毒瘤xor

CC-XXOR

C - 硬币游戏

题目大意:

A和B各有一行长度为(2n(nle10^6))的01序列,A先取,每次只能取两个人之前都没取过的位置,这样(n)次后两个人就得到了长度为(n)的数字串,谁的字典序大谁就赢了。若两人都按照最优策略,问最后谁赢(或平手)。

思路:

每次贪心取未被选择位置上的(1),如果有很多(1)那么优先取对方也是(1)的。用堆来维护,时间复杂度(mathcal O(nlog n))

源代码:

#include<queue>
#include<cstdio>
#include<cctype>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
inline bool getval() {
    register char ch;
    while(!isalpha(ch=getchar()));
    return ch=='U';
}
const int N=2e6+1;
bool a[N],b[N],mark[N];
struct Node {
    bool a,b;
    int id;
    bool operator < (const Node &rhs) const {
        if(a^rhs.a) return !a;
        if(b^rhs.b) return !b;
        return id<rhs.id;
    }
};
std::priority_queue<Node> q[2];
int main() {
    const int n=getint();
    for(register int i=1;i<=n*2;i++) a[i]=getval();
    for(register int i=1;i<=n*2;i++) b[i]=getval();
    for(register int i=1;i<=n*2;i++) {
        q[0].push((Node){a[i],b[i],i});
        q[1].push((Node){b[i],a[i],i});
    }
    for(register int i=1;i<=n;i++) {
        while(mark[q[0].top().id]) q[0].pop();
        a[i]=q[0].top().a;
        mark[q[0].top().id]=true;
        while(mark[q[1].top().id]) q[1].pop();
        b[i]=q[1].top().a;
        mark[q[1].top().id]=true;
    }
    for(register int i=1;i<=n;i++) {
        if(a[i]==b[i]) continue;
        puts(a[i]?"clccle trl!":"sarlendy tql!");
        return 0;
    }
    puts("orz sarlendy!");
    return 0;
}

D - 粉樱花之恋

题目大意:

求斐波那契数列前(n(nle10^{18}))项和。

思路:

找规律可以发现前(n)项和(F(n)=f(n+3)-1),因此直接矩阵快速幂或者折半公式即可。

时间复杂度(mathcal O(nlog n))

源代码:

#include<cstdio>
#include<cctype>
#include<unordered_map>
using int64=long long;
inline int64 getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int64 x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
const int64 mod=998244353;
std::unordered_map<int64,int> m;
inline int64 sqr(const int64 &x) {
    return x*x;
}
int64 f(const int64 &n) {
    if(m[n]) return m[n];
    if(n==1||n==2) return m[n]=1;
    if(n&1) return m[n]=(sqr(f(n/2+1))+sqr(f(n/2)))%mod;
    return m[n]=(f(n/2-1)*2+f(n/2))*f(n/2)%mod;
}
int main() {
    printf("%lld
",f(getint()+3)-1);
    return 0;
}

E - 符合条件的整数

题目大意:

([2^n,2^m)(n,mle65))内满足(xequiv1pmod{7})(x)个数。

思路:

使用__int128直接算即可。

源代码:

#include<cstdio>
#include<cctype>
#include<iostream>
typedef unsigned __int128 uint128;
std::ostream &operator <<(std::ostream &os,const uint128 &x) {
    if(x>=10) os<<x/10;
    return os<<int(x%10);
}
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
int main() {
    const int n=getint(),m=getint();
    std::cout<<(((uint128)1<<m)-2)/7-(((uint128)1<<n)-2)/7<<std::endl;
    return 0;
}

F - 可爱即正义

题目大意:

给你一个字符串(s),问是否能通过交换两个字符使得其不包括suqingnianloveskirito作为子串。

思路:

哈希以后统计suqingnianloveskirito的出现次数,并记录出现位置,分情况讨论即可。

源代码:

明明很多锅(比如(cnt=0)时交换前两个可能产生新的suqingnianloveskirito),但还是过了。

#include<cstdio>
#include<cstring>
using uint64=unsigned long long;
const int N=1e6+2,base=31;
char s[N];
const char t[23]="suqingnianloveskirito";
uint64 hash[N],pwr[N],tmp;
int pos[N];
inline uint64 calc(const int &i) {
    return hash[i]-hash[i-21]*pwr[21];
}
int main() {
    scanf("%s",&s[1]);
    const int n=strlen(&s[1]);
    if(n==1) {
        puts("No");
        return 0;
    }
    for(register int i=pwr[0]=1;i<=n;i++) {
        pwr[i]=pwr[i-1]*base;
        hash[i]=hash[i-1]*base+s[i]-'a'+1;
    }
    for(register int i=1;i<=21;i++) {
        tmp=tmp*base+t[i]-'a'+1;
    }
    int cnt=0;
    for(register int i=1;i<=n;i++) {
        if(i>=21&&calc(i)==tmp) {
            pos[++cnt]=i;
        }
    }
    if(cnt==0) {
        puts("Yes
1 2
");
        return 0;
    }
    if(cnt==1) {
        puts("Yes");
        printf("%d %d
",pos[1],pos[1]-1);
        return 0;
    }
    if(cnt==2) {
        puts("Yes");
        printf("%d %d
",pos[1],pos[2]-1);
        return 0;
    }
    puts("No");
    return 0;
}
原文地址:https://www.cnblogs.com/skylee03/p/9637996.html