牛客IOI周赛17-普及组 题解

嗯,这次比赛证明了,打得快不一定排名就高。。。qwq大佬们的程序跑得好快啊

A.夹娃娃

狂爆手速拿下一血,成就感++

题目就是给你个数列,让你求若干个区间的和。

直接预处理出前缀和,然后回答完事。。。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+1;
int s[N];
int main(){
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i){
        scanf("%d",&s[i]);s[i]+=s[i-1];
    }
    while(k--){
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%d\n",s[r]-s[l-1]);
    }
    system("pause");
    return 0;
}

哪怕加了快读快写,还是比大佬们的总用时都长

B.莫的难题

做这道题,只需要字典序学得好,懂排列组合初步就行了。。。

我们先预处理出所有的组合数的值(直接递推式,也就是做一遍杨辉三角就好了)

然后,我们现在就只需求最终第k小的字符串即可。

我们先枚举最终字符串的长度。

注意到,长度为1的有5个,长度为2的有25...长度为x的有个。

(每个位置5种选法,乘法原理相乘即可)

于是,我们找到最小的i,满足(也就是所有长度小于等于i的字符串的个数比k大了)

那么,第k小的字符串一定在这里面,又由于i是最小的,所以第k小的字符串长度即为i

然后,我们令(这个的意思是,第k小的字符串在所有长度为i的字符串中的排名)

我们设函数dfs(x,y)的作用是求出长度为y的字符串中排名为x的字符串(think function~)

那么,答案肯定就是dfs(p,i)了

现在,我们只需要实现这个函数即可。

实现dfs(x,y)

现在,我们开始愉快的枚举每一位。

我们由小到大枚举,即按照1,2,3,5,9的顺序枚举。

当我们枚举到1时,我们算下这一位为1时,剩下的位可以凑出几个串(由之前的推导可以知道,一共可以凑出个串)

我们比较下x和的大小关系。

若x小于等于它,那么,很明显的,我们要求的串肯定包含在当前位为1所形成的所有串中。

若x大于它,怎么办呢?很明显,要求的串肯定就不包含在里面了,那么,我们肯定就要枚举另一个数2了。

不过,需要注意的是,我们枚举2时,我们就相当于把开头为1的所有情况都忽视掉了,那么,我们需要求的串在忽略所有1开头的串后的所有串中的排名就会变化,因为舍弃的,以1为开头的串都会比之后的串小,所以,我们要求的串在忽略所有1开头的串后的所有的串的排名即为:,所以我们令即可(其实就是类似于用数据结构求kth)

然后,类似1的方法,我们依次枚举2,3,5,9即可。

那么,如果我们确定了当前位,之后怎么做呢?

肯定就是去枚举下一位辣!

做一遍dfs(x,y-1)即可。

当y=0时,return就好了

代码:

#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int N=101;
int C[N][N];int num[6]={0,1,2,3,5,9};
inline int ksm(int x,int y){
    int ans=1;
    while(y){
        if(y&1)ans*=x;
        x*=x;
        y>>=1;
    }
    return ans;
}
inline void print(int x,int lon){
    if(!lon)return;
    for(int i=1;i<=5;++i){
        int tot=ksm(5,lon-1);
        if(x<=tot){
            printf("%d",num[i]);
            print(x,lon-1);
            return;
        }else{
            x-=tot;
        }
    }
}
int main(){
    for(int i=1;i<N;++i){
        C[i][0]=C[i][i]=1;
    }
    for(int i=2;i<N;++i){
        for(int j=1;j<i;++j){
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
        }
    }
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        int tot=C[n][m],lon=0,sum=0,tp=1;
        for(int i=1;;++i){
            tp*=5;
            if(tp>=tot){
                lon=i;
                break;
            }
            tot-=tp;
        }
        print(tot,lon);putchar('\n');
    }
    system("pause");
    return 0;
}

C.不平衡数组

一开始太蠢了,以为是个带后悔的贪心

我们设dp[i][0/1]表示,保证前i个数合法的情况下,第i个数是否+1的最小花费

那么,我们只需要分当前的i是否+1,和i-1是否+1,来转移方程即可。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+1;
#define int long long
int a[N],b[N];
int dp[N][2];//前i个数符号,第i个数是否+1的最小代价
signed main(){
    int n;long long ans=0;
    scanf("%lld",&n);
    for(int i=1;i<=n;++i){
        scanf("%lld%lld",&a[i],&b[i]);
    }
    memset(dp,0x3f3f,sizeof(dp));
    dp[1][0]=0,dp[1][1]=b[1];
    for(int i=2;i<=n;++i){
        if(a[i]!=a[i-1]){
            dp[i][0]=min(dp[i][0],dp[i-1][0]);
        }
        if(a[i]!=a[i-1]+1){
            dp[i][0]=min(dp[i][0],dp[i-1][1]);
        }
        if(a[i]+1!=a[i-1]){
            dp[i][1]=min(dp[i][1],dp[i-1][0]+b[i]);
        }
        if(a[i]+1!=a[i-1]+1){
            dp[i][1]=min(dp[i][1],dp[i-1][1]+b[i]);
        }
    }
    printf("%lld",min(dp[n][0],dp[n][1]));
    return 0;
}

D.数列统计

通过打表发现,答案即为x-1维前缀和的第l个数,即C(x+l-2,x-1)

Ps:

0维前缀和的每一项都是1

k维前缀和()就是对k-1维前缀和再做一遍前缀和

咳咳,我们来推导下吧。。。

我们设表示以i()结尾,长度为j的数列的个数。

那么,明显有转移

(因为我们只能放一个i进去)

注意到,dp方程的递推式,和多维前缀和的递推式完全一样,并且,当j=1时,正好即为0维前缀和的值。

所以,我们带公式即可。

注意到T很大,n不是很大,所以我们预处理出所有的阶乘和逆元阶乘,然后回答即可

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+1,mod=911451407;
int s[N],g[N],dp[11][11];
inline int C(int x,int y){
    int res=(1LL*s[x]*g[y])%mod;
    res=(1LL*res*g[x-y])%mod;
    return res;
}
int main(){
    s[0]=s[1]=g[0]=g[1]=1;
    for(int i=2;i<N;++i){
        s[i]=(1LL*s[i-1]*i)%mod;
        g[i]=(1LL*g[mod%i]*(mod-mod/i))%mod;
    }
    for(int i=2;i<N;++i){
        g[i]=(1LL*g[i-1]*g[i])%mod;
    }
    int T;
    scanf("%d",&T);
    while(T--){
        int l,x;
        scanf("%d%d",&l,&x);
        printf("%d\n",C(x+l-2,x-1));
    }
    return 0;
}
全部评论
强 但你的代码好像某些字符被转义了 没法看
点赞 回复 分享
发布于 2020-06-05 21:41

相关推荐

来,说点可能被同行“骂”的大实话。🙊当初接数字马力Offer时,朋友都说:“蚂蚁的“内包”公司?你想清楚啊!”但入职快一年后的今天,我反而对他有了不一样的看法!🔹&nbsp;是偏见?还是信息差!之前没入职之前外面都在说什么岗位低人一等这类。实际上:这种情况不可至否,不能保证每个团队都是其乐融融。但我在的部门以及我了解的周边同事都还是十分好相处的~和蚂蚁师兄师姐之间也经常开一些小玩笑。总之:身份是蚂蚁公司给的,地位是自己挣的(一个傲娇女孩的自述)。🔹&nbsp;待遇?玩的就是真实!试用期工资全额发!六点下班跑得快(早9晚6或者早10晚7,动态打卡),公积金顶格交。别听那些画饼的,到手的钱和下班的时间才是真的(都是牛马何必难为牛马)。🔹&nbsp;能不能学到技术?来了就“后悔”!我们拥有权限直通蚂蚁知识库,技术栈多到学不完。说“学不到东西”的人,来了可能后悔——后悔来晚了(哈哈哈哈,可以不学但是不能没有)!💥&nbsp;内推地址:https://app.mokahr.com/su/ueoyhg❗我的内推码:NTA6Nvs走我的内推,可以直达业务部门,面试流程更快速,进度可查!今天新放HC,之前挂过也能再战!秋招已经正式开始啦~机会就摆在这,敢不敢来试一试呢?(和我一样,做个勇敢的女孩)
下午吃泡馍:数字马力的薪资一般哇,5年经验的java/测试就给人一万出头,而且刚入职第三天就让人出差,而且是出半年
帮你内推|数字马力 校招
点赞 评论 收藏
分享
评论
5
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务