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;
}

CodeTON Round 3 (C.差分维护,D.容斥原理)的更多相关文章

  1. Codeforces Round #258 E Devu and Flowers --容斥原理

    这题又是容斥原理,最近各种做容斥原理啊.当然,好像题解给的不是容斥原理的方法,而是用到Lucas定理好像.这里只讲容斥的做法. 题意:从n个容器中总共取s朵花出来,问有多少种情况.其中告诉你每个盒子中 ...

  2. Experimental Educational Round: VolBIT Formulas Blitz K. Indivisibility —— 容斥原理

    题目链接:http://codeforces.com/contest/630/problem/K K. Indivisibility time limit per test 0.5 seconds m ...

  3. Codeforces Global Round 2 D 差分 + 前缀和 + 二分

    https://codeforces.com/contest/1119/problem/D 题意 有n个数组,每个数组大小为\(10^{18}+1\)且为等差数列,给出n个数组的\(s[i]\),q次 ...

  4. CodeTON Round 3 (Div. 1 + Div. 2, Rated, Prizes!) A-D

    比赛链接 A 题解 知识点:贪心. 注意到 \(a[1] \neq 1\) , \(1\) 永远不可能换到前面:\(a[1] = 1\) 可以交换后面任意元素. 时间复杂度 \(O(n)\) 空间复杂 ...

  5. BZOJ 4999 LCA树状数组差分维护DFS序

    Description 给一颗树,每个节点有个初始值 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x 2. Q i j x(0<=x<2 ...

  6. CodeTON Round 1 (Div. 1 + Div. 2, Rated, Prizes!) A ~ D

    A. 给定一个序列,对于任意1<=k<=n 都满足|ai−ak|+|ak−aj|=|ai−aj|, 找满足条件的i和j并输出 思路: 观察样例,发现输出的是最大值和最小值,那么猜答案是最大 ...

  7. CodeTON Round 2 (Div. 1 + Div. 2, Rated, Prizes!) A-E

    比赛链接 A 题解 知识点:思维,模拟. 发现 \(b\) 串第一个字符是 \(1\) 则只能使用 max , \(0\) 则只能使用 min ,随后只需要模拟到 \(a\) 串剩余 \(m\) 个字 ...

  8. UOJ236 IOI2016 Railroad 差分、欧拉回路、最小生成树

    传送门 将"进入路段时速度\(\leq s_i\)"转换为:"进入路段时速度恰好等于\(s_i\),并且铺设铁轨有加速和减速两种,加速无需代价,减速每\(1 km/h\) ...

  9. BZOJ4538 HNOI2016网络(树链剖分+线段树+堆/整体二分+树上差分)

    某两个点间的请求只对不在这条路径上的询问有影响.那么容易想到每次修改除该路径上的所有点的答案.对每个点建个两个堆,其中一个用来删除,线段树维护即可.由于一条路径在树剖后的dfs序中是log个区间,所以 ...

随机推荐

  1. kubernetes网络排错思想

    Overview 本文将引入一个思路:"在Kubernetes集群发生网络异常时如何排查".文章将引入Kubernetes 集群中网络排查的思路,包含网络异常模型,常用工具,并且提 ...

  2. SpringBoot RabbitMQ 注解版 基本概念与基本案例

    前言 人间清醒 目录 前言 Windows安装RabbitMQ 环境工具下载 Erlang环境安装 RabbitMQ安装 RabbitMQ Web管理端安裝 RabbitMQ新增超级管理员 Rabbi ...

  3. qt unknown type name编译报错记录

    在classA中include class B,然后定义成员变量的时候,报错unknown type name了. 一共有两种可能造成这种问题: 1.circle include,同时在classA中 ...

  4. openstack 搭建详细步骤

    该博文转载于(https://www.cnblogs.com/whwh/p/16200004.html) 一.openstack单点部署 1.配置虚拟机NAT网络连接 查看vmware的NAT网络默认 ...

  5. C++ 由快排学习到的的随机数等知识

    起: 力扣的912题 数组排序 ,想着先用快速排序来写写,在实际用c++编写的时候,有一些之前没注意到的细节问题造成了一些麻烦. 912. 排序数组 - 力扣(LeetCode) 快排思想 每次以数组 ...

  6. 开源即时通讯GGTalk 8.0发布,增加Linux客户端,支持在统信UOS、银河麒麟上运行!

    GGTalk在2021年推出7.0后,经过一年多时间的开发,终于推出8.0版本,实现了Linux客户端. 这几年,信创国产化的势头越来越猛,政府事企业单位都在逐步转向使用国产OS.国产CPU.国产数据 ...

  7. NODE 基于express 框架和mongoDB的cookie和session认证 和图片的上传和删除

    源码地址 https://gitee.com/zyqwasd/mongdbSession 本项目的mongodb是本地的mongodb 开启方法可以百度一下 端口是默认的27017 页面效果 1. 注 ...

  8. Coprime

    Coprime 前置芝士 莫比乌斯反演 正文 首先,我们来分析题意. 题目中给出 \(n\) 个人,每个人有一个编号 \(k\) ,要求我们从中选出 \(3\) 个人,三人编号分别为 \(k_a\) ...

  9. es根据关键词查看某个指定索引的内容并删除

    # 根据关键词查询某个索引的内容 GET product/_search?q=title:测试商品 {"query":{"match_all":{}}} # 根 ...

  10. 内网横向渗透 之 ATT&CK系列一 之 信息收集

    前言 靶机下载地址:ATT&CK 拓扑图: 通过模拟真实环境搭建的漏洞靶场,完全模拟ATK&CK攻击链路进行搭建,形成完整个闭环.虚拟机默认密码为hongrisec@2019. 环境搭 ...