【安徽集训】fiend
- 考试的时候只会 \(O(Tn^3)\) 的做法,其它题还都不会,想到一整场就打这么点是人都能写的暴力没啥意思,就懒得写了。。
Description
双人博弈。每一轮 A 和 B 同时选择一个 \(1\text{~} n\) 的排列 \(P_i\),必须满足 \(L_i\le P_i\le R_i\)。同时,A 选择的排列的逆序对数必须是偶数,B 选择的排列的逆序对数必须是奇数(显然 A 的排列和 B 的排列不可能相同)。每一轮选择的排列不能和之前出现过的排列相同。先无法选择排列的输,若双方同时无法选择排列则和局。
\(T\) 组数据,每次给定 \(n,L_i,R_i\),求游戏的结果。

Solution
就是让你比逆序对数是奇数的排列多 还是是偶数的排列多。
前置知识:行列式
看到逆序对计数,我们很容易想到行列式。
因为行列式的公式是 $$det(a) = \sum\limits_{p_{1\cdots n}} (-1)^{\sigma(p)} \prod\limits_{i=1}^n a_{i,p_i}$$ 其中 \(p\) 为 \(1\) 到 \(n\) 的任意排列,\(\sigma(p)\) 表示排列 \(p\) 的逆序对数。
这个公式本身就和逆序对数有关系。
其中排列 \(p\) 等价于本题中 A 和 B 选择的排列。
然后关键就是后面那个 \(\prod\limits_{i=1}^n a_{i,p_i}\) 的意义。
显然,只要有一个 \(a_{i,p_i}\) 为 \(0\),这个式子就为 \(0\)。
那么不难想到,对于一组限制 \(L_i\le P_i\le R_i\),可以将矩阵的第 \(i\) 行的第 \(L_i\) 到 \(R_i\) 位设为 \(1\),其余位设为 \(0\)。
这样 \(\prod\limits_{i=1}^n a_{i,p_i} = 1\) 当且仅当排列 \(p\) 中的每一个数 \(p_i\) 都满足限制 \(L_i\le p_i\le R_i\)。其余情况下 \(\prod\limits_{i=1}^n a_{i,p_i} = 0\),表示不满足限制。
现在只有所有满足限制的排列 \(p\) 才会被计算一次,下面考虑 \(\sum\limits_{p_{1\cdots n}} (-1)^{\sigma(p)}\)。
这就是把逆序对数为奇数的排列 \(p\) 的权值记为 \(-1\),逆序对数为偶数的排列 \(p\) 的权值记为 \(1\)。
所以最后算出来的行列式的值 \(det(a) = 满足条件的逆序对数为偶数的排列数 - 满足条件的逆序对数为奇数的排列数\)
直接判断 \(det(a)\) 是 \(\gt 0\),\(\lt 0\) 还是 \(=0\) 就好了。
那行列式 \(det(a)\) 的值怎么算?
最暴力的是 \(O(n^3)\) 的高斯消元做法,即把行列式高消成上三角,对角线上所有数的乘积 就是行列式的值。
因为有 \(100\) 组数据,这个做法只能得 \(35\) 分,但在高消时判断若 \(a_{i,i}=0\) 则直接返回行列式值为 \(0\),可以卡到 \(70\) 分。
观察到矩阵中所有数都是 \(0,1\),而且每行只有一个连续段是 \(1\),其余位置都是 \(0\)。那么可以优化高消过程。
依然从小到大枚举 \(x\),找到左端点为 \(x\) 的右端点最小的区间,设其右端点为 \(y\),则模拟高消过程,其余左端点为 \(x\) 的区间的左端点都会被挪到 \(y+1\)。
把所有全 \(1\) 连续段按左端点分类,那么这一轮高消就是把左端点为 \(x\) 的集合 合并到左端点为 \(y+1\) 的集合。
同时我们还要支持查询一个集合中的最小值(集合中存储所有连续段的右端点)。
左偏树即可。
复杂度 \(O(Tn\log n)\)。
#include<bits/stdc++.h>
#define N 100002
using namespace std;
inline int read(){
int x=0; bool f=1; char c=getchar();
for(;!isdigit(c); c=getchar()) if(c=='-') f=0;
for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
if(f) return x;
return 0-x;
}
int n,l[N],r[N],siz,rt[N],ch[N][2],dis[N],lst[N];
bool vis[N];
int merge(int x, int y){
if(!x || !y) return x|y;
if(r[x]>r[y]) swap(x,y);
ch[x][1] = merge(ch[x][1],y);
if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
dis[x] = dis[ch[x][1]]+1;
return x;
}
inline void ins(int L, int x){
rt[L] = merge(rt[L], x);
}
inline int popNode(int x){
return merge(ch[x][0], ch[x][1]);
}
int solve(){
for(int i=1; i<=n; ++i) rt[i]=ch[i][0]=ch[i][1]=dis[i]=0, vis[i]=0;
for(int i=1; i<=n; ++i) ins(l[i],i);
int ans=1;
for(int i=1; i<=n; ++i){
int x=rt[i];
if(!x) return 0;
rt[i] = popNode(x);
lst[i] = x;
if(rt[i] && r[rt[i]]==r[x]) return 0;
rt[r[x]+1] = merge(rt[i], rt[r[x]+1]);
}
if(ans==0) return 0;
int tot = n;
for(int i=1; i<=n; ++i) if(!vis[i]){
--tot; int x=i;
do{
vis[x]=1, x=lst[x];
}while(x!=i);
}
if(tot&1) ans=-ans;
return ans;
}
int main(){
int T=read();
while(T--){
n=read();
for(int i=1; i<=n; ++i) l[i]=read(), r[i]=read();
int ans=solve();
if(ans==1) puts("Y");
else if(ans==-1) puts("F");
else puts("D");
}
return 0;
}
/*
3
1
1 1
2
2 2
1 1
2
1 2
1 2
*/
【安徽集训】fiend的更多相关文章
- 【安徽集训】Emerald
Description \(n\) 座城市在数轴上,第 \(i\) 座城市有一条连向第 \(i+1\) 座城市的单向边.每座城市有一个类型 A/B 以及一个非负整数人口,A 类城市的人觉得自己的城市比 ...
- 【安徽集训】Entropy
出题人罗哲正是神爷 Orz Description 这是一道披着交互题外衣的通信题,只支持 C++. 你需要实现 \(2\) 个函数. 交互库先给第一个函数传入一个参数 \(n\),你加密得到的 \( ...
- [BZOJ2599][Race][IOI2011]点分治
这是为了真正去学一下点分治..然后看了迪克李的ppt 又是一道写(改)了很久的题..终于ac了 1354799 orzliyicheng 2599 Accepted 31936 kb 23584 ms ...
- NOI2017 酱油记
侥幸混进市队让我晚退役了几个月..不过终究还是退役了呢..这应该是最后一篇游记了吧.. 考前半个月都在安徽集训..然后发现所有人都停课集训..只有我暑假了开始.. 反正上课各种听不懂..各种被大佬虐. ...
- QDEZ集训笔记【更新中】
这是一个绝妙的比喻,如果青岛二中的台阶上每级站一只平度一中的猫,差不多站满了吧 自己的理解 [2016-12-31] [主席树] http://www.cnblogs.com/candy99/p/61 ...
- DP/最短路 URAL 1741 Communication Fiend
题目传送门 /* 题意:程序从1到n版本升级,正版+正版->正版,正版+盗版->盗版,盗版+盗版->盗版 正版+破解版->正版,盗版+破解版->盗版 DP:每种情况考虑一 ...
- Ural 1741 Communication Fiend(隐式图+虚拟节点最短路)
1741. Communication Fiend Time limit: 1.0 second Memory limit: 64 MB Kolya has returned from a summe ...
- 2015UESTC 暑假集训总结
day1: 考微观经济学去了…… day2: 一开始就看了看一道题目最短的B题,拍了半小时交了上去wa了 感觉自己一定是自己想错了,于是去拍大家都过的A题,十分钟拍完交上去就A了 然后B题写了一发暴力 ...
- JS省队集训记
不知不觉省队集训已经结束,离noi也越来越近了呢 论考前实战训练的重要性,让我随便总结一下这几天的考试 Day 1 T1 唉,感觉跟xj测试很像啊?meet in middle,不过这种题不多测是什么 ...
随机推荐
- JoinableQueue队列,线程,线程于进程的关系,使用线程,线程的特点,守护线程,线程的互斥锁,死锁问题,递归锁,信号量
1.JoinableQueue队列 JoinableQueue([maxsize]):这就像是一个Queue对象,但是队列允许项目的使用者通知生成者项目已经被成功处理.通知进程是使用共享的信号和条件变 ...
- 【FFMPEG】使用ffmpeg类库打开流媒体
版权声明:本文为博主原创文章,未经博主允许不得转载. 使用ffmpeg类库进行开发的时候,打开流媒体(或本地文件)的函数是avformat_open_input(). 其中打开网络流的话,前面要加上函 ...
- Java学习笔记-GUI
Java也提供图像化编程 图形化 GUI(图形用户界面) GUI Graphical User Interface(图形用户接口) 用图形的方式,来显示计算机操作的界面,这样更方便更直观 CLI Co ...
- ip地址查询python3小工具_V0.0.1
看到同事在一个一个IP地址的百度来确认导出表格中的ip地址所对应的现实世界的地址是否正确,决定给自己新开一个坑.做一个查询ip“地址”的python小工具,读取Excel表格,在表格中的后续列输出尽可 ...
- Oracle导入/导出某个用户下的数据库
导出 exp用户名/密码@数据库实例owner=用户名file=文件存储路径 例如:exp MM/123456@ORCL owner=MM file=F\abcd.dmp 导入 imp用户名/密码@数 ...
- 2019牛客暑期多校训练营(第二场) - B - Eddy Walker 2 - BM算法
参考于: https://www.luogu.org/problemnew/solution/P4723 shadowice1984 (太难) https://www.cnblogs.com/zhgy ...
- Jmeter之压测探索和结果分析
1.copy过来的,很有道理的一句话~ 最大并发数:取决于你的业务类型,数据量,处理时的资源需求等,具体多少,需要做一些性能测试来衡量 确定待测试的场景,设计脚本,不断增加并发数量. 2.CPU压不上 ...
- 链表分割——牛客剑指offer
题目描述: 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 给定一个链表的头指针 ListNode pHead,请返回重新排列后的链表的头指针.注意:分割以后 ...
- 8.bash编辑命令行
8.编辑命令行本章介绍 GNU 命令行编辑界面的基本功能.命令行编辑是 Readline 库提供的:这个库被几个不同的程序共用,Bash 是其中一个.使用交互式的 shell 时,默认已经打开了命令行 ...
- java lesson14Homework
/** * 1. 本程序找出字符串数组 String[] arr = {“welcome”, “china”, “hi”, “congratulation”, “great”} 中的长度最大的元素,并 ...