嗯,这次比赛证明了,打得快不一定排名就高。。。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; }