A - Who`s better?
链接:https://ac.nowcoder.com/acm/contest/893/A
ICPC比赛中,谁通过的题数多,谁排名靠前;在通过题数相同的情况下,谁的罚时少,谁排名靠前;如果前两者都相同,就看最后正确提交的时间,谁早最排名靠前。 现在给你两个队伍的正确通过的题数、罚时和最后正确提交时间,请判断一下,谁的排名更靠前?
只有一组测试样例,两行,每行三个整数n(0≤n≤13),p(1≤p≤1000),s(1≤s≤300)n(0≤n≤13),p(1≤p≤1000),s(1≤s≤300),依次表示两个队的正确通过的题数、罚时和最后正确提交时间。
输出一行(末尾要换行符)。 如果是第1个队排名靠前,输出1;如果是2队,输出2;如果无法分辨,输出"God"。
示例1
复制
1 10 10 1 22 2
复制
1
示例2
复制
1 10 10 2 42 20
复制
2
示例3
复制
1 10 10 1 10 10
复制
God
解题思路
直接比较即可
代码如下
#include
using namespace std;
int main()
{
int n1, p1, s1;
int n2, p2, s2;
cin >> n1 >> p1 >> s1;
cin >> n2 >> p2 >> s2;
if(n1 > n2){
cout << 1 << endl;
}
else if(n1 < n2){
cout << 2 << endl;
}
else {
if(p1 < p2)
cout << 1 << endl;
else if(p1 > p2)
cout << 2 << endl;
else {
if(s1 < s2)
cout << 1 << endl;
else if(s1 > s2)
cout << 2 << endl;
else
cout << "God" << endl;
}
}
return 0;
}
B-Number
链接:https://ac.nowcoder.com/acm/contest/893/B
来源:牛客网
Bonnie得到了一个数字n。
现在她想对这个数字不断的做一种操作:
给定n,请问Bonnie需要做多少次操作?
第一行一个数字T(1≤T≤300000)T(1≤T≤300000)--样例个数。 每个样例仅一行一个数字n(1≤n≤109)n(1≤n≤109)。
每个样例输出一行一个数字—Bonnie需要做的操作次数。
示例1
复制
6 9 99 2 11032 1000000000 62
复制
2 3 9 44 9 13
第一个样例: 9→10→19→10→1 第二个样例: 99→100→10→199→100→10→1
解题思路
模拟即可,见注释
#include
using namespace std;
int main()
{
std::ios::sync_with_stdio(false);
int n;
cin >> n;
while(n --){
string str;
cin >> str;
int ans = 0;
for(int i = str.size() - 1; i >= 0; i --){
int x = str[i] - '0';
if(i == 0 && x == 1){ //只剩1的时候结束
break;
}
if(!x){ //此位是0,直接去掉
ans ++;
}
else if(x == 10){
ans ++; //去掉一个0
if(i != 0) //进位
str[i - 1] ++;
}
else {
ans += 10 - x + 1; //加上那么多的1 and 去掉一个0
if(i != 0) //进位
str[i - 1] ++;
}
}
cout << ans << endl;
}
return 0;
}
C-Math Problem
链接:https://ac.nowcoder.com/acm/contest/893/C
来源:牛客网
已知整数a,a3a,a3除192的余数是1。求区间[L,R]之间满足条件的a的累加和是多少?
第一行是一个整数T(1≤T≤10000)T(1≤T≤10000),表示样例的个数。 每个样例包含两个整数L,R,1≤L≤R≤109L,R,1≤L≤R≤109。
每行输出一个样例的结果。
示例1
复制
1 1 10
复制
1
解题思路
求一个等差数列,具体见注释
代码如下
#include
#include
#include
#include
#define maxn 10005
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int main()
{
int T;
cin >> T;
while(T --){
ll l, r;
cin >> l >> r;
ll ra = (r - 1) / 192 + 1; //1-r存在多少满足条件的数
ll la = (l - 1) / 192 + 1; //1-l存在多少满足条件的数
//因为l不一定满足条件,不满足时la++
if((l - 1) % 192)
la ++;
//此时这个区间内的满足条件的序列为(la-1)*192+1 la*192+1 ... (ra-1)*192+1
if(la > ra){ //不存在满足条件的数
cout << 0 << endl;
continue;
}
//提取1和192,然后等差数列求和
ll sum = (ra - la + 1) + 192 * (la + ra - 2) * (ra - la + 1) / 2;
cout << sum << endl;
}
return 0;
}
D-Stone
链接:https://ac.nowcoder.com/acm/contest/893/D
来源:牛客网
有n堆石子排成一排,第i堆石子有aiai个石子。
每次,你可以选择任意相邻的两堆石子进行合并,合并后的石子数量为两堆石子的和,消耗的体力等价于两堆石子中石子数少的那个。
请问,将所有的石子合并成一堆,你所消耗的体力最小是多少?
第一行是一个整数T(1≤T≤20)T(1≤T≤20),表示样例的个数。 每个样例的第一行是一个整数n(1≤n≤10000)n(1≤n≤10000),表示石子堆的数量。 第二行是n个整数ai(1≤ai≤109)ai(1≤ai≤109)
每行输出一个样例的结果。
示例1
复制
2 2 1 2 1 1
复制
1 0
巨大的输入,请使用C风格的输入。
解题思路
贪心,对于n堆石子,要合并成一堆,至少需要合并n-1次,每次合并消耗的体力等价于两堆石子中石子数少的那个, 把所有石子的和加起来减去最大的那堆即可。
代码如下
#include
#include
#include
#include
#define maxn 10005
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int a[maxn];
int main()
{
int T;
cin >> T;
while(T --){
int n;
cin >> n;
ll ans = 0;
int maxx = 0;
for(int i = 1; i <= n; i ++){
scanf("%d", &a[i]);
ans += a[i];
if(a[i] > maxx){
maxx = a[i];
}
}
cout << ans - maxx << endl;
}
return 0;
}
E-Watermelon
链接:https://ac.nowcoder.com/acm/contest/893/E
来源:牛客网
在ACM队暑假集训的某一天,实验室里有 n n个人。因为天气很热,大家都很想吃西瓜。
于是Eric买了 m m个西瓜拿到了实验室。
Eric把这 n n个人分别编号为 1,2,3...n 1,2,3...n,他希望这 n n个人循环轮流来吃西瓜。
也就是说从 1 1号开始,然后 2 2号, 3 3号... n n号依次吃西瓜, n n号吃完后又轮到 1 1号来吃,直到这 m m个西瓜被吃完。
而这 n n个人每个人有一个肚量值,第i个人的肚量值为 ai ai。
lililalala是这 n n个人肚量值最大的人,不仅如此,他还非常贪吃,每次轮到他吃西瓜时,都会直接吃掉等同于他的度量值数量的西瓜。如果剩余的西瓜已经不够吃了,那么他会把所有西瓜直接吃完。(是的他很能吃)
除了lililalala以外的其他人,对于第 i i号每次吃西瓜可以选择吃掉 [1,ai] [1,ai]中任意整数数量个西瓜。当然,不能超过当前剩余的西瓜数量。
为了使吃西瓜更有意思一些,Eric规定如果在轮到某个人吃西瓜时没有西瓜了,那么由他来打扫一次实验室。(是的大家都很能吃)
其他人都觉得lililalala吃的太多了应该由他来打扫卫生。请问在其他人串通好的情况下能否合理安排每个人的行动使得吃完西瓜后由lililalala来打扫卫生?
第一行一个数字T(1≤T≤50)T(1≤T≤50)--样例个数。 每个样例包含两行。 第一行两个数字n,m(1≤n≤105,0≤m≤106)n,m(1≤n≤105,0≤m≤106)。 第二行 n n个数字a1,a2...an(1≤ai≤107)a1,a2...an(1≤ai≤107),以空格分隔。 保证所有样例中肚量最大的人只有一个。这个人是lililalala。 保证所有样例中 ∑n ∑n不超过 3×106 3×106。 保证所有样例中 ∑m ∑m不超过 107 107。
每个样例输出一行,输出”YES”如果合理安排可以使得最后由lililalala来打扫卫生,否则输出“NO”。
示例1
复制
2 4 3 1 2 3 2 5 8 1 2 3 2 1
复制
YES NO
第一个样例中lililalala是3号: 一种可行的方案: 1号吃掉1个西瓜 2号吃掉2个西瓜 第一次到3号吃西瓜时就没有西瓜可以吃了,所以3号需要打扫卫生。 第二个样例无论怎样安排各个人在每一次吃西瓜的数量,也不能达成目标。
解题思路
#include
#include
#define maxn 100005
using namespace std;
typedef long long ll;
ll a[maxn];
int main()
{
int T;
cin >> T;
while(T --){
int n, m;
scanf("%d%d", &n, &m);
ll maxx = -1;
int k = 0; //最能吃的人的编号
for(int i = 1; i <= n; i ++){
scanf("%lld", &a[i]);
if(a[i] > maxx){
maxx = a[i];
k = i;
}
}
ll min_s, max_s; //最大的人前面的最小最大消耗
ll min_c, max_c; //一个周期的最大最小消耗
min_s = max_s = min_c = max_c = 0;
for(int i = 1; i <= n; i ++){
if(i < k){
min_s ++;
max_s += a[i];
}
min_c ++;
max_c += a[i];
if(i == k)
min_c += a[i] - 1;
}
ll max_left = m - min_s; //轮到k时最多剩下
ll min_left = m - max_s; //轮到k时最少剩下
bool flg = false;
while(max_left >= 0){ //如果轮到k时最多剩下的小于0了,则说明不可能
if(min_left <= 0){ //轮到k时剩下的区间饱和了0,则可以
flg = true;
break;
}
max_left -= min_c;
min_left -= max_c;
}
if(flg || n == 1) //特判n==1的情况
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
F-Black & White
链接:https://ac.nowcoder.com/acm/contest/893/F
来源:牛客网
你有一个长度为 n 的 01 串S,你可以执行最多 m 次操作。
对于每次操作,你可以选择一个位置 i 满足 1≤i≤n1≤i≤n,翻转这一位的值,0变成1,1变成0。
定义一个 01 串的价值为其中最长连续0的个数和最长连续1的个数的较大值,求S在经过最多m次操作后的最大价值。
* 第一行一个整数 T ,表示接下来有 T 个样例。 * 首先输入n,m,表示S串的长度n和操作次数m,其中1≤n≤1000001≤n≤100000,0≤m≤10000≤m≤1000; * 接下来输入一个长度为n的字符串S。
一个整数,表示题面上描述的最大价值。
示例1
复制
2 5 1 00101 2 1 01
复制
4 2
第一个串翻转第三个位置,00001的价值为4;第二个串翻转第一个位置,11的价值为2。
解题思路
求一次前缀和,维护1的个数。然后二分答案,若要求的答案为x,对于每一个以i为结尾的长度为x的字符串,比较其max(1的数量,0的数量)+m是否大于x,若大于x,则说明答案x存在。
代码如下
#include
#define maxn 100005
using namespace std;
int a[maxn]; //前缀中1的个数
int n, m;
string str;
bool work(int x)
{
for(int i = x - 1; i < str.size(); i ++){
int num1 = a[i] - a[i - x + 1] + str[i - x + 1] - '0';
int maxx = max(num1, x - num1);
if(maxx + m >= x)
return true;
}
return false;
}
int main()
{
std::ios::sync_with_stdio(false);
int T;
cin >> T;
while(T --){
cin >> n >> m;
cin >> str;
a[0] = str[0] - '0';
for(int i = 1; i < str.size(); i ++){
a[i] = a[i - 1] + str[i] - '0';
}
int l = 1;
int r = str.size();
int mid = (l + r + 1) / 2;
while(l < r){
if(work(mid))
l = mid;
else
r = mid - 1;
mid = (l + r + 1) / 2;
}
cout << mid << endl;
}
return 0;
}
G-Truthman or Fakeman
链接:https://ac.nowcoder.com/acm/contest/893/G
来源:牛客网
有n个人在玩一个身份扮演的游戏。
把这n个人编号为1,2,3...n。
其中每个人会扮演下面两种身份中的一种:
Truthman:当某个人扮演Truthman时,这个人只会说真话。
Fakeman:当某个人扮演Fakeman时,这个人只会说假话。
这n个人是互相知道身份的,但是Casya作为一个旁观者不知道任何一个人的身份。
为了让Casya有可能推断这些人的身份,这n个人说了m句话。
每句话的内容只包含某人对某人身份的一条描述,且被Casya记录为以下形式:
u,v,0 -- u认为v是一个Fakeman;
u,v,1 -- u认为v是一个Truthman;
当然这些话不一定都是真话,这取决于说话的人的身份。
但是可以肯定的是身份只有两种,也就是说某个人不是Truthman就是Fakeman。
Casya想知道不违反上面的条件和记录最少有多少个Fakeman,除此之外他还想得到一组在此情况下的一组合理的解—即所有人的身份。或者确定记录本来就是矛盾的所以没有任何符合条件的解。
第一行一个数字T(1≤T≤30)T(1≤T≤30)--样例个数。 其中每个样例: 第一行两个数字n,m(1≤n≤105,0≤m≤105)n,m(1≤n≤105,0≤m≤105)。 然后m行,每一行包含三个整数u,v,w(1≤u,v≤n,w={0,1})u,v,w(1≤u,v≤n,w={0,1}) 保证所有样例中∑n∑n不超过2×1062×106。 保证所有样例中∑m∑m不超过2×1062×106。
每个样例输出一行。 如果存在合理的解,输出一个长度为n的字符串,且只包含’0’或’1’。 其中第i个字符为’0’表示$i$是一个Fakeman,为’1’表示i是一个Truthman。并使得Fakeman的数量最少。如果有多个解符合要求,输出任意一个即可。 如果不存在任何合理的解,输出-1。
示例1
复制
2 5 4 1 2 1 2 3 0 2 4 0 1 5 0 3 3 1 2 1 1 3 0 2 3 1
复制
00111 -1
解题思路
并查集。如果a说b是1,那么如果a是1,b也是1,如果a是0,b也是0,即a和b的身份是相同的。反之,如果a说b是0,那么a和b的身份是不同的。由此,我们进行并查集操作,以及要遵循,和我身份不同的人身份不同的,和我身份相同。
代码如下
#include
#include
H-Chat
链接:https://ac.nowcoder.com/acm/contest/893/H
来源:牛客网
在Casya生活的世界里,一天由m个小时组成。
最近Casya的女神终于答应在接下来的n天中与Casya聊天,Casya非常激动。
在这n天中的每一天的每一个小时中女神可能会在线或者不在线,
某个小时如果女神如果在线且Casya在线的话他们就会开心的聊一个小时;
反之如果女神在线Casya没有在线的话女神就会认为Casya放了她的鸽子而积累一点生气度。
而Casya是个很懒惰的人,他每天只愿意上线一次,当他某天下线后就不愿意再上线了。
换句话说,他每天在线的时间必须是连续的。
现在Casya已经知道每一天的每个小时女神是否会在线
Casya希望在这n天中女神的总生气度不超过k,在此前提下Casya希望他的总上线时间最小。
假设每个小时Casya和女神要么完整在线要么完整不在线,请问Casya在这n天中最小的总上线时间是多少小时?
第一行一个数字T(1≤T≤30)T(1≤T≤30)--样例个数。 每个样例第一行三个数字n,m,k(1≤n,m≤200,0≤k≤200)n,m,k(1≤n,m≤200,0≤k≤200)。 然后这n行,每行一个长度为m的只含'0'和'1'的字符串, 第i个字符串的第j个字符为'0'代表女神第i天的第j个小时不在线,为'1'表示女神第i天的第j个小时在线。 保证所有样例中∑n×m∑n×m不超过5×1055×105。
每个样例输出一行一个数字--Casya在这n天中最小的总上线时间
示例1
复制
2 2 5 1 01001 10110 2 5 0 01001 10110
复制
5 8
第一个样例: 一种可行的方案: Casya第一天只在第2个小时上线,第五个小时女生在线而Casya不在线,生气度积累1; Casya第一天在第1、2、3、4个小时上线。 Casya的总上线时间是1+4=5。 第二个样例: 只能老老实实上线。 Casya第一天在第2、3、4、5个小时上线; Casya第一天在第1、2、3、4个小时上线。 Casya的总上线时间是4+4=8。
解题思路
可以转为为分组背包问题,以生气值为背包容量。
#include
#include
#include
#define maxn 205
using namespace std;
int dp[maxn][maxn];
int a[maxn][maxn]; //第i天造成j点生气值最多不在线时间
string str[maxn];
int c[maxn];
int main()
{
std::ios::sync_with_stdio(false);
int T;
cin >> T;
while(T --){
int n, m, k;
cin >> n >> m >> k;
for(int i = 1; i <= n; i ++){
cin >> str[i];
}
memset(dp, 0, sizeof(dp));
memset(a, 0, sizeof(a));
for(int i = 1; i <= n; i ++){
int s, t;
s = t = m;
int qz[maxn], hz[maxn];
for(int j = 0; j < m; j ++){
if(str[i][j] == '1'){
s = j;
break;
}
}
for(int j = m - 1; j >= 0; j --){
if(str[i][j] == '1'){
t = m - j - 1;
break;
}
}
int cnt = -1;
for(int j = 0; j < m; j ++){
if(str[i][j] == '1'){
qz[++cnt] = j;
}
}
cnt = -1;
for(int j = m - 1; j >= 0; j --){
if(str[i][j] == '1'){
++ cnt;
hz[cnt] = m - j - 1;
a[i][cnt] = max(qz[cnt], hz[cnt]);
}
}
a[i][0] = min(m, s + t);
cnt ++;
a[i][cnt] = m;
c[i] = cnt;
for(int j = 1; j < cnt; j ++){
for(int u = 0; u <= j; u ++)
a[i][j] = max(qz[u] + hz[j - u], a[i][j]); //前缀和后缀
}
}
for(int i = 1; i <= n; i ++){
for(int j = 0; j <= k; j ++){
for(int u = 0; u <= min(j, c[i]); u ++)
dp[i][j] = max(dp[i][j], dp[i - 1][j - u] + a[i][u]);
}
}
int ans = 0;
for(int i = 0; i <= k; i ++){
if(dp[n][i] > ans)
ans = dp[n][i];
}
cout << n * m - ans << endl;
}
return 0;
}