CodeForces - 731D 80-th Level Archeology(线段树+暴力/差分)
题目链接:点击查看
题目大意:给出 n 个数列,再给出一个模数 mod,每次操作可以将所有的数字进行:x = x %mod + 1 操作,问至少进行多少次操作,才能使得 n 个数列按照字典序非降序排列
题目分析:思维不够暴力来凑。。感觉很像是威海线段树维护哈希暴力取模的那个题,事实证明是可以类比过去的
先说我的思路,对于任意两个相邻的数列来说,先找出其首个不相同的位置 pos,然后记录一下其值,在代码中我记做了 a 和 b,因为对于这两个数列来说,a 和 b 的大小关系就直接决定了这两个数列的相对大小关系,所以只需要关注这里即可
然后用线段树维护一下这最多 n - 1 个大小关系,也就是每个节点维护一下每个关系中 b - a 的值,因为我们想要使得 n 个数按照字典序非降序排列,也就是所有的 a <= b ,也就是 b - a >= 0,此时我们就可以暴力枚举更新次数,每次将所有的 a 和 b 都加一,此时考虑三种情况:
- 如果 a > b,且 a == mod,那么在一次更新后,a = 1,且 b - a 的值会发生改变
- 如果 b > a,且 b == mod,那么在一次更新后,b = 1,且 b - a 的值会发生改变
- 否则 b - a 的值不变
不难看出每个关系中的 a 和 b 至多更新一次,因为暴力枚举更新次数的话只需要枚举 [ 0 , mod - 1 ] 就足够了,所以对于每个位置维护一个变量 mmin 用来记录当前节点还剩几次 “加一操作” 后才需要更新即可,这样均摊时间复杂度是 O( nlogn ) 的
然后去网上看了题解,发现果然有简单做法,那就是更需要思维的差分
依然是借助上文中的 a 和 b 继续讲,对于一对相对大小关系 ( a , b ) 来说,仍然是分两种情况讨论一下:
- a > b:更新次数 x 在 [ mod - a + 1 , mod - b ] 内是合法的,也就是满足了 ( x + a )%mod + 1 < ( x + b )%mod + 1
- b > a:同上,更新次数在 [ 0 , mod - b ] 和 [ mod - a + 1 , mod ] 内是合法的
- 没有冲突,比如 123 和 1234,永远是 "123" < "1234":执行任意次操作都符合条件,即 [ 0 , mod ] 内都是可行的
所以我们只需要找到某一个更新次数 i ,使得此时差分数组的前缀和等于 n - 1 就好了
代码:
线段树+暴力
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;int n,m;vector<int>a[N];vector<pair<int,int>>node;struct Node
{int l,r;int mmin;//最小更新时间int delta;//b-aint a,b;int lazy;//最小更新时间的lazy
}tree[N<<2];void pushup(int k)
{tree[k].mmin=min(tree[k<<1].mmin,tree[k<<1|1].mmin);tree[k].delta=min(tree[k<<1].delta,tree[k<<1|1].delta);
}void pushdown(int k)
{if(tree[k].lazy){int lz=tree[k].lazy;tree[k].lazy=0;tree[k<<1].lazy+=lz;tree[k<<1|1].lazy+=lz;tree[k<<1].mmin+=lz;tree[k<<1|1].mmin+=lz;}
}void build(int k,int l,int r)
{tree[k].l=l;tree[k].r=r;tree[k].lazy=0;if(l==r){int a,b;tie(a,b)=node[l-1];tree[k].mmin=min(m-a+1,m-b+1);tree[k].delta=b-a;tree[k].a=a;tree[k].b=b;return;}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k);
}void update()
{tree[1].mmin--;tree[1].lazy--;
}void update(int k)
{if(tree[k].mmin>0)return;if(tree[k].l==tree[k].r){if(tree[k].a>tree[k].b){tree[k].b+=m-tree[k].a+1;tree[k].a=1;tree[k].delta=tree[k].b-tree[k].a;tree[k].mmin=m-tree[k].b+1;}else{tree[k].a+=m-tree[k].b+1;tree[k].b=1;tree[k].delta=tree[k].b-tree[k].a;tree[k].mmin=m-tree[k].a+1;}return;}pushdown(k);update(k<<1);update(k<<1|1);pushup(k);
}int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){int num;scanf("%d",&num);for(int j=1;j<=num;j++){int x;scanf("%d",&x);a[i].push_back(x);}}for(int i=2;i<=n;i++)//查找相邻两个数列中的a和b{bool flag=(a[i-1].size()>a[i].size());for(int j=0;j<min(a[i].size(),a[i-1].size());j++){if(a[i][j]==a[i-1][j])continue;node.push_back(make_pair(a[i-1][j],a[i][j]));flag=false;break;}if(flag)//特判1234和123的情况return 0*puts("-1");}if(node.empty())//没有冲突,无需更改return 0*puts("0");build(1,1,node.size());for(int i=0;i<=m;i++){if(tree[1].delta>0)return 0*printf("%d\n",i);update();update(1);}puts("-1");return 0;
}
差分:
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;vector<int>a[N];int delta[N];int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){int num;scanf("%d",&num);for(int j=1;j<=num;j++){int x;scanf("%d",&x);a[i].push_back(x);}}for(int i=2;i<=n;i++)//查找相邻两个数列中的a和b{bool flag=true;for(int j=0;j<min(a[i].size(),a[i-1].size());j++){if(a[i][j]==a[i-1][j])continue;int x=a[i-1][j],y=a[i][j];if(x>y){delta[m-x+1]++;delta[m-y+1]--;}else{delta[0]++;delta[m-y+1]--;delta[m-x+1]++;delta[m]--;}flag=false;break;}if(flag){if(a[i-1].size()>a[i].size())//特判1234和123的情况return 0*puts("-1");else//特判123和1234的情况{delta[0]++;delta[m]--;}}}int sum=0;for(int i=0;i<m;i++){sum+=delta[i];if(sum==n-1)return 0*printf("%d\n",i);}puts("-1");return 0;
}
CodeForces - 731D 80-th Level Archeology(线段树+暴力/差分)相关推荐
- 【codeforces 731D】80-th Level Archeology
[题目链接]:http://codeforces.com/contest/731/problem/D [题意] 给你n个象形文; 每个象形文由l[i]个数字组成; 你可以把所有的组成象形文的数字同时增 ...
- Codeforces 1004F Sonya and Bitwise OR (线段树)
题目链接 https://codeforces.com/contest/1004/problem/F 题解 这种水题都不会做了怎么.. 考虑一个序列的前缀 \(\text{or}\) 值只会变化 \( ...
- CodeForces - 1529E Trees of Tranquillity(贪心+线段树)
题目链接:https://vjudge.net/problem/CodeForces-1529E 题目大意:给出两棵根节点为 111 的树,分别称为 AAA 树和 BBB 树,现在通过两棵树可以构造出 ...
- Codeforces Round #723 (Div. 2) D. Kill Anton 线段树 + 暴力
传送门 文章目录 题意: 思路: 题意: 给你一个只有ANTOANTOANTO四个字母的字符串,你每次可以交换相邻两个,花费为111,让后让你打乱字符串,使得将打乱的字符串还原为原来的字符串的花费最小 ...
- Codeforces 1045. A. Last chance(网络流 + 线段树优化建边)
题意 给你 \(n\) 个武器,\(m\) 个敌人,问你最多消灭多少个敌人,并输出方案. 总共有三种武器. SQL 火箭 - 能消灭给你集合中的一个敌人 \(\sum |S| \le 100000\) ...
- [codeforces] 383C Propagating tree(dfs序+线段树)
题意: 给你一棵n个结点的树, 以1为根.每个结点有点权.有m次操作: 1.x结点权值 +val,x的儿子权值 −val,x的孙子们 +val,以此类推. 2.询问x的点权: 题解: 我们首先跑一边d ...
- CodeForces - 1217F Forced Online Queries Problem(线段树分治+并查集撤销)
题目链接:点击查看 题目大意:给出 nnn 个点,初始时互相不存在连边,需要执行 mmm 次操作,每次操作分为两种类型: 1xy1 \ x \ y1 x y:如果 (x,y)(x,y)(x,y) 之间 ...
- CodeForces - 504B Misha and Permutations Summation(线段树模拟康托展开与逆展开)
题目链接:点击查看 题目大意:给出两个排列 ppp 和 qqq,现在要求输出 Perm((Ord(p)+Ord(q))modn!)Perm((Ord(p)+Ord(q)) \bmod n!) Perm ...
- codeforces CF438D The Child and Sequence 线段树
$ \Rightarrow $ 戳我进CF原题 D. The Child and Sequence time limit per test: 4 seconds memory limit per te ...
最新文章
- 一个KVO 实现WKWebView加载进度条的例子 (注意最后移除观察者)
- 数据结构--折半查找法 详解
- 计算机不会输入函数怎么办,函数不正确_电脑上文件打不开,显示函数不正确怎么解决?...
- android phonegap 服务器ip配置,android + phoneGap 环境搭建
- mysql数据库恢复数据_【技术分享】使用Innodb存储引擎的mysql数据库恢复
- python 规则引擎 drools_Drools规则引擎入门demo
- SIP中第三方呼叫控制(3PCC)建立流程
- 电脑双系统--我想体验不一样的感觉
- error: ignoring return value of 编译错误处理
- Javascript 编程风格
- 计算机毕设 SpringBoot+Vue旧物置换系统 旧物交易管理系统 旧物二手交易系统Java Vue MySQL数据库 远程调试 代码讲解
- 管理好项目——带好技术团队的秘籍
- Ubuntu 18.04 中Chrome浏览器安装与使用
- docker push 过程 distribution源码 分析
- java基于ssm的道路求援车队管理系统
- (改进GM(1,1)模型)灰色残差马尔科夫预测模型的matlab实现
- 基于docker安装的rabbitmq如何安装rabbitmq_delayed_message_exchange-3.8.0.ez插件
- laravel物流地址查询
- 智能垃圾桶(八)——红外对管传感器(树莓派pico)
- repeater导出excel html,Repeater控件数据导出Excel(附演示动画)