牛客OI赛制测试赛3(ABCDEF)

A - 思维、快速幂

题目描述

小a有一个n位的数字,但是它忘了各个位上的数是什么,现在请你来确定各个位上的数字,满足以下条件:

设第i位的数为ai,其中a1为最高位,an为最低位,K为给定的数字

1. 不含前导0
2.

请你求出满足条件的方案数

输入描述:

两个整数N, K

若存在无解的情况,请输出0

输出描述:

一个整数表示答案,对109 + 7取模

示例1

输入

复制

2 3

输出

复制

6

说明

满足条件的数有:14, 25, 36, 47, 58, 69

示例2

输入

复制

2 -3

输出

复制

7

说明

满足条件的数有:41, 52, 63, 74, 85, 96, 30

示例3

输入

复制

4 3

输出

复制

600

说明

可能的方案有:1234, 1334

示例4

输入

复制

4 -3

输出

复制

700

备注:

对于30%的数据:n, |k| = 5
对于60%的数据:n, |k| ≤ 1000

对于100%的数据:n, |k| ≤ 1013

保证n > 1

思路:

由题可知,满足an-a1=k,-9=<an-a1<=8,k不在此范围的可以输出0了,在的话,枚举a1,an的情况,再乘10^(n-2)

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#include<string>
#include<cstring>
using namespace std;
#define ll long long
const int mod=1e9+7;

ll n,k;

ll pow_mod(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)res=(res%mod*a%mod)%mod;
        b>>=1;
        a=(a%mod*a%mod)%mod;
    }
    return res%mod;
}

int main(){
    while(scanf("%lld%lld",&n,&k)!=EOF){
        if(k>8||k<-9)printf("0\n");
        else{
            ll ans=0;
            for(int i=1;i<=9;i++){//a1的值
                int an=i+k;
                if(an<10&&an>=0){
                    ans++;
                }
            }
            ans=(ans*pow_mod(10,n-2))%mod;
            printf("%lld\n",ans);
        }
    }
}

B - 贪心、位运算

题目描述

小a有N个数a1, a2, ..., aN,给出q个询问,每次询问给出区间[L, R],现在请你找到一个数X,使得
1、
2、最大,表示异或操作(不懂的请自行百度)
 

输入描述:

第一行一个整数N,表示序列的长度
第二行N个整数,表示序列内的元素
第三行一个整数q,表示询问的个数
接下来q行,每行两个整数[L, R],表示询问的区间

输出描述:

输出q行,每行一个整数表示答案

若有多组可行解,请输出较小的解

示例1

输入

复制

5 
4 78 12 1 3
3
2 5
1 4
3 3

输出

复制

2147483632
2147483635
2147483635

备注:

对于30%的数据,n , q ≤ 10
对于60%的数据,n , q ≤ 1000

对于100%的数据,n, q ≤ 105

保证ai < 231

思路:

注意看题啊qwq,求得是x与区间内各个数异或之和的最大值,不是分别与他们异或的最大值。

先求数组sum[i][j]:=从1到第i个数,倒数j位上的1的个数

我们用贪心的思想,若1的个数少于n的一半,那么我们让x对应的位为1(1^0=1,0的个数多),若大于等于,就让x对应的位为0(等于是因为,题中数有相同解输出最小值)

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#include<string>
#include<cstring>
using namespace std;
#define ll long long
const int N=1e5+5;
ll a[N];
int sum[N][35];//所有数的倒数第i位的1的值得个数
int main(){
    int n,q;
    scanf("%d",&n);
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        for(int j=0;j<31;j++){
            sum[i][j]=sum[i-1][j]+(a[i]&1);
            a[i]>>=1;
        }
    }
    scanf("%d",&q);
    int l,r;
    while(q--){
        scanf("%d%d",&l,&r);
        int que=r-l+1;
        int cnt=0;
        ll ans=0;
        for(int i=0;i<31;i++){
            if((sum[r][i]-sum[l-1][i])*2<que)ans|=1<<i;
        }
        printf("%lld\n",ans);
    }

}

C - 博弈论

题目描述

 有一天clccle在机房里和sarlendy玩游戏,游戏的规则是这样的,在clccle和sarlendy的面前有两行长度为2n的硬币序列,共4n枚硬币,从clccle开始取,每次只能取两个人之前都没取过的位置的硬币,如果所取硬币朝上(U)的话记为1,所取硬币朝下(D)的话记为0,这样n次后两个人就得到了长度为n的数字串,谁的数字大谁就赢了,当然也存在平局的情况,当然这两个人都非常的睿智,现在clccle想知道,Ta有没有必胜策略?如果有的话就输出“clccle trl!”,没有的话输出“sarlendy tql!”,特别的,平局输出“orz sarlendy!”。

输入描述:

第一行,一个数字n(N<=1000000)
第二,三行,每行各一个长度为2n的字符串

输出描述:

一行 输出   clccle trl!或sarlendy tql!或orz sarlendy!

示例1

输入

复制

3
UDUDUU
DUDUUD

输出

复制

clccle trl!

说明

clccle先取5,sarlendy取4,clccle取6,sarlendy取2,clccle取1,sarlendy取3
此时clccle得到的数字为111,sarlendy得到的数字为110
因为111>110 所以说输出clccle trl!

备注:

不保证数据有梯度(但肯定没有极限数据)

思路:

分情况讨论,有一点需要注意的是,A是先手,当它的1的个数比B少1时,它能取得平局的情况

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#include<string>
#include<cstring>
using namespace std;
#define ll long long
const int N=1e5+5;
char s1[2000005],s2[2000005];
int main(){
    int n;
    string s1,s2;
    scanf("%d",&n);
    cin>>s1>>s2;
    int a=0,b=0,both=0;
    for(int i=0;i<2*n;i++){
        if(s1[i]=='U'&&s2[i]=='U')both++;
        else if(s1[i]=='U')a++;
        else if(s2[i]=='U')b++;
    }
    if(both%2==1){
        if(a>=b)printf("clccle trl!\n");
        else if(b==a+1||b==a+2)printf("orz sarlendy!\n");
        else printf("sarlendy tql\n");
    }
    else{
        if(a>b)printf("clccle trl!\n");
        else if(a==b||b==a+1)printf("orz sarlendy!\n");
        else printf("sarlendy tql\n");
    }
}

D - 矩阵快速幂

题目描述

qn是个特别可爱的小哥哥,qy是个特别好的小姐姐,他们两个是一对好朋友 [ cp (划掉~)
又是一年嘤花烂漫时,小qn于是就邀请了qy去嘤花盛开的地方去玩。当qy和qn来到了田野里时,qy惊奇的发现,嘤花花瓣以肉眼可见的速度从树上长了出来。
仔细看看的话,花瓣实际上是以一定规律长出来的,而且,每次张成新的花瓣的时候,上一次的花瓣就会都落到地上,而且不会消失。
花瓣生长的规律是,当次数大于等于2时,第i次长出来的花瓣个数和上一次张出来的花瓣个数的差是斐波那契数列的第i-1项。初始的时候地上没有花瓣,树上的花瓣个数为1,第一次生长的花瓣个数为1。初始的那个花瓣就落到了地上

现在,小qn想知道,经过k次生长之后,树上和地上的总花瓣个数是多少?

ps:斐波那契数列:

    f[1]=f[2]=1;f[i]=f[i-1]+f[i-2] (i>=2且i   N+) 

输入描述:

一行一个数k

输出描述:

一行一个数m,表示第k次生长过后,树上和地上的总花瓣数是多少。由于答案会很大,请你将答案mod 998244353后输出

示例1

输入

复制

4

输出

复制

12

说明

第一次:树上1,地上1.第二次树上2,地上1+1,第三次树上3,地上1+1+2,第四次树上5,地上1+1+2+3。总共12个

示例2

输入

复制

5

输出

复制

20

说明

第五次树上8,地上1+1+2+3+5。总共20个

备注:

对于0%的数据,有k=样例
对于20%的数据,有k<=1'000
对于60%的数据,有k<=1'000'000
对于80%的数据,有k<=1'000'000'000
对于100%的数据,有k<1'000'000'000'000'000'000

思路:

我们可以发现,所求得是斐波那契数列的前n+1项和,即fn+3-1

快速求斐波那契数列:

会爆int!!!

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#include<string>
#include<cstring>
using namespace std;
#define ll long long
const int mod=998244353;

struct mat{
    ll m[2][2];
}ans,base;

mat multi(mat a,mat b){
    mat tmp;
    for(int i=0;i<2;i++){
        for(int j=0;j<2;j++){
            tmp.m[i][j]=0;
            for(int k=0;k<2;k++){
                tmp.m[i][j]=(tmp.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
            }
        }
    }
    return tmp;
}

ll fast_mod(ll n){
    base.m[0][0]=base.m[0][1]=base.m[1][0]=1;
    base.m[1][1]=0;
    ans.m[0][0]=ans.m[1][1]=1;
    ans.m[0][1]=ans.m[1][0]=0;
    while(n){
        if(n&1)ans=multi(ans,base);
        base=multi(base,base);
        n>>=1;
    }
    return (ans.m[0][1]-1+mod)%mod;
}

int main(){
    ll n;
    while(scanf("%lld",&n)!=EOF){
        printf("%lld\n",fast_mod(n+3));
    }

}

E - 快速幂、打表

题目描述

众所周知,某个被共青团点名的学校的机房里有一个蒟蒻,名字叫做clccle,因为文化课成绩不好而经常被班主任gank,这次他遇到了一个很困(rui)难(zhi)的数学题,因为clccle非常辣鸡,所以他想到了聪明的你,你能帮Ta解决这个问题吗?

给定两个整数N,M,表示区间 [2N,2M),请求出在这个区间里有多少个整数i满足i % 7=1

输入描述:

一行,两个整数N,M 0<=N<M<=65

输出描述:

一个数字ans,表示满足条件的数字的个数

示例1

输入

复制

2 3

输出

复制

0

说明

在区间[22,23 )里满足条件的整数的个数为零  ,(4,5,6,7,8因为在开区间边界上所以不做考虑)

思路:

这题的思路很直接,就是快速幂,令a=2^n,b=2^m

区间为前闭后开,所以我们a--;b--;又因为题中是求模7余1的数的个数,所以(b-1)/7-(a-1)/7

n、m为63,64,65时爆ll了,我看别人的代码是在数的第19位后加了ll(但是不知道为什么)

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#include<string>
#include<cstring>
using namespace std;
#define ll long long
const int N=1e5+5;
ll ans5=5270498306774157605ll,ans4=2635249153387078803ll,ans3=1317624576693539401ll;
ll mod_pow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)res=a*res;
        a=a*a;
        b>>=1;
    }
    return res;
}

ll cal(ll x){
    if(x==0)return 0;
    if(x==63)return ans3;
    if(x==64)return ans4;
    if(x==65)return ans5;
    return (mod_pow(2,x)-2)/7;
}
int main(){
    ll n,m,ans,a,b;
    scanf("%lld%lld",&n,&m);
    printf("%lld\n",cal(m)-cal(n));
}

F - 思维

题目描述

小可爱是个可爱的女孩子(nzdl)。

众所周知,小可爱在物竞初赛时候有两道大题没有做出来,所以,可爱的小可爱(qwq)便沉浸在了毒瘤之中——无法接受在任何地方看到"suqingnianloveskirito"这个东西。然而,这时候从SD某处送来了一封安慰信(情书),信的内容是一个26个小写拉丁字母组成的字符串s。这封信提前被wyxdrqc劫了下来(没错,就是这个劫),他打开了这封信,结果发现了满篇的"suqingnianloveskirito"所以他想篡改这封信。

由于他的能力有限,所以他只能把这个字符串的其中两个位置上的字符互换,而且只能操作一次。

他现在想问你,通过他的操作能不能使"suqingnianloveskirito"不是这个字符串的子串。

输入描述:

一行一个字符串s

输出描述:

如果他能通过只交换其中的两个位置上的字符使"suqingnianloveskirito"不是交换后的字符串的子串,则在第一行输出一个Yes,之后一行输出两个数d1,d2,表示你的方案是把原字符串在位置d1和位置d2上的字符互换,字符串的第一个字符的位置是1。
如果他不管交换那两个字符都不能满足条件,直接输出一行No。

示例1

输入

复制

suqingnianloveskiritosuqingnianloveskiritosuqingnianloveskiritothemostimportantthingneedsaidatleastthreetimes

输出

复制

No

示例2

输入

复制

suqingnianloveskiritosomuch

输出

复制

Yes
1 2

备注:

对于100%数据,有字符串的长度<=1000000
对于10%数据,有测试数据的答案=样例。
并且你的方案中,不能出现d1=d2的情况。
如果有多种可行方案,输出任何一种即可得分

思路:

当长度小于21,直接输出1 2

否认的话判断模式串在主串出现的次数和位置

当次数大于2时输出No

次数等于2时,输出第一个位置和第二个位置+1

次数等于1时,输出第一个位置和第一个位置+1

次数等于0时,交换有可能使次数变为非0,(这点需要注意!)

我们先交换位置1,2 若此时次数是0,可输出1 2

若非0,输出1 3

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#include<string>
#include<cstring>
using namespace std;
#define ll long long
const int mod=998244353;
const int N=1000005;
int a[N];
int main(){
    string s;
    string t="suqingnianloveskirito";
    while(cin>>s){
        int len=s.length();
        if(len<21){
            printf("Yes\n1 2\n");
            continue;
        }
        int ci=0,pos=0;
        int k=0;
        while(1){
            pos=s.find(t,pos);
            if(ci>2)break;
            if(pos!=-1){
                ci++;
                a[k++]=pos+1;
                pos=pos+21;
            }
            else break;
        }
        if(ci<=2&&ci>0){
            printf("Yes\n");
            if(ci==1)printf("%d %d\n",a[0],a[0]+1);
            if(ci==2)printf("%d %d\n",a[0],a[1]+1);
        }
        else if(ci==0){
            printf("Yes\n");
            swap(s[0],s[1]);
            if(s.find(t,0)==-1)printf("1 2\n");
            else printf("1 3\n");
        }
        else printf("No\n");
    }
}

猜你喜欢

转载自blog.csdn.net/m0_37579232/article/details/82715311