首页 > 其他分享 >CodeTON Round 3 (C.差分维护,D.容斥原理)

CodeTON Round 3 (C.差分维护,D.容斥原理)

时间:2022-11-07 14:23:36浏览次数:79  
标签:int res top 容斥 CodeTON 操作 互质 Round rightarrow

C. Complementary XOR


题目大意:

给你两个01串ab,问你是否可以通过一下两种操作在不超过n+5次的前提下将两个串都变为0,同时需要输出可以的操作方案

  1. 选择一个区间[l,r]
  2. 将串a的[l,r]翻转(0 \(\rightarrow\) 1,1 $\rightarrow$0), 同时将b的[1,l)和(r,n]区间翻转

解题思路:

通过写两组样例,我们可以尝试这种思路,因为我们需要输出可以的操作方案 ,我们很难去考虑同时操作a,b两个串的操作,所以我们尝试只考虑a串。将a串的全部0变成1,观察b串经过这种操作后的结果。
我们可以发现,如果a串全为1,那b串此时有三种可能:

  1. 全为0
  2. 全为1
  3. 即含1,又含0

我们发现状况1可以通过对a进行一次[1,n]操作使a,b都为0
状况2可以通过对a进行一次[1,1],[2,n]操作使a,b都为0(观察最后一个样例)
但是状况3我们没有任何办法使得a,b都为0


自此整个题目分析完毕,我们只需要记录让a全部为1的操作对b的影响,最后看b串是否属于情况1,2即可

我们观察操作对b的影响是对[1,l)和(r,n]整个的影响,所以可以理解为对[1,l)和(r,n]操作次数都+1,因为翻转2次等于没翻转,(只有翻转奇数次才会真的翻转),因为是对整个区间+1,所以就可以考虑用差分维护(O(1))

操作影响如下,假如选择的区间为[i,i],对b的影响就是b[1] += 1;b[i]-=1;b[i+1] += 1;

代码实现:

# include<iostream>
# include<bits/stdc++.h>
using namespace std;
# define int long long
# define endl "\n"
const int N = 2e5 + 10, inf = 1e9 + 7;
int b[N];
int a[N];
void solve() {
	int n;
	cin>>n;
	for(int i = 1;i <= n+1;++i) b[i] = a[i] = 0;
	string s1,s2;
	cin>>s1>>s2;
	s1 = "?"+s1;
	s2 = "?"+s2;
	bool ok = true;
	vector<pair<int,int>> ans;
	for(int i = 1;i <= n;++i)//看看两个串是不是本身就为全0
        {
		if(s1[i]!= '0'||s2[i] != '0') {
			ok = false;
			break;
		}
	}
	if(ok){
		cout<<"YES"<<endl;
		cout<<0<<endl;
		return;
	}
	for(int i = 1;i <= n;++i){
		if(s1[i] == '0'){
			ans.push_back({i,i});
			b[1] += 1;//差分维护对b的影响
			b[i]-=1;
			b[i+1] += 1;
		}
	}
	for(int i = 1;i <= n;++i){
		a[i] = a[i-1]+b[i];//前缀和计算对每个位置的影响
	}
	for(int i = 1;i <= n;++i){
		if(a[i]&1){//如果操作次数为奇数则进行变化
			if(s2[i] == '0') s2[i] = '1';
			else s2[i] = '0';
		}
	}
	for(int i = 1;i <= n;++i){
		if(s2[i] != s2[1])//非(全0或者全1)
                {
			cout<<"NO"<<endl;
			return;
		}
	}
	if(s2[1] == '0'){
		ans.push_back({1,n});
	}
	else{
		ans.push_back({1,1});
		ans.push_back({2,n});
	}
	cout<<"YES"<<endl;
	cout<<ans.size()<<endl;
	for(auto [x,y]:ans){
		cout<<x<<" "<<y<<endl;
	}
	
	
	
}
int tt;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	tt = 1;
	cin >> tt;
	while (tt--)solve();


	return 0;
}

D. Count GCD


题目大意:

对于给定n,m,给你一个含n个数的数组,数组中每个数的取值范围在[1,m]

问能构造多少组数组b满足一下条件:

  1. b[i] \(\in\)[1,m]
  2. gcd(b[1],b[2],...,b[i]) = a[i]

解题思路:

基本看到构造多少组b满足以上条件的就可以考虑原数组每一位的贡献了,类似于组合数学是每一位的贡献的积为总的组数
所以总的框架就是

        int ans = 1;
	for(int i = 2;i <= n;++i){
		if(a[i] == a[i-1]){
                        int t = m/a[i];//当前这一位的贡献
			ans = ans*t%mod;//总贡献
		}
		else{
			int t = cal(a[i-1]/a[i],m/a[i]);//当前这一位的贡献
			ans = ans*t%mod;
		}
	}
	cout<<ans<<endl;

然后考虑每一位的贡献是怎么样的形式
我们写两组数据大概可以的到一下的思路:
因为是前缀gcd,所以明显每个数的质因子是不断变小的,然后我们如果要求解b[i]
就有如下思路:gcd(a[i-1],b[i]) = a[i]
那我们要求的其实就是a[i]的倍数,比如a[i-1] = 6,a[i] = 3,那能够满足g(6,b[i]) = 3的只有3的倍数(3,6,9,12,15.....k*3<= m),但是我们很容易就发现6,12是不能选的gcd(6,6||12) = 6,同理如果m/a[i] (所有的倍数)包含a[i-1]/a[i]的质因子的时候就都不能选

所以,问题可以转化为:从[1,m/a[i]]中选与(a[i-1]/a[i])互质的数有多少个

于是引入容斥原理:

Tot = C\(_n\)\(^1\) - C\(_n\)\(^2\) + C\(_n\)\(^3\).....

用韦恩图表示如下:

所以我们就考虑用总的(m/a[i])-res(所有与a[i-1]/a[i]不互质的数的并集)

之所以取与a[i-1]/a[i]不互质的数的并集是因为它比较好表示,用(m/a[i])/(选中的因子的积)就是不互质数的数量
比如从1,2,3,4,5,6中求与2,3不互质的数
实际上就是6-(2的倍数({2,4,6} $\rightarrow$6/2 = 3)+3的倍数({3,6} $\rightarrow$6/3 = 2)-(2*3)的倍数({6} $\rightarrow$6/6 = 1)) = 6-3-2+1 = 2{1,5}

代码实现:

# include<iostream>
# include<bits/stdc++.h>
using namespace std;
# define int long long
# define endl "\n"
const int N = 2e5 + 10, mod = 998244353;
int a[N];
//在[1,top]范围内,找和n互质的数的个数 
int cal(int n,int top){
	vector<pair<int,int>> divisors;//质因子
	for(int i = 2;i*i<=n;++i){
		if(n%i == 0){
			int s  = 0;
			while(n%i == 0) n/=i,s++;
			divisors.push_back({i,s});//i的s次 
		} 
	} 
	if(n>1) divisors.push_back({n,1});
	
	int res = 0,m = divisors.size();
	for(int i = 1;i< (1<<m);++i)//二进制模拟第j个元素选还是不选
      {
		int t = 1,s = 0;
		for(int j = 0;j < m;++j){
			if(i>>j&1){
				if(t*divisors[j].first>top){
					t = -1;
					break;
				}
				t *= divisors[j].first;
				s++;
			}
		}
		if(t != -1)
                {
			if(s%2) res += top/t;//如果选了奇数个元素就是加
			else res -= top/t;//偶数个元素是减
                                          //从容斥原理可以得到
		}
	}
	return top-res;
}

void solve() {
	int n,m;
	cin>>n>>m;
	for(int i = 1;i <= n;++i) cin>>a[i];
	for(int i = 2;i <= n;++i){
		if(a[i-1]%a[i]){
			cout<<0<<endl;
			return;
		}
	}
	int ans = 1;
	for(int i = 2;i <= n;++i){
		if(a[i] == a[i-1]){
			ans = ans*(m/a[i])%mod;
		}
		else{
			int t = cal(a[i-1]/a[i],m/a[i]);
			ans = ans*t%mod;
		}
	}
	cout<<ans<<endl;
	
}
int tt;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	tt = 1;
	cin >> tt;
	while (tt--)solve();


	return 0;
}

标签:int,res,top,容斥,CodeTON,操作,互质,Round,rightarrow
From: https://www.cnblogs.com/empty-y/p/16865632.html

相关文章

  • Codeforces Round #721 (Div. 2) B2. Palindrome Game (hard version)
    ​​传送门​​Theonlydifferencebetweentheeasyandhardversionsisthatthegivenstringsintheeasyversionisinitiallyapalindrome,thisconditioni......
  • Codeforces Round #713 (Div. 3) F
    F.Education考虑贪心显然我们每次只有这样一种情况就是钱够了就升级然后到一个位置就一直不动了不可能我们先在一个位置钱赚够了再赚几轮再去下一级那么证明我们......
  • Educational Codeforces Round 113 (Rated for Div. 2) D
    D.InconvenientPairs观察完样例我们发现发现有且仅有一个共同区间的才是一对这样我们直接记录x,y二分出他在哪个区间内check在共同区间的个数即可但是还有另一种解......
  • Codeforces Round #732 (Div. 1) B
    B.AquaMoonandChess简单计数观察样例我们发现如果是00111100这样是11是随便可以放置在任何地方但是要是011100这样的就会有个单独的1出来我们显然可以这样011......
  • Codeforces Round #832 (Div. 2) D (预处理+二分)
    D.YetAnotherProblem观察题干发现一定要是odd考虑发掘性质发现之后还会将[l,r]长度为奇数的区间全部赋值成这个区间的异或和我们设长度为lenlen-1个偶数个异或为......
  • 背景缩放 background-size
    背景缩放background-sizebackground-size属性规定背景图像的尺寸background-size:背景图片宽度背景图片宽度;单位:长度I百分比lcoverlcontain;cover把背景图像扩......
  • Educational Codeforces Round 138 E,F
    E一道比较基础的题。首先就是纵向,走无障碍的格子,无法四联通和横向,走有障碍的格子,八联通是等价的。也就是,如果我们要让其不存在非法路径,那么应该存在一个从第一列出发,一......
  • 使用AspectJ-@AfterReturning(returning ret),@Around (ProceedingJoinPoint pjp)环绕
    开始使用AspectJ1.[掌握]@AfterReturning后置通知-注解有returning属性在目标方法执行之后执行。由于是目标方法之后执行,所以可以获取到目标方法的返回值。该注解......
  • Educational Codeforces Round 118 D
    D.MEXSequences对于一个数x要是前面出现过0,1,2...x-1我们显然可以将他放在后面要是前面出现过012...x-1x我们也可以将他放在后面但是观察样例还有一种情况......
  • UVA1364 Knights of the Round Table | 点双连通分量
    主要就是一个性质:如果一个点双连通分量中有奇环,那么这个点双连通分量中的每个点都在至少一个奇环中。#include<bits/stdc++.h>usingnamespacestd;constintN=100......