T1 取球游戏

问题描述

现有\(N\)个小球,依次编号为\(1\)到\(N\),这些小球除了编号以外没有任何区别。从这\(N\)个小球中取出\(M\)个,请问有多少种取球方案使得在取出的\(M\)个小球中,编号最小的小球的编号为\(K\)。

考虑到方案数可能很大,请输出方案数对\(1e9+7\)去模的值。

输入格式

输入数据只有一行,包含三个整数\(N,M,K\)。

输出格式

一个整数,表示取法总数对\(1e9+7\)取模的值。

样例

样例输入1
4 2 2
样例输出1
2
样例输入2
888 222 555
样例输出2
424089030

题解

板子题,卢卡斯定理。这里给卢卡斯定理的板子写法。

  1. #include<bits/stdc++.h>
  2. #define p 1000000007
  3. #define maxn 10000005
  4. using namespace std;
  5. long long E[maxn];
  6. inline void init(){
  7. E[0]=1;
  8. for(register int i=1;i<maxn;i++)E[i]=E[i-1]*i%p;
  9. }
  10. inline long long inv(long long a,long long m){
  11. if(a==1)return a;
  12. return inv(m%a,m)*(m-m/a)%m;
  13. }
  14. inline long long lucas(long long n,long long m){
  15. long long ans=1;
  16. while(n&&m){
  17. long long a=n%p;
  18. long long b=m%p;
  19. if(a<b)return 0;
  20. ans=ans*E[a]%p*inv(E[a-b]*E[b]%p,p)%p;
  21. n/=p;
  22. m/=p;
  23. }
  24. return ans;
  25. }
  26. long long n,m,k;
  27. int main(){
  28. init();
  29. cin>>n>>m>>k;
  30. n-=k;m-=1;
  31. printf("%lld",lucas(n,m));
  32. return 0;
  33. }

T2 维修机器人

问题描述

土豪贾老师拥有\(n\)个机器人。这\(n\)个机器人排成一行,第\(i\)个机器人的身高

为\(h_i\)。贾老师发现这些机器人的身高参差不齐,看起来十分不美观,于是决定对

它们的身高进行修改。

贾老师希望修改后的机器人队伍身高值单调,形式化地说,满足下面两个条

件之一的机器人队伍是合格的队伍 。

  • \(h_1\le h_2\le ... \le h_{n-1} \le h_n\)
  • $h_1 \ge h_2\ge...\ge h_{n-1} \ge h_n $

增加第\(i\)个机器人的身高,需要的费用为\(m_1\),减小第\(i\)个机器人的身高,需

要的费用为\(m_2\)。注意,费用与是否增加和是否减小有关,与具体增加或减小的

数值无关。对于一个身高为\(5\)的机器人,把它的身高增加到\(6\)和增加到\(100\)所需

要的费用都为\(m_1\)。

贾老师希望你能帮他计算出,为了得到合格的机器人队伍,所需要花费的最

小费用是多少。 由于某些特殊的原因, 我们保证这\(n\)个机器人不同的身高不会超

过\(1,000\)个。

输入格式

输入文件共包含两行。

第一行共包括三个正整数,分别为\(n,m_1,m_2\),含义如上文所述。

第二行包含\(n\)个整数,依次表示每个机器人的身高\(h_i\)。

输出格式

共一行,包含一个整数,表示贾老师所需修理费用的最小值。

样例

样例输入1
5 2 3
1 2 3 5 4
样例输出1
2
样例输入2
15 5 7
10 10 10 10 10 9 2 8 7 6 1000 5 3 4 1
样例输出2
17

数据规模与规定

题解

首先考\(m_1=m_2\)的情况,因为升高或降低一个机器人的高度所需要的花费一样,所以我们只需要设法用最小的步数将整个序列变为单调递增或单调递减即可。此时我们可以选择求整个序列的最长不上升与最长不下降序列子序列,用\([n-max(up_{size},down_{size})]*m_1\)即可得到答案

代码如下(75)

  1. #include<bits/stdc++.h>
  2. #define maxn 50005
  3. #define inf 0x3f3f3f3f
  4. using namespace std;
  5. inline char get(){
  6. static char buf[30],*p1=buf,*p2=buf;
  7. return p1==p2 && (p2=(p1=buf)+fread(buf,1,30,stdin),p1==p2)?EOF:*p1++;
  8. }
  9. inline long long read(){
  10. register char c=get();register long long f=1,_=0;
  11. while(c>'9' || c<'0')f=(c=='-')?-1:1,c=get();
  12. while(c<='9' && c>='0')_=(_<<3)+(_<<1)+(c^48),c=get();
  13. return _*f;
  14. }
  15. bool cmp(long long a,long long b){
  16. return a>b;
  17. }//重载upper_bound
  18. long long n,m1,m2;
  19. long long a[maxn],f[maxn],g[maxn];
  20. long long ans1,ans2;
  21. long long cas[maxn];
  22. int main(){
  23. //freopen("robot.in","r",stdin);
  24. //freopen("robot.out","w",stdout);
  25. n=read();m1=read();m2=read();
  26. for(register long long i=1;i<=n;i++)a[i]=read();
  27. if(m1==m2){
  28. for(register long long i=0;i<maxn;i++)f[i]=0,g[i]=0x3f3f3f3f;
  29. g[0]=0;
  30. for(register long long i=1;i<=n;i++){
  31. f[i]=upper_bound(g+1,g+1+ans1,a[i])-g;
  32. g[f[i]]=a[i];
  33. ans1=max(ans1,f[i]);
  34. }
  35. //cout<<ans1<<endl;
  36. for(register long long i=0;i<maxn;i++)f[i]=0,g[i]=0x3f3f3f3f;
  37. g[0]=0;
  38. for(register long long i=1;i<=n;i++){
  39. f[i]=upper_bound(g+1,g+1+ans2,a[i],cmp)-g;
  40. g[f[i]]=a[i];
  41. ans2=max(ans2,f[i]);
  42. }
  43. //cout<<ans2<<endl;
  44. printf("%lld",(n-max(ans1,ans2))*m1);
  45. return 0;
  46. }
  47. return 0;
  48. }

注意到题目的关键条件,不同的\(h_i\)取值不超过$T=1000 $个。考虑将

读入数据先离散成\(1——1000\)的整数,接下来用动态规划解决。设\(dp[i][j]\)表示将前 i 个机

器人改为单调不减,第\(i\)个机器人的身高变为\(j\)所需的最小费用。则\(dp[i][j]=min(dp[i-
1][k])+change(a[i],j)(1≤k≤j)\)。其中\(change(x,y)\)表示把一个机器人的身高从\(x\)改为\(y\)所需的

费用,这个值只能是\(m_1\)或者0或者\(m_2\) 。

按上述做法时间复杂度为\(O(nT^2 )。\)注意到对于当前的决策位置,\(k\)的可取值越来越

多, 因此可以再同时维护$ min(dp[i-1][k])$, 这样转移代价变成 \(O(1)\), 时间复杂度变为\(O(nT)\),

可以获得\(100\)分。

  1. #include <bits/stdc++.h>
  2. #define maxn 50005
  3. #define maxt 1005
  4. #define maxl 1000005
  5. #define inf 0x3f3f3f3f
  6. using namespace std;
  7. int n,m1,m2;
  8. int p[maxn];
  9. int t[maxt];
  10. bool vis[maxl];
  11. int level[maxl];
  12. int cnt;
  13. int now,pre;
  14. int minv;
  15. int dp[2][maxt];
  16. int ans=inf;
  17. void init(){
  18. scanf("%d %d %d",&n,&m1,&m2);
  19. for (int i=1;i<=n;i++){
  20. scanf("%d",&p[i]);
  21. if (!vis[p[i]]) t[++cnt]=p[i];
  22. vis[p[i]]=true;
  23. }
  24. sort(t+1,t+cnt+1);
  25. for (int i=1;i<=cnt;i++) level[t[i]]=i;
  26. for (int i=1;i<=n;i++) p[i]=lev el[p[i]];
  27. }
  28. inline int getdp(){
  29. now=1;
  30. for (int i=1;i<=cnt;i++){
  31. if (i>p[1])dp[now][i]=m1;
  32. else if (i<p[1])dp[now][i]=m2;
  33. else dp[now][i]=0;
  34. }
  35. for (int i=2;i<=n;i++){
  36. now=1-now;pre=1-now;
  37. minv=dp[now][1]=dp[pre][1];
  38. for (int j=2;j<=cnt;j++){
  39. minv=min(minv,dp[pre][j]);
  40. dp[now][j]=minv;
  41. }
  42. for (int j=1;j<p[i];j++)dp[now][j]+=m2;
  43. for (int j=p[i]+1;j<=cnt;j++)dp[now][j]+=m1;
  44. }
  45. int res=inf;
  46. for (int i=1;i<=cnt;i++)res=min(res,dp[now][i]);
  47. return res;
  48. }
  49. void solve(){
  50. ans=getdp();
  51. reverse(p+1,p+n+1);
  52. ans=min(ans,getdp());
  53. printf("%d\n",ans);
  54. }
  55. int main(){
  56. freopen ("robot.in","r",stdin);
  57. freopen ("robot.out","w",stdout);
  58. init();
  59. solve();
  60. return 0;
  61. }

T3 下标

问题描述

Bella 同学在学习 C++的时候,有一天意外地把\(a[i]\)写成了\(i[a]\),发现程

序居然还能正常地编译和运行!(如果你现在做题做累了,不妨拿出半分钟时间

试试看这是不是真的! )

通过进一步的实验,Bella认为,对于任意的两个合法的表达式\(A\)和\(B\),表

达式\(A[B]\)与\(B[A]\)是等价的。

并且,等价是具有传递性的。例如,\(a[b[c]]\)和\(c[b][a]\)是等价的,因为这

两个表达式都和\(a[c[b]]\)等价。

现在给你一些合法的表达式,其中只会出现小写字母与方括号。你需要对每

个表达式进行若干次这样的等价变换,得到一个字典序尽可能小的表达式。

更正式地,所有可能出现的表达式恰好能由如下上下文无关文法从符号

Expr生成:

\[Expr -> Term | Expr [ Expr ]
\]

\[Term -> Char | Char Term
\]

\[Char -> a | b | ... | z
\]

而每次的等价变换,是将一个形如\(Expr1[Expr2]\)的式子变为

\(Expr2[Expr1]\),并且要求\(Expr1\)与\(Expr2\)都能由\(Expr\)生成。

输入格式

输入文件的第一行只包含一个正整数\(T\),表示该输入文件的数据个数。

接下来\(T\)行,每行一个字符串,表示一个合法的表达式。

输出格式

对于每个输入数据,输出一行,表示所能得到的字典序最小的表达式。

样例

样例输入
aaa[bbb]
a[b[abbb]]
b[a[azzz]]
x[a][b[a]]
样例输出
aaa[bbb]
a[abbb[b]]
a[azzz][b]
a[b]a[x]]

题解

将输入字符串的括号进行匹配,找到每个右括号对应的左括号。记

匹配后的字符串为\(S=aaa[A][B]\),其中\(A\)和\(B\)都为\(expr,B\)右侧的括号为整个字符串

的结尾,\(B\)左侧的括号是与最后的右括号匹配的左括号。定义过程\(solve(S)\)表示寻找

字符串 S 的最小字典序表示,首先递归调用\(solve(aaa[A])与solve(B)\)然后再比较

\(aaa[A][B]\)与\(B[aaa[A]]\)的字典序, 将\(S\)变为这两者中较小的一个。时间复杂度\(O(n^2)\),

期望得分 80 分。在 80 分做法的基础上,使用链表控制整个字符串,记录每个字符串

的后继元素,这可以使得等价变换的时间复杂度变为\(O(1)\)即可。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <string>
  4. #include <cstring>
  5. using namespace std;
  6. const int maxn = 100010;
  7. int sta[maxn], len, top, mp[maxn];
  8. string s;
  9. string work(int l, int r){
  10. string res = "";
  11. if(s[r] != ']'){
  12. for(int i = l; i <= r; i++){
  13. res += s[i];
  14. }
  15. return res;
  16. }
  17. string s1 = work(l, mp[r] - 1);
  18. string s2 = work(mp[r] + 1, r - 1);
  19. if(s1 > s2){
  20. swap(s1, s2);
  21. }
  22. res += s1;
  23. res += '[';
  24. res += s2;
  25. res += ']';
  26. return res;
  27. }
  28. int main(){
  29. int t;
  30. scanf("%d", &t);
  31. while(t--){
  32. cin >> s;
  33. len = s.size();
  34. for(int i = len - 1; i >= 0; i--){
  35. if(s[i] == ']'){
  36. sta[top++] = i;
  37. }
  38. if(s[i] == '['){
  39. mp[sta[--top]] = i;
  40. }
  41. }
  42. cout << work(0, len - 1) << endl;;
  43. }
  44. return 0;
  45. }

CCF-NOIP-2018 提高组(复赛) 模拟试题(三)的更多相关文章

  1. CCF-NOIP-2018 提高组(复赛) 模拟试题(九)(2018 CSYZ长沙一中)

    T1 Circle [问题描述] 小 w 的男朋友送给小 w 一个 n 个点 m 条边的图,并且刁难小 w 要她找出点数最少的正环. 小 w 不会做,于是向你求助. [输入格式] 第一行两个整数\(n ...

  2. 冲刺NOIP2015提高组复赛模拟试题(五)2.道路修建

    2.道路修建 描述 Description liouzhou_101最悲痛的回忆就是NOI2011的道路修建,当时开了系统堆栈,结果无限RE… 出于某种报复心理,就把那题神奇了一下: 在 Z星球上有N ...

  3. CCF-NOIP-2018 提高组(复赛) 模拟试题(四)

    T1 贪吃蛇 [问题描述] 贪吃蛇是一个好玩的游戏.在本题中,你需要对这个游戏进行模拟. 这个游戏在一个 \(n\) 行 \(m\) 列的二维棋盘上进行. 我们用 \((x, y)\) 来表示第 \( ...

  4. CCF-NOIP-2018 提高组(复赛) 模拟试题(七)

    T1 Adjoin [问题描述] 定义一种合法的\(0-1\)串:串中任何一个数字都与\(1\)相邻.例如长度为$ 3 的 0-1 $串中,\(101\)是非法的,因为两边的\(1\)没有相邻的\(1 ...

  5. CCF-NOIP-2018 提高组(复赛) 模拟试题(一)

    T1 帽子戏法 问题描述 小 Y 有一个\(n*n*n\)的"帽子立方体" ,即一个\(n\)层的立方体,每层的帽子都 可以排成\(n*n\)的矩阵. "帽子立方体&qu ...

  6. 破译情报-NOIP2016提高组复赛模拟试题

    [题目描述] 最近国安人员截获了一份 RB 国的秘密情报, 全文都是经过加密的,每个单 词都很长.破译人员想到先把单词化简一下,方法是把每个单词尽量取短些的前 缀,但所取的前缀不能是其他单词的前缀. ...

  7. 冲刺NOIP2015提高组复赛模拟试题(五) 3.破坏基地

    3.破坏基地 描述 Description 在Z国和W国之间一直战火不断. 好不容易,W国的间谍把完整的Z国的军事基地的地图到手了. 于是W国决定再次出击,一举击破Z国的防线. W国认真研究了Z国的地 ...

  8. 冲刺NOIP2015提高组复赛模拟试题(五)1.数学作业

    1. 数学作业 [问题描述] 路人丙的数学老师非常乏力,他喜欢出一些非常乏力的数学题来为难乏力的学生们.这次数学老师布置了一堆的数学题作为作业,而且这些数学题有个共同的特点是都求C(N,M)中不同质因 ...

  9. CCF-NOIP-2018 提高组(复赛) 模拟试题(五)

    T1 相遇 [问题描述] 在一场奇怪的梦里,小 Y 来到了一个神奇的国度.这个国度可以用一根数轴表示,小 Y 在 N 处,而小 Y 想吃的美食在 K 处.小 Y 有两种方式移动, 一种叫做步行, 一种 ...

随机推荐

  1. 用selenium爬动态网页

    0-安装 我用python2.7,用pip安装selenium即可,phantomjs到官网下载安装,也不难. 1-主要参考的几篇文章 Python爬虫利器四之PhantomJS的用法 Python爬 ...

  2. asp.net 在repeater控件中加按钮

    在repeater中加入方法有两种方法: 第一种:是对repeater控件的行添加OnItemCommand事件,添加方法也是有两种 1.在设计页面中,选中repeater控件右击==>属性== ...

  3. H5新增API和操作DOM

    博客原文:https://dobinspark.com.cn/ H5-dom扩展 获取元素 document.getElementsByClassName ('class'); //通过类名获取元素, ...

  4. 技巧:Vimdiff 使用

    技巧:Vimdiff 使用 各种 IDE 大行其道的同时,传统的命令行工具以其短小精悍,随手可得的特点仍有很大的生存空间,这篇短文介绍了一个文本比较和合并的小工具:vimdiff.希望能对在 Unix ...

  5. 如何在linux中创建虚拟环境

    安装虚拟环境的命令 : sudo pip install virtualenv sudo pip install virtualenvwrapper 安装完虚拟环境后,如果提示找不到mkvirtual ...

  6. yii 自带RBAC

    common:中加 'authManager' => [ 'class' => 'yii\rbac\DbManager', 'itemTable' => 'auth_item', ' ...

  7. Laravel-admin 当使用Form组件hasMany的时候 进行编辑出现错误 foreach错误的时候解决方案

    我的关联关系原名是 goodImage 修改成 image 之后解决问题 分析得出应该是  laravel会将goodImage 转成 good_image字段  这样就foreach会报错  所以出 ...

  8. flask钩子

    请求钩子  从请求到响应的过程中,设置了一些方法来实现某些功能 before_first_request   在处理第一个请求前运行 before_request  在每次请求前运行 after_re ...

  9. Windows和Linux系统下,虚拟环境安装的全面说明和详细步骤

    虚拟环境的创建和使用 用途: ​ 1.在同一台电脑安装同一个包的不同版本 2.记录项目所用的所有的包的版本,方便部署. 如何使用: 1.创建虚拟环境 mkvirtualenv 虚拟环境名 -p pyt ...

  10. 【Java】关于Spring框架的总结 (二)

    上文提到了 Spring 的 IoC 特性和 AOP 特性,只提到个别的实现方法.本文将对 IoC 和 AOP 其他方法进行讲解. 多种方式实现依赖注入 1.设值注入 上文中使用的注入方法:通过 se ...