Codeforces Round #780 (Div. 3)(A~F1)

A. Vasya and Coins

题意:瓦西娅决定去杂货店。他在他的钱包里发现了 1 1 1 颗豆的硬币和 2 2 2 颗豆的硬币。他还不知道所有商品的总成本,所以帮他找出 s s s ( s > 0 ) (s>0) (s>0) :他不找零钱就不能支付的最小正整数,或者只用硬币就不能支付。
例如,如果 a = 1 a=1 a=1 b = 1 b=1 b=1 (他有一枚 1 − b u r l e 1-burle 1burle 硬币和一枚 2 − b u r l e 2-burle 2burle硬币),则:
他可以不用找零付 1 1 1 波利,用 1 1 1 波利硬币付,
他可以不用找零付 2 2 2 波利,用 1 1 1 波利硬币付3波利
1 − b u r l e 1-burle 1burle 硬币和 1 − b u r l e 1-burle 1burle 硬币支付的 B u r l e Burle Burle 无零钱,他无法支付 4 B u r l e 4 Burle 4Burle 无零钱(此外,他无法支付这笔金额)。
对于 a = 1 a=1 a=1 b = 1 b=1 b=1,答案是 s = 4 s=4 s=4

分享: 当 a a a 为0, 1不能凑出, 当 a a a 不为 0 0 0 1 1 1 ~ a + 2 ∗ b a + 2 * b a+2b 一定能凑出, 所以 a + 2 ∗ b + 1 a + 2 * b + 1 a+2b+1不能凑出

#include<bits/stdc++.h>
#define x first
#define y seoncd
#define int long long 
#define gg exit(0);
#define sf1(x) scanf("%lld",&x)
#define sf2(x,y) scanf("%lld%lld",&x,&y)
#define pr1(x) printf("%lld\n", x)
#define pr2(x, y) printf("%lld%lld\n", x, y)
#define db printf("debug\n");
const int N = 1e6 + 10;
using namespace std;
typedef pair<int, int>PII;

int t, a, b;
void solve()
{
	cin >> a >> b;

	if(a == 0 )
		cout << 1 <<'\n';
	else 
		cout << a + 2 * b + 1 << '\n';
 }
signed main()
{
	//t = 1;	 	
	scanf("%lld", &t);
	while(t -- )
	solve();
}

B. Vlad and Candies
不久前,弗拉德过生日时,收到了一包糖果。一共有n种糖果,i类型的糖果有 a i a_i ai ( 1 ≤ i ≤ n ) (1≤i≤n) (1in)

弗拉德决定每次只吃一颗糖果,从目前最常见的糖果中选择一颗(如果有几种,他可以选择其中的任何一颗)。为了从吃中获得最大的乐趣,弗拉德不想连续吃两颗相同类型的糖果。

帮他弄清楚他是否可以吃完所有的糖果,而不用连续吃两个相同的糖果。

分析: 找规律即可, 如果最大的与第二大的相差大于 1 1 1 就无解

#include<bits/stdc++.h>
#define x first
#define y seoncd
#define int long long 
#define gg exit(0);
#define sf1(x) scanf("%lld",&x)
#define sf2(x,y) scanf("%lld%lld",&x,&y)
#define pr1(x) printf("%lld\n", x)
#define pr2(x, y) printf("%lld%lld\n", x, y)
#define debug printf("debug\n");
const int N = 1e6 + 10;
using namespace std;
typedef pair<int, int>PII;

int t, n, a[N];
bool cmp(int a, int b)
{
	return a > b;
}
void solve()
{
	cin >> n;

	for(int i = 1; i <= n; i ++ ) cin >> a[i];

	if(n == 1)
{
	if(a[1] >= 2)
	 cout << "NO\n";
	else cout << "YES\n";
	}
	else 
	{
		sort(a + 1, a + 1 + n, cmp);  //排序
		if(a[1] - a[2] >= 2)
			cout << "NO\n";
		else cout << "YES\n";

	}
}
signed main()
{
	//t = 1;
	scanf("%lld", &t);
	while(t -- )
	solve();
}

https://codeforces.com/contest/1660/problem/C

题意: 一个字符串 A A A = a 1 a 2 … , a n =a_1a_2…,a_n =a1a2,an 被调用,即使它由由相同字符组成的长度为 2 2 2 的字符串串联(连接)组成。换句话说,如果同时满足两个条件,字符串a就是偶数:它的长度 n n n 是偶数;
对于所有奇数i(1≤i≤n−1),满足 a i = a i + 1 a_i=a{i + 1} ai=ai+1
例如,下面的字符串是偶数:“”(空字符串)、“tt”、“aabb”、“oooo”和“trrrrouuuuuuuukk”。下面的字符串不是偶数的:“aaa”,“abab”和“abba”。

给定一个由小写拉丁字母组成的字符串s。找出要从字符串s中删除的最小字符数,使其为偶数。删除的字符不必是连续的。

从贪心的角度来想,只要一个字母之前出现过, 就把中间的其他字符删去,我们可以用 m a p map map 来记录每个字母是否出现, 之前就出现过就加上答案,清空哈希表, 最后要记得哈希表能如果还有字符也要删去

#include<bits/stdc++.h>
#define x first
#define y seoncd
#define int long long 
#define gg exit(0);
#define sf1(x) scanf("%lld",&x)
#define sf2(x,y) scanf("%lld%lld",&x,&y)
#define pr1(x) printf("%lld\n", x)
#define pr2(x, y) printf("%lld%lld\n", x, y)
#define debug printf("debug\n");
const int N = 1e6 + 10;
using namespace std;
typedef pair<int, int>PII;

int t, n;
char s[N];
map<char ,int>cnt;
void solve()
{
	string s;
	cin >> s;
	int n = (int)s.size();
	if(n == 1)
		cout << 1 << '\n';
	else 
	{
		cnt.clear();
		int res = 0, sum = 0;
		 for(int i = 0; i < n; i ++ )
		 {
		 	cnt[s[i]] ++;
		 	res ++;
		 	if(cnt[s[i]] == 2)  //之前出现过
		 	{
		 		cnt.clear();  //清空
		 		sum += res - 2, res = 0; //计入答案

		 	}
		 }

		 if(cnt.empty()) cout << sum << '\n';  //没有多余字符
		 else cout << res + sum << '\n';  //有多余字符
	}

}
signed main()
{
	//t = 1;
	scanf("%lld", &t);
	while(t -- )
	solve();
}

D. Maximum Product Strikes Back

题意: 给定一个由 n n n 个整数组成的数组 a a a。对于每个 i ( 1 ≤ i ≤ n ) i(1≤i≤n) i(1in),下列不等式都成立:
可以从数组的开头移除任意数量(可能为 0 0 0 )的元素,也可以从数组的末尾移除任意数量(可能为 0 0 0 )的元素。允许删除整个数组。

您需要回答以下问题:应该从数组的开头删除多少个元素,以及应该从数组的末尾删除多少个元素,这样,结果将是一个元素乘积(乘法)最大的数组。如果有一种以上的方法可以获得元素乘积最大的数组,则允许输出其中任何一种。

空数组(长度为0的数组)的元素乘积应该假定为 1 1 1

思路: 首先 0 0 0 是必须要删去的, 我们可以按 0 0 0划分区间, 0…0…0…0, 然后给首尾也加上 0 0 0 如果有 x x x 0 0 0, 那么我们就得到了 x − 1 x - 1 x1 个区间, 然后计算每个区间内负数的个数, 如果为偶数, 直接更新最大值即可, 如果为负数, 从左边起到左边第一负数全部删去, 或者从右边起到右边第一个负数全部删去, 更新最大值

#include<bits/stdc++.h>
using namespace std;

#define fer(i,a,b) for(int i = a ; i <= b ; ++ i)
#define lb lower_bound
#define ub upper_bound
inline void de2(long long   a , long long  b) {cout << a << " " << b << "\n" ;}
#define cf int _; cin>> _; while(_--)
const int N = 1e6 + 10 , M = 3010 , mod = 1e9 + 7 ; // mod = 998244353 ;
int n , m ;
int a[N] ;
int s[N] ; // s[i]表示[1,i]中负数的个数
int ss[N] ; // ss[i]表示[1,i]中a[i]绝对值=2的个数
int res , ll , rr ;
 
void get(int l , int r)
{
    int x = s[r] - s[l - 1] ;
    int sum = ss[r] - ss[l - 1] ;
    if(sum > res && x % 2 == 0)
    {
        res = sum ;
        ll = l - 1 , rr = n - r ;
    }
}
 
signed main()
{
    cf
    {
        cin >> n ;
        vector<int> v ;
        fer(i,1,n) cin >> a[i] , s[i] = s[i - 1] + (a[i] < 0) , ss[i] = ss[i - 1] + (abs(a[i]) == 2) ;
        a[0] = 0 , a[n + 1] = 0 ;
        fer(i,0,n+1) 
            if(a[i] == 0)
                v.push_back(i) ;
                
        multiset<int> q ; // set里面放所有负数的下标
        fer(i,1,n)
            if(a[i] < 0)
                q.insert(i) ;
                
        res = -1e9 ;
        ll = 1 , rr = n - 1 ;
        for(int i = 0 ; i + 1 < (int)v.size() ; i ++)
        {
            int l = v[i] + 1 , r = v[i + 1] - 1 ;
            int x = s[r] - s[l - 1] ;
            if(x % 2 == 0)
            {
                get(l,r);
            }
            else
            {
                auto it = q.lb(l) ;
                get(*it + 1 , r) ;
                
                it = q.ub(r) ;
                -- it ;
                get(l , *it - 1) ;
            }
        }
        
        de2(ll , rr) ;
    }
    return 0 ;
}

E. Matrix and Shifts

题意:给定一个大小为n×n的二进制矩阵a。行从上到下从1到n编号,列从左到右从1到n编号。位于第i行和第j列交点的元素称为Aij。考虑一组4个操作:
循环地向上移动所有的行。索引为i的行将被写在i−1(2≤i≤n)行的位置,索引为1的行将被写在n行的位置。
循环移动所有行。下标为i的行
当第i+1行(1≤i≤n−1)被写入时,索引为n的行将被写入第1行。
循环地向左移动所有列。索引为j的列
将写在第j−1列(2≤j≤n)的位置,索引为1的列将写在第n列的位置。
循环地向右移动所有列。索引为j的列
将被写在第j+1列(1≤j≤n−1)的位置,索引为n的列将被写在第1列的位置。
你可以对矩阵执行任意次数的操作(可能是零);操作可以按任意顺序执行。
在此之后,你可以执行任意(可能为零)次新的异或操作:选择任何元素Aij,并给它赋新值Aij⊕1。换句话说,(Aij+1)mod2的值必须写在元素Aij中。
这种异或操作的每次应用花费一个树瘤。注意4
移位操作-是免费的。这4个操作只能在xor操作之前执行。
输出你需要支付的最小毛刺数量来制作A
矩阵。矩阵是主对角线上为1且其其余元素为0的矩阵(即,如果 i=j, Aij=1,否则Aij=0)

分析: 找每一条对角线, 对角线上 1 1 1 的个数最多的( r e s res res), 计算出缺少的 1 1 1 的个数( n − r e s n - res nres),然后计算总矩阵中 1 1 1 的个数减去前面计算出的答案(cnt1 - res + (n - res)即可, 注意每条对角线的长度都是 n n n, 也就是每一斜行

#include<bits/stdc++.h>
#define x first
#define y seoncd
#define int long long 
#define gg exit(0);
#define sf1(x) scanf("%lld",&x)
#define sf2(x,y) scanf("%lld%lld",&x,&y)
#define pr1(x) printf("%lld\n", x)
#define pr2(x, y) printf("%lld%lld\n", x, y)
#define debug printf("debug\n");
const int N = 1e6 + 10;
using namespace std;
typedef pair<int, int>PII;

int t, n;
char g[2010][2010];
void solve()
{
	 cin >> n;

	 for(int i = 0; i < n; i ++ )
	 	scanf("%s", g[i]);
	 int res = 0;
	 for(int i = 0; i < n; i ++ )
{
		int sum = 0;
		int a = i, b = 0;
		for(int j = 0; j < n; j ++ )
		{
			a = (a + 1) % n;
			b = (b + 1) % n;
			if(g[a][b] == '1') //1的个数
				sum ++;
		}
		res = max(res, sum);
}	 	
 	int cnt = n - res,ans = 0;
 	for(int i = 0; i < n; i ++ )
 		for(int j = 0; j < n; j ++ ) if(g[i][j] == '1') ans ++; //找1
    
 	cout << ans - res + cnt << '\n'; 
}
signed main()
{
	//t = 1;
	scanf("%lld", &t);
	while(t -- )
	solve();
}

F1. Promising String (easy version)
这是问题f的简单版本,简单版本和困难版本之间的唯一区别是约束条件。
如果一个非空字符串包含相同数量的正负号,我们将称其为balanced。例如:字符串“+——+”和“+±+——”是平衡的,而字符串“+——”,“——”和“”是不平衡的。
如果一个字符串可以通过以下几次(可能是0)的操作来实现平衡,我们就称该字符串为promising:将两个相邻的减号替换为一个加号。
特别是,每一个平衡的弦都是有希望的。然而,反过来就不正确了:不是每一个有希望的字符串都是平衡的。
例如,字符串“-+——”很有前途,因为你可以用加号替换两个相邻的减号,得到一个平衡的字符串“-+±”,或者得到另一个平衡的字符串“-±+”。
给定的字符串s中有多少非空的子字符串?每个非空的有希望的子字符串在答案中出现的次数必须与它在字符串s中出现的次数相同。回想一下,子字符串是字符串的连续字符序列。例如,对于字符串“±+”,它的子字符串是:“±”,“-+”,“+”,“±+”(字符串本身是一个子字符串)和其他一些。但是下面的字符串不是它的子字符串:"——","++","-++"。

分析: 设有 a a a 个负号, b b b 个正号,有 k k k 个负号变成正号

b + k = = a − 2 ∗ k b + k == a - 2 * k b+k==a2k
a − b = 3 ∗ k a - b = 3 * k ab=3k
所以要使字符串有前途, 如果 a > b a > b a>b, 并且满足 a − b a - b ab % 3 = = 0 3 == 0 3==0即可

#include<bits/stdc++.h>
#define x first
#define y seoncd
#define int long long 
#define gg exit(0);
#define sf1(x) scanf("%lld",&x)
#define sf2(x,y) scanf("%lld%lld",&x,&y)
#define pr1(x) printf("%lld\n", x)
#define pr2(x, y) printf("%lld%lld\n", x, y)
#define debug printf("debug\n");
const int N = 1e6 + 10;
using namespace std;
typedef pair<int, int>PII;

int t, n;
char s[N];
void solve()
{
	cin >> n;
	int res = 0;
	scanf("%s", s + 1);
	  for(int i = 1; i <= n; i ++)
        {
            int a = 0, b = 0;
            for(int j = i; j <= n; j ++)
            {
                if(s[j]=='+') b ++;
                else a ++;
                if(a >= b && (a - b) % 3 == 0)
                    res++;
            }
        }
        cout << res << '\n';
}
signed main()
{
	//t = 1;
	scanf("%lld", &t);
	while(t -- )
	solve();
}

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

广西小蒟蒻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值