Codeforces Round #786 (Div. 3) ABCDEF

文章目录

    • @[TOC](文章目录)
  • 前言
  • 一、A - Number Transformation + 思维
  • 二、B - Dictionary + 模拟
  • 三、C - Infinite Replacement + 思维 + 数学
  • 四、D - A-B-C Sort + 思维
  • 五、E - Breaking the Wall + 思维
  • 六、Desktop Rearrangement + 树状数组

前言

—这次写的一般,第3题题意没看清楚wa了一次,e题没有写出来,有点扯

一、A - Number Transformation + 思维

题目大意: 就是 给你一个x和y,让你找到1个a和一个b ,使得x * pow(b,a) = y

思路: 因为a,b都是大于0 的正整数,所以,如果x大于y 那x * pow(b,a) 一定是 大于 y的,所以,x > y 不符合条件*,同理如果y % x != 0的话,代表x *pow(b,a)一定 != y, 因为要想 x * pow(b,a) = y,那pow(b,a) = y / x,又因为,a,b是都是大于0 的正整数,所以pow(b,a)一定为正整数,那 y / x 也一定要是正整数,

#include 
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0)
#define read(i,l,r) for(int i = l;i <= r;i ++ )
#define pb push_back
#define all(x) x.begin(),x.end()

using namespace std;

void solve()
{
	int x,y;cin >> x >> y;
	if(y % x != 0 || x > y) cout << "0 0" << endl;
	else
	{
		int u = y / x;
		 cout << "1 " << u << endl;
	}
	
}
signed main()
{
	ios; int t; cin >> t;
	while(t -- ) solve();

	return 0;
} 

二、B - Dictionary + 模拟

题目大意: 给你只由两个不相等字母组成的字符串,每一个字符串都有一个对应的数值,题目给你这个字符串,问你他对应的数值是多少.

思路: 题目让我们求的是不相等的两个字母对应的数值,这样不太好算,我们可以考虑把两个相同的字母算进去,然后再减去算进去的个数就行了, 因为是26个字母 所以一共是26 * 26 = 676个数值 ,我们可以发现这就相当于一个26进制的数值,
我们假设输入的两个字符分别是a和b,算当前字符串对应哪一个数值,计算方法就是 (a - ‘a’) * 26 + (b - ‘b’) + 1,然后再减去重复算的数值 比如字符串是de 那就应该减去aa bb cc dd 这四个 字符串是dc 那减去的就是 aa bb cc 三个 我们发现只要是a > b 就减去 (a - ‘a’) + 1,否则就减去 (a - ‘a’)**

#include 
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0)
#define read(i,l,r) for(int i = l;i <= r;i ++ )
#define pb push_back
#define all(x) x.begin(),x.end()

using namespace std;
// 两个字母,两个字母各不相同 
void solve()
{
	char a,b; cin >> a >> b;
	int w = a - 'a'; 
	int q = b - 'a' + 1;
	int c = w * 26 + q;
	
	
	int s = (int)(a - 'a') + 1;
	
	
	if(a > b)
	s--;
	
	cout << c - s << endl;
	
}
signed main()
{
	ios; int t; cin >> t;
	while(t -- ) solve();

	return 0;
} 

三、C - Infinite Replacement + 思维 + 数学

题目大意: 给你两个字符串,一个是S一个是T, S只由"a"组成,S中任何一个a都可以被字符串T替换,每一次替换的a的个数的范围是从 0 - 'a’的个数,你可以替换任意次数,你最多可以整出来多少个不同的字符串

思路
1 如果T里面有 ‘a’ 出现,如果只有一个’a’,并且只有一个’a’,那对S就无影响,所以答案就是1.否则其他情况下,你就可以一直替换,因为你替换一次a的数量没有少,但是长度增加了
2 如果没有’a’出现的话,我们可以观察一下 例如S = aaa,T = b 有多少种情况
每次只选1个a替换就有3种情况 ,每次只选两个a替换也有三种情况,每次只选三个a替换只有1种情况 再加上本身的一种情况 就是8种 也就是二项式的和答案就是2的n次方,n是S字符串的长度

#include 
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0)
#define read(i,l,r) for(int i = l;i <= r;i ++ )
#define pb push_back
#define all(x) x.begin(),x.end()

using namespace std;
// 一个 s 只有a 一个t数组 小写字母 
void solve()
{
	string s,t; cin >> s >> t;
	
	if(t.find('a') != -1)
	{
		if(t.size() == 1)
		cout << "1" << endl;
		else
		cout << "-1" << endl; 
	}
	else
	{
		int e = pow(2,s.size());
		cout << e << endl;
	}
	
}
signed main()
{
	ios; int t; cin >> t;
	while(t -- ) solve();

	return 0;
} 

四、D - A-B-C Sort + 思维

题目大意,给你3个数组a,b,c,a由n个元素组成,b,c 都是空数组,让你执行下面两个操作,使得c数组变成一个非递减序列
第 1 步:当 a 不为空时,从 a 中取出最后一个元素并将其移动到数组 b 的中间。 如果 b 当前为奇数长度,您可以选择:将 a 中的元素放在 b 的中间元素的左侧或右侧。 最后使得结果是 a 变为空,b 由 n 个元素组成。
第 2 步:当 b 不为空时,从 b 中取出中间元素并将其移动到数组 c 的末尾。 如果 b 当前具有偶数长度,您可以选择取两个中间元素中的哪一个。 最后结果是,b 变为空,c 现在由 n 个元素组成。

思路 : 可以先考虑b与c,如果b是奇数的话,b中间的元素一定要是b数组中的最小值,即满足 b[k] <= b[k + 1] && b[k ] <= b[k - 1] 如果b是偶数的话,中间的两个元素一定是b数组中的两个最小值,必须满足 b[k] <= b[k + 2] 并且 b[k] <= b[k - 1] 并且 b[k +1] <= b[k + 2] 并且 b[k + 1] <= b[k - 1] ,
这我们就知道了b数组必须满足中间的值都是最小值,

考虑a和b,因为a是取最后一个元素放到b的中间,b的中间必须是最小值,所以a的末元素要是最大值,因为每次是a的末尾放到b的中间,所以先放的一定是b的边界,b的边界必须是最大值,所以a的末元素要是最大值,那a的首元素就是最小值
1 如果a是偶数,那我们就是要考虑两个, 也就是 每一个 i 都满足 a[ i ] <= a [ i + 2 ] 并且 a[ i ] <= a[ i + 3] 并且 a[ i + 1] <= a[ i + 2 ] 并且 a[ i + 1 ] <= a[ i + 3 ]
2 如果a是奇数,就先刨除第一个,那就是偶数的条件了,最后判断一下a[1] 是否小于等于 a[ 3 ] 并且
a[ 1 ] 是否小于等于 a[ 4 ]

#include 
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0)
#define read(i,l,r) for(int i = l;i <= r;i ++ )
#define pb push_back
#define all(x) x.begin(),x.end()

using namespace std;
const int N = 2e5 + 100;
int a[N];
// a,b,c a取最后放中间,  b 是取中间放末尾 
void solve()
{
	int n; cin >> n;
	read(i,1,n) cin >> a[i];
	
	if(n == 1 || n == 2)
	{
		cout << "YES" << endl;
		return;
	}
	
	if(n % 2 == 0) // 偶数的话两个两个看 
	{
		for(int i = 1;i <= n - 3;i += 2)
		{
			if(a[i] <= a[i + 2] && a[i] <= a[i + 3] && a[i + 1] <= a[i + 2] && a[i + 1] <= a[i + 3])
			continue;
			else
			{
				cout << "NO" << endl;
				return;
			}
		}
	}
	else
	{
			for(int i = 2;i <= n - 3;i += 2)
		{
			if(a[i] <= a[i + 2] && a[i] <= a[i + 3] && a[i + 1] <= a[i + 2] && a[i + 1] <= a[i + 3])
			continue;
			else
			{
				cout << "NO" << endl;
				return;
			}
		}
		
		if(a[1] > a[2] || a[1] > a[3])
		{
			cout << "NO" << endl;
			return;
		}
		
		
	} 
	
	cout << "YES" << endl;
}
signed main()
{
	ios; int t; cin >> t;
	while(t -- ) solve();

	return 0;
} 

五、E - Breaking the Wall + 思维

题目大意: 给你n个城墙,第 i 个城墙的厚度是a[ i ],你可以拿枪射击城墙,假如你射击第x个城墙一次,那第x个城墙的厚度减2,然后第 x + 1个城墙和第 x - 1个城墙的厚度减去1 ,问你最少射击几次可以使得最少两个城墙的厚度为0;

思路: 因为射击x只会影响 x 和 x +1 和 x - 1 位置上面的城墙的厚度分三种情况讨论
1 就是两个位置之间的差距为1(相邻)
2 就是两个位置之间的差距为2
3 就是两个位置之间的差距 >= 2
对于第三种情况就是直接排个序找最小的两个分别相除再相加
对于第二种情况
1 一直射击i + 1的位置,使得 i 和 i + 2 两个位置都小于等于0.
2 射击第i + 1位置使得城墙薄的城墙先倒下,然后再射击厚的城墙
对于第一种情况
1 通过规律发现,只要两个城墙其中一个的厚度是另外一个城墙厚度的两倍以上 就射击厚的城墙就行
2 就两个轮流射击,射击一次会使得其中一个城墙 - 2 另外一个城墙 - 1 ,也就是说射击一次会使得他们两个一共减去3,那就直接(a[i] + a[i + 1] +2 ) / 3 就是他们需要的次数

#include 
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0)
#define read(i,l,r) for(int i = l;i <= r;i ++ )
#define pb push_back
#define all(x) x.begin(),x.end()

using namespace std;
const int N = 2e5 + 100;
int a[N],b[N];

void solve()
{
	int n; cin >> n;
	read(i,1,n)
	{
		 cin >> a[i];
		 b[i] = a[i];
	}
	
	int ans = 0x3f3f3f3f;
	
	for(int i = 1;i <= n - 1;i ++ ) // 差距 == 1 
	{
		if(a[i] >= a[i + 1] * 2 || a[i] * 2 <= a[i + 1])
		{
			ans = min(ans,(max(a[i],a[i + 1])+ 1)/ 2);
		}
		else 
		{
			ans = min(ans,(a[i + 1] + 2 + a[i]) / 3);
		}
		
	}
	 
	for(int i = 1;i <= n - 2;i ++ ) // 差距 == 2 
	{
		ans = min(ans,max(a[i],a[i + 2]));
		int q = max(a[i],a[i + 2]);
		int w = min(a[i],a[i + 2]);
		ans = min(ans,w + (q - w + 1) / 2);// 射击第一个位置
	
	}
	
	sort(b + 1,b + 1 + n);
	ans = min(ans,(b[1] + 1) / 2 + (b[2] + 1) / 2); // 差距 >= 2 
	
	cout << ans << endl;
	
	
}
signed main()
{
	ios; 
	solve();

	return 0;
} 

六、Desktop Rearrangement + 树状数组

题目大意: 你的电脑桌面上的图标很乱,然后你想要恢复到初始的电脑桌面,也就是先把第一列排满,然后再排第二列,不懂了,可以看看自己电脑上的桌面咋排列的,问你最少几次可以排列成初始的桌面

思路: 因为要使得全部的图标排列好,最差需要 (图标的数量) 次,但是如果这个图标的位置 <= 图标的个数,就不要动这个图标就好,那我们可以用一个树状数组,使得所有的不是图标的位置 + 1,是图标的位置 + 0,然后因为是二维,我们可以把他变成一维来算

#include 
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0)
#define read(i,l,r) for(int i = l;i <= r;i ++ )
#define pb push_back
#define all(x) x.begin(),x.end()

using namespace std;
const int N = 1100,M = 1e6 + 100;
char a[N][N];
int tr[M];

int lowbit(int x)
{
	return x & -x;
}
int add(int x,int v)
{
	for(int i = x;i <= M;i += lowbit(i))
	{
		tr[i] += v;
	}
}
int sum(int x)
{
	int ans = 0;
	
	for(int i = x;i >= 1;i -= lowbit(i))
	{
		ans += tr[i];
	}
	
	return ans;
}

void solve()
{
	int n,m,q; cin >> n >> m >> q;
	int num = 0;
	read(i,1,n)
		read(j,1,m)
		{
			cin >> a[i][j];
			if(a[i][j] != '*')
			add((j - 1) * n + i,1);
			else
			num++;
		}
			
	
	while(q -- )
	{
		int x,y; cin >> x >> y;
		if(a[x][y] == '*')
		{
			a[x][y] = '.';
			add((y - 1) * n + x,1);
			num--;
		}
		else
		{
			a[x][y] = '*';
			add((y - 1) * n + x,-1);
			num++;
		}
		
		int w = sum(num);
		cout << w <<endl;
	}		 
}
signed main()
{
	ios; 
	solve();

	return 0;
} 

你可能感兴趣的:(c++,算法)