比赛传送门:点我
A题:出题
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
小B准备出模拟赛。
她把题目按难度分为四等,分值分别为6,7,8,9。
已知小B共出了m道题,共n分。
求小B最少出了多少道6分题。
她把题目按难度分为四等,分值分别为6,7,8,9。
已知小B共出了m道题,共n分。
求小B最少出了多少道6分题。
输入描述:
两个正整数n,m
输出描述:
一个数,表示答案。
若无解,输出"jgzjgzjgz"。
示例1
输入
34 5
输出
1
示例2
输入
32 5
输出
3
示例3
输入
5 1
输出
jgzjgzjgz
思路:
读完题目,感觉是个解方程的题。首先确定无解的情况:m*6>n或者m*9<n 即:n太小了,全都用6都凑不齐或者n太大了,全都用9都凑不到那么大。
再讨论可以的情况。在可以的情况下,n可以先减去6*m。那么题目就变成了用0、1、2、3,这四个数,使用m次凑成n-m*6。(肯定能凑成,因为有0存在)
因为题目要求的是,使用6的最少次数,转换到上面的场景,就是使用0的最少次数。
思路转变为,用尽量多的次数,1、2、3三个数凑成n-m*6。那么用0就变少了。
一个三可以变成1,2,3个贡献(3,1+2,1+1+1)
两个三可以变成[2,9]里面任何的一个。
k个三可以变成[k,3*k]里面任何一个。
假设刚开始使用最多个3,其他的用1来填补,分别用Use_1,use_3表示使用了3和1的个数。
use_3 = (n-m*6)/3, use_1 = n-n3*3;
然后开始拆掉3。
分两种情况:m-use_1>=3*use_3。就是把全部的3拆了都不够,剩下的就用0来填了。
m-use_1在[use_3,3*use_3]这个区间里面,则不需要0了,已经可以用3拆出所需要的。
代码:
#include<iostream> #include<algorithm> #include<cstdlib> #include<sstream> #include<cstring> #include<cstdio> #include<string> #include<deque> #include<stack> #include<cmath> #include<queue> #include<set> #include<map> using namespace std; #define INF 0x3f3f3f3f #define MM(x) memset(x,0,sizeof(x)) #define MMINF(x) memset(x,INF,sizeof(x)) typedef long long LL; int main() { LL n,m; cin>>n>>m; if(m*6 > n || m*9 < n){ puts("jgzjgzjgz"); } else{ n = n-m*6; LL n3 = n/3; LL n1 = n-n3*3; LL k; if(3*n3 <= m-n1){ k = m-n1-3*n3; } else if ((m-n1)>=n3 && (m-n1)<=3*n3){ k = 0; } else{ return puts("jgzjgzjgz"),0; } printf("%lld\n",k); } } /* 90000000000 14000000007 */
B题:链接:https://ac.nowcoder.com/acm/contest/332/B
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
小j开始打工,准备赚钱买煤气灶。
第一天,小j的工资为n元,之后每天他的工资都比前一天多d元。
已知煤气灶需要m元,求小j最少工作几天才能买到煤气灶。
第一天,小j的工资为n元,之后每天他的工资都比前一天多d元。
已知煤气灶需要m元,求小j最少工作几天才能买到煤气灶。
输入描述:
四个整数 n,m,d,x
分别表示小j第一天的工资,煤气灶的价格,工资每天的增长量,答案不超过x
输出描述:
一个数表示答案
示例1
输入
10 100 20 100
输出
4
说明
10+30+50+70>=100
备注:
0≤n,d≤10^9,n+d>0
思路:暴力就完事了。
代码:
#include<bits/stdc++.h> typedef long long LL; int main() { LL n,m,d,x; cin>>n>>m>>d>>x; LL k = 1,dep = n,now = n; while(true){ if(k > x)break; if(now >= m)break; k++; dep = n+(k-1)*d; now += dep; } printf("%lld\n",k); }
C题:项链
链接:https://ac.nowcoder.com/acm/contest/332/C
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
小B想给她的新项链染色。
现在有m种颜色,对于第i种颜色,小B有a_i单位的颜料,每单位颜料可以染项链的一个珠子;
同时,小B对于第i种颜色的喜爱度为b_i。
已知项链有n个珠子,求染色后每个珠子的颜色的喜爱度之和的最大值。
(每个珠子只能至多被染一次,不被染色则喜爱度为0)
现在有m种颜色,对于第i种颜色,小B有a_i单位的颜料,每单位颜料可以染项链的一个珠子;
同时,小B对于第i种颜色的喜爱度为b_i。
已知项链有n个珠子,求染色后每个珠子的颜色的喜爱度之和的最大值。
(每个珠子只能至多被染一次,不被染色则喜爱度为0)
输入描述:
第一行两个数n,m
第二行m个数a_i
第三行m个数b_i
输出描述:
一个数表示答案
示例1
输入
5 3 1 2 3 3 2 1
输出
9
示例2
输入
5 3 1 2 1 3 2 1
输出
8
备注:
1≤n,m≤10^5,0≤ai,bi≤10^6
思路:简单贪心,先选价值大的。
代码:
#include<bits/stdc++.h> typedef long long LL; struct node{ int a,b; }p[100001]; bool cmp(node x,node y){ return x.b>y.b; } int main() { int n,m;cin>>n>>m; for(int i = 0 ; i < m ; i ++){ scanf("%d",&p[i].a); } for(int i = 0 ; i < m ; i ++){ scanf("%d",&p[i].b); } int k = 0; LL ans = 0; sort(p,p+m,cmp); while(n > 0){ if(n >= p[k].a){ n -= p[k].a; ans += p[k].a*p[k].b*1LL; } else if(n < p[k].a){ ans += (n)*p[k].b*1LL; n = 0; } k++; if(k == m)break; } printf("%lld\n",ans); } /* 5 3 1 2 3 3 2 1 */
D题:美食
链接:https://ac.nowcoder.com/acm/contest/332/D
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
64bit IO Format: %lld
题目描述
小B喜欢美食。
现在有n个美食排成一排摆在小B的面前,依次编号为1..n,编号为i的食物大小为 a[i] ,即足够小B吃 a[i] 口。
小B每次会吃两口,这两口要么是编号相同的美食,要么是编号之差的绝对值为1的美食。
小B想知道,她最多能吃几次?
现在有n个美食排成一排摆在小B的面前,依次编号为1..n,编号为i的食物大小为 a[i] ,即足够小B吃 a[i] 口。
小B每次会吃两口,这两口要么是编号相同的美食,要么是编号之差的绝对值为1的美食。
小B想知道,她最多能吃几次?
输入描述:
第1行一个正整数n,表示美食个数
接下来n行,第i行一个整数a[i],表示编号为i的美食的大小
输出描述:
一个数表示小B最多吃几次。
示例1
输入
4 1 5 7 8
输出
10
说明
用二元组(a,b)表示某一次吃的两个美食分别为第a个美食和第b个美食,则下面为一个吃10次的方案:
(1,2)(2,2)(2,2)(3,4)(3,4)(3,4)(3,4)(3,4)(3,4)(3,4)
注意不一定要吃完。
思路:
考虑一下相邻都-1,和自己本身-2,那么最后的串可以变为01串(比如说4231能变为0011,其实是本身去不断的-2)
考虑串323,中间的2可以跟左边和右边的3分别消去一次,即323这种奇数偶数奇数的串可以消去4次。
再考虑串3223,即奇偶偶奇,同样也能最后变为0000(3223->2123->2112->2002->0000)
再考虑串32223,也能消成00000。
即如果是1x1 其中x为若干偶数,即可消掉左边和右边的1,让次数+1。(有特殊情况)
特殊情况:如果本身没变成01串之前原位置就是0,例如30003这种通过自身尽量-2,变为10001,左右两边的1是不能消去的。
代码:
#include<bits/stdc++.h> typedef long long LL; int a[100001]; int main() { LL ans = 0; int n;cin>>n; for(int i = 0 ; i < n ; i++){ cin>>a[i]; if(a[i] == 0)a[i] = -1;//如果本身是0,那么记为-1 ans += (a[i]/2)*1LL;//尽量让自己通过-2变为最简 a[i] = a[i]%2; } int flag = 0; for(int i = 0 ; i < n ; i ++){ if(a[i] == -1){ flag = 0; continue; } if(a[i] == 1 && flag == 0){ flag = 1; continue; } if(a[i] == 1 && flag == 1){ flag = 0; ans++; }//找到可以消去的1,次数+1 } printf("%lld\n",ans); }
G题:区间或和
链接:https://ac.nowcoder.com/acm/contest/332/G
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
求a|(a+1)|(a+2)|...|(b-1)|b。
其中|表示[按位或](https://baike.baidu.com/item/%E6%8C%89%E4%BD%8D%E6%88%96)。
输入描述:
多组输入,每行两个数表示a和b
输出描述:
对于每组输入,输出一个数a|(a+1)|(a+2)|...|(b-1)|b。
示例1
输入
99 109 68 77 55 66 34 43 1111234 1114321
输出
111 79 127 47 1179647
思路:
看到或,想到的肯定是二进制。
那么就好做了,看以下例子:(括号2表示2进制情况)
0000100(2)
1010000(2)
答案是1111111(2) ,因为中间肯定有个数是111111,即可以后面全部为1
000101(2)
101111(2)
答案是111111(2),因为中间肯定有个数是11111,即也可以全部为1
第一种情况是,两个二进制数位数不等的情况下,那么就是大的那个数全补1,原因是肯定能从上个1111-->10000,即可以补齐全部1
第二种情况是,位数相等。
例子:
1000100(2)
1010000(2)
答案是1011111(2),因为在从左往右数第三个位置大的数是1,所以后面的都能补齐
在这种情况下,稍微多看几个例子就会发现,可以抛去第一位,然后如果小的数和大的数对应位置都是0,那么这位是1,一旦大的数某一位是1,后面的全部是1.
到此就分析完了。
代码:(java大数写的,只给主要代码)
Scanner input = new Scanner(System.in); while(input.hasNext()){ BigInteger a = input.nextBigInteger(); BigInteger b = input.nextBigInteger(); String s = a.toString(2); String s1 = b.toString(2); String s2 = ""; if(s1.length() > s.length()){ BigInteger ans = BigInteger.valueOf(2); for(int i = 0 ; i < s1.length()-1 ; i ++){ ans = ans.multiply(BigInteger.valueOf(2)); } ans = ans.subtract(BigInteger.ONE); System.out.println(ans); }//位数不等 else{ int flag = 0; for(int i = 0 ; i < s.length();i++){ char p1 = s.charAt(i); char p2 = s1.charAt(i); if(flag == 2){ s2 = s2+"1";continue; } if(p1 == p2 && p1 == '0'){ s2 = s2+"0";flag = 1; }//如果都是0,则该位是0 else{ s2 = s2+"1"; if(p2=='1'&&p1=='0')flag = 2;//一旦出现大的串是1的情况,则后面的都是1 } } BigInteger c = new BigInteger(s2,2);//二进制转十进制 System.out.println(c); } }
G:迷宫
链接:https://ac.nowcoder.com/acm/contest/332/J
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
你在一个 n 行 m 列的网格迷宫中,迷宫的每一格要么为空,要么有一个障碍。
你当前在第 r 行第 c 列(保证该格子为空)。每次移动你可以向上下左右任意一个方向移动一格,前提是不能走到障碍上,也不能超出迷宫的边界。
你向左移动的次数不能超过 x 次,向右不能超过 y 次。
问在这种情况下,对于每个格子,是否存在一种移动方案让你走到它。
输出有多少个格子存在移动方案让你走到它。
你当前在第 r 行第 c 列(保证该格子为空)。每次移动你可以向上下左右任意一个方向移动一格,前提是不能走到障碍上,也不能超出迷宫的边界。
你向左移动的次数不能超过 x 次,向右不能超过 y 次。
问在这种情况下,对于每个格子,是否存在一种移动方案让你走到它。
输出有多少个格子存在移动方案让你走到它。
输入描述:
第一行两个正整数 n,m 。
第二行两个正整数 r,c ,保证 1≤r≤n1≤r≤n ,1≤c≤m1≤c≤m 。
第三行两个整数 x,y ,保证 0≤x,y≤1090≤x,y≤109 。
接下来 n 行,每行一个长度为 m 的字符串,
第 i 行第 j 个字符表示迷宫第 i 行第 j 列的格子,
字符为`.` 表示格子为空,字符为`*` 表示格子上有一个障碍。
输出描述:
输出一个数,表示有多少个格子存在移动方案让你走到它。
示例1
输入
4 5 3 2 1 2 ..... .***. ...** *....
输出
10
说明
将能走到的格子用+标记:
+++..
+***.
+++**
*+++.
示例2
输入
4 4 2 2 0 1 .... ..*. .... ....
输出
7
说明
.++.
.+*.
.++.
.++.
思路:广搜就完事了,注意限制条件有左移右移距离,其实就是加个判断。
代码:
#include<iostream> #include<algorithm> #include<cstdlib> #include<sstream> #include<cstring> #include<cstdio> #include<string> #include<deque> #include<stack> #include<cmath> #include<queue> #include<set> #include<map> using namespace std; #define INF 0x3f3f3f3f #define MM(x) memset(x,0,sizeof(x)) #define MMINF(x) memset(x,INF,sizeof(x)) typedef long long LL; char mp[1001][1001]; bool vis[1001][1001]; int n,m,r,c,bx,by; struct node{ int x,y,left,right; node(){} node(int x,int y,int left,int right) :x(x),y(y),left(left),right(right){} }; bool judge(int x,int y,int L,int R){if(vis[x][y] || x < 0 || x >= n || y < 0 || y >= m || L > r || R > c || mp[x][y] == '*') return false; return true; } void bfs(){ queue<node>q; node a(bx,by,0,0); q.push(a); vis[bx][by] = 1; while(!q.empty()){ int dx,dy,L,R; node u = q.front();q.pop(); dx = u.x + 1; dy = u.y; L = u.left; R = u.right; if(judge(dx,dy,L,R)){ node v(dx,dy,L,R); vis[dx][dy] = 1; q.push(v); } //下 dx = u.x - 1; dy = u.y; L = u.left; R = u.right; if(judge(dx,dy,L,R)){ node v(dx,dy,L,R); vis[dx][dy] = 1; q.push(v); } //上 dx = u.x; dy = u.y - 1; L = u.left+1; R = u.right; if(judge(dx,dy,L,R)){ node v(dx,dy,L,R); vis[dx][dy] = 1; q.push(v); } //左 dx = u.x; dy = u.y + 1; L = u.left; R = u.right+1; if(judge(dx,dy,L,R)){ node v(dx,dy,L,R); vis[dx][dy] = 1; q.push(v); } //左 } } int main() { cin>>n>>m>>bx>>by>>r>>c; memset(vis,0,sizeof(vis)); for(int i = 0 ; i < n ; i ++){ scanf("%s",mp[i]); } bx-=1;by-=1; bfs(); int ans = 0; for(int i = 0 ; i < n ; i ++){ for(int j = 0 ; j < m ; j++){ if(vis[i][j] == 1){ ans++; } } } printf("%d\n",ans); } /* 4 5 3 2 1 2 ..... .***. ...** *.... */