T1 好数

设ctz(x)为x二进制下末尾0的个数,如ctz(1001000)=3。

设ppc(x)为x二进制下1的个数,如ppc(1001000)=2。

定义一个数是好数,当且仅当ctz(x)=ppc(x)。

给定Q,有Q次询问,每次给出区间[l,r],你需要求出[l,r]中任意一个好数,或判断无输出-1。

考虑逐位模拟,我们从大到小考虑,如果 \(x\) 非法时如何操作。

  • \(\operatorname{ctz}(x) > \operatorname{ppc}(x)\) 时,我们将 \(x\) 减去 \(1\),再去考虑新的数。

  • \(\operatorname{ctz}(x) < \operatorname{ppc}(x)\) 时,我们将 \(x\) 减去 \(\operatorname{lowbit}(x)\),此时一定是一个最接近 \(x\) 的可能的合法操作,减少一个 \(1\) 的同时增加一个 \(0\),因为对于 \((x -\operatorname{lowbit}(x), x]\) 中一定不存在合法的 \(x\),否则 \(1\) 比末尾 \(0\) 多。

时间复杂度 \(O(Q\log{n} \sim Q\log^2{n})\),但上界是远远达不到的。

参考代码

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull; int ctz(ull x)
{
x = x & -x;
int cnt = 0;
while (x) x >>= 1, cnt ++ ;
return cnt - 1;
} void solve()
{
ull l, r;
cin >> l >> r;
while (r >= l)
{
if (__builtin_popcount(r) < ctz(r)) r -- ;
else if (__builtin_popcount(r) > ctz(r)) r -= r & -r;
else return cout << r << "\n", void();
}
cout << "-1\n";
} int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL), cout.tie(NULL);
int T;
cin >> T;
while (T -- ) solve();
return 0;
}

T2 排序

今天是YQH的生日,她得到了一个长度为n排列a1,a2,...,an 作为生日礼物,这 个排列包含了 1,2,...,n 里每个元素恰好一次。

由于YQH十分喜欢升序,于是她打算把这个排列进行排序使得最后排列升序。

但是她发现一个问题:她太笨了,不会各种O(nlogn)的排序算法,于是她退而求次,准备使用O(n) 的“斯大林排序”。

斯大林排序是这样一个过程:

假设我们要排序的序列是a1,a2,...,an,那么维护一个初始为空的栈,然后从 1 到 n 枚 举i:

• 假如ai 比栈顶严格大或者栈为空,那么把ai加入栈中。

• 否则,此刻有ai小于等于栈顶,那么什么都不干。

最后把栈里的元素从底到顶输出作为结果。

容易发现,这样我们获得就是原排列的一个上升子序列,但是可能会失去太多的元 素,比如假如我们要排序[5,1,2,3,4],我们最后只得到了 [5]。

于是YQH进行了改进,现在排序变成这样一个过程:

假设我们要排序的序列是a1,a2,...,an,那么维护一个初始为空的栈,然后从 1 到 n 枚举 i:

• 假如 ai 比栈顶严格大或者栈为空,那么把ai加入栈中。

• 否则,此刻有 ai 小于等于栈顶,那么有两种选择:把栈顶弹出并把ai加入栈中, 或什么都不干。

注意,你需要保证任意时刻,栈中的元素从底到顶严格单调上升。

最后把栈里的元素从底到顶输出作为结果。

比如现在我们要排序[5,1,2,3,4],栈的变化是 [] → [5] → [1] → [1,2] → [1,2,3] → [1,2,3,4]。

容易发现,最后栈的大小与排序时进行的选择有关。YQH当然希望最后栈越大越 好,于是她找到了你,希望你对于她给出的排列,求出最后栈大小的最大值。

容易发现,对于一个位置的 \(a_i\),所有后续连续的 \(a_j < a_i(j > i)\),我们是可以进行删除或替换当前 \(a_i\) 操作的,记 \(ne_i = \min(\{j \mid a_j > a_i, j > i\})\),但 \(dp_i\) 对 \(a_j > a_i, j \in [ne_i, ne_{ne_i})\) 的 \(dp_j\) 均有贡献,合法的 \(j\) 是离散的,这并不好办到,因此我们考虑从值域入手。

设 \(dp_i\) 表示以 \(i\) 结尾的栈并且栈不弹出 \(i\) 的最大长度,从 \(1 \sim n\) 枚举考虑能否对答案进行贡献,由上面的定义可知,对 \(i\) 的合法转移是删除 \(i\) 后比 \(i\) 小区间段,即 \(dp_j = \max(dp_j, dp_i + 1), j \in [ne_i, ne_{ne_i})\),我们用线段树对区间段进行赋值即可。

时间复杂度 \(O(n\log{n})\)。

参考代码

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int n;
int a[N], p[N], ne[N], dp[N];
struct Node
{
int l, r, sum;
}tr[N << 2]; void build(int u, int l, int r)
{
tr[u] = {l, r, -100000};
if (l == r) return;
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
} void modify(int u, int l, int r, int d)
{
if (tr[u].l >= l && tr[u].r <= r) return tr[u].sum = max(tr[u].sum, d), void();
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) modify(u << 1, l, r, d);
if (r > mid) modify(u << 1 | 1, l, r, d);
} int query(int u, int l, int r)
{
if (tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
int mid = tr[u].l + tr[u].r >> 1;
int res = tr[u].sum;
if (l <= mid) res = max(res, query(u << 1, l, r));
if (r > mid) res = max(res, query(u << 1 | 1, l, r));
return res;
} void solve()
{
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> a[i], p[a[i]] = i;
ne[n + 1] = a[n + 1] = n + 1;
for (int i = n; i >= 0; i -- )
{
ne[i] = i + 1;
while (a[ne[i]] < a[i]) ne[i] = ne[ne[i]];
}
build(1, 1, n);
int ans = 0;
for (int i = 0; i <= n; i ++ )
{
int u = p[i];
int l = ne[u], r = ne[l] - 1;
if (u) dp[u] = query(1, u, u) + 1;
if (l <= r) modify(1, l, r, dp[u]);
ans = max(ans, dp[u]);
}
cout << ans << "\n";
} int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL), cout.tie(NULL);
int T = 1;
while (T -- ) solve();
return 0;
}

T3 图同构

有两张边集相同的图A,B,每个点都是红黑二色之一,并且带着点权ai。

你可以依次执行以下操作零次或任意次:

  1. 选择一张图和相邻的两个点u,v。
  2. 交换au 和av。
  3. 如果u和v 同色,则将他们同时反色,否则颜色保持不变。

    你想要知道,两张图能否变得相同,即所有点的颜色和点权对应相同。

    从标准输入中读入数据。

本题多测。

第一行包含一个整数T 表示数据组数。

对于每组数据: 第一行两个整数n,m表示点的个数和边的个数。

接下来m行每行两个整数u,v表示一条边。

接下来一行n个整数,第i个整数ai表示A上第i个点的点权。

接下来一行一个长为n的字符串,第i个字符ci表示A上第i个点的颜色,为‘R‘ 或‘B‘。

接下来一行n个整数,第i个整数bi表示B上第i个点的点权。

接下来一行一个长为n的字符串,第i个字符di 表示B 上第i个点的颜色,为 ‘R‘ 或 ‘B‘。

对于所有数据,保证1≤T ≤3×104,1 ≤ n,∑n ≤ 106,0 ≤ m,∑m ≤ 106,1 ≤ u, v ≤ n,0 ≤ ai,bi ≤ 109,ci,di ∈ {′R′,′B′},图中无重边无自环。

对于相邻两点的操作,不妨考虑交换两个点权时候,同时交换了颜色并取反,可以发现这个操作恰好是满足上面操作的条件的。

因此我们转化问题形式为,对于每个点 \(u\) 具有二元组 \(\{a_u, c_u\}\),每个点有一个终点,在移动过程中 \(a_u\) 保持不变,\(c_u\) 在每次移动一条边后取反,我们想要交换两个点,可以移动后使得中间的点不变化,仅改变这两个点的二元组,两个点的二元组变化与否之和他们之间有奇数还是偶数条边有关,容易发现这个题可以分为偶图奇图,对于每一个联通块可以独立讨论。

  • 联通块为偶图时,可以划分为左右两边的点集,使得点集内部没有边,因此对于两张图的相同权值的点左侧红点 \(+\) 右侧黑点数量相等,左侧黑点 \(+\) 右侧红点数量相等,因为通过移动这些点,容易发现两类点在移动过程中仍属于同一部分。

  • 联通块为奇图时,容易发现可以将一个点绕着奇环转一圈,使得颜色取反,同样的,由于一个点颜色取反,必有另一个点颜色取反,因此,我们只需要考虑一共有多少个点需要将颜色取反,如果为偶数个,那么可以满足,否则不能满足。

按照上述讨论,可以完成此题,时间复杂度 \(O(n\log{n} + q)\)。

参考代码

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 10;
int n, m;
int a1[N], a2[N], h[N], e[N << 1], ne[N << 1], idx;
int color[N];
char s1[N], s2[N];
vector<PII> now1, now2;
int pd; void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
} void dfs(int u)
{
now1.push_back({a1[u], u});
now2.push_back({a2[u], u});
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (color[j])
{
if (color[j] == color[u]) pd = 1;
}
else
{
if (color[u] == 1) color[j] = 2;
else color[j] = 1;
dfs(j);
}
}
} void solve()
{
cin >> n >> m, idx = 0;
for (int i = 1; i <= n; i ++ ) h[i] = -1, color[i] = 0;
for (int i = 1; i <= m; i ++ )
{
int u, v;
cin >> u >> v;
add(u, v), add(v, u);
}
for (int i = 1; i <= n; i ++ ) cin >> a1[i];
for (int i = 1; i <= n; i ++ ) cin >> s1[i];
for (int i = 1; i <= n; i ++ ) cin >> a2[i];
for (int i = 1; i <= n; i ++ ) cin >> s2[i];
for (int i = 1; i <= n; i ++ )
{
if (!color[i])
{
pd = 0, color[i] = 1;
now1.clear(), now2.clear();
dfs(i);
if (!pd)
{
sort(now1.begin(), now1.end());
sort(now2.begin(), now2.end());
int cnt1 = 0, cnt2 = 0;
for (int i = 0; i < now1.size(); i ++ )
{
int u = now1[i].second, v = now2[i].second;
if (now1[i].first != now2[i].first) return cout << "NO\n", void();
if (i && now1[i].first != now1[i - 1].first)
{
if (cnt1 || cnt2) return cout << "NO\n", void();
cnt1 = cnt2 = 0;
}
if (color[u] == 1)
{
if (s1[u] == 'R') cnt1 ++ ;
else cnt2 ++ ;
}
else
{
if (s1[u] == 'R') cnt2 ++ ;
else cnt1 ++ ;
}
if (color[v] == 1)
{
if (s2[v] == 'R') cnt1 -- ;
else cnt2 -- ;
}
else
{
if (s2[v] == 'R') cnt2 -- ;
else cnt1 -- ;
}
}
if (cnt1 || cnt2) return cout << "NO\n", void();
}
else
{
sort(now1.begin(), now1.end());
sort(now2.begin(), now2.end());
int cnt = 0;
for (int i = 0; i < now1.size(); i ++ )
{
int u = now1[i].second, v = now2[i].second;
if (now1[i].first != now2[i].first) return cout << "NO\n", void();
if (s1[u] != s2[v]) cnt ++ ;
}
if (cnt & 1) return cout << "NO\n", void();
}
}
}
cout << "YES\n";
} int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T -- ) solve();
return 0;
}

NZOJ NOIP模拟赛1的更多相关文章

  1. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  2. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  3. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

  4. 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程

    数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...

  5. 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...

  6. 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...

  7. 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...

  8. CH Round #58 - OrzCC杯noip模拟赛day2

    A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...

  9. CH Round #52 - Thinking Bear #1 (NOIP模拟赛)

    A.拆地毯 题目:http://www.contesthunter.org/contest/CH%20Round%20%2352%20-%20Thinking%20Bear%20%231%20(NOI ...

  10. CH Round #49 - Streaming #4 (NOIP模拟赛Day2)

    A.二叉树的的根 题目:http://www.contesthunter.org/contest/CH%20Round%20%2349%20-%20Streaming%20%234%20(NOIP 模 ...

随机推荐

  1. 解决gedit报错无法打开的问题

    彻底解决关于gedit的Unable to init server: 无法连接: 拒绝连接_BD_Marathon的博客-CSDN博客_unable to init server: 无法连接: 拒绝连 ...

  2. Java 实现线程的方式有几种方式?带有返回值的线程怎么实现?

    Java 实现线程的方式有几种方式?带有返回值的线程怎么实现? 在Java线程开发中,有几种方法开启线程?假如需要得到线程返回的信息怎么办?可以实现吗?凯哥将通过源码和大家一起分享下线程怎么将返回值带 ...

  3. Gson toJson 忽略 long 为 0的数据

    起因于数据id过大,所以将对应int , Integer都修改为long, 测试过程中发现 Gson toJson时,字段将int为0的数据忽略,但long 没有, 所以 1. 新增适配器 impor ...

  4. OpenCV开发笔记(八十):基于特征点匹配实现全景图片拼接

    前言   一个摄像头视野不大的时候,我们希望进行两个视野合并,这样让正视的视野增大,从而可以看到更广阔的标准视野.拼接的方法分为两条路,第一条路是Sticher类,第二条思路是特征点匹配.  本篇使用 ...

  5. 今日算法随笔:填充每个节点的下一个右侧节点指针 II

    题目链接:117. 填充每个节点的下一个右侧节点指针 II 题目描述 给定一个二叉树,填充它的每个 next 指针,让这个指针指向其下一个右侧节点.如果找不到下一个右侧节点,则将 next 指针设置为 ...

  6. fluent python-chap2

    1. 内置序列类型 容器序列: list tuple collections.deque 可以存放不同类型的数据. 存放的是它们所包含的任意类型的对象的引用. 扁平序列: str bytes byte ...

  7. Google Analytics & Ads 学习笔记 2 (gtag 版本)

    gtag 是用来取代之前的 ga 的 但其实它底层就是调用 ga 而已. 只是封装了一个上层. 1. start up script <script async src="https: ...

  8. 图解YUV420、YUV420(YUY2)、YUV422(YVYU)

    Y:亮度分量    UV:色度分量 1.  标准yuv指的是yuv420 一般看文章,会出现下面的公式,但不涉及具体的yuv格式,其实这一定指的是yuv420 Y与RGB的演算关系为:Y = 0.21 ...

  9. Java远程连接服务器实现文件上传下载及目录操作

    详情请阅读原文 在其基础之上做了进一步的封装 <!-- https://mvnrepository.com/artifact/com.jcraft/jsch --> <depende ...

  10. 基于 Nginx 的大型互联网集群架构与实战方案

    1. Nginx 负载均衡基础配置 首先,搭建一个基础的 Nginx 负载均衡器,用于将流量分发到多个后端服务器上. 步骤 1.1:安装 Nginx 在每台要作为负载均衡器的服务器上,安装 Nginx ...