题目链接:点击查看

题目大意:给出 n 个数列,再给出一个模数 mod,每次操作可以将所有的数字进行:x = x %mod + 1 操作,问至少进行多少次操作,才能使得 n 个数列按照字典序非降序排列

题目分析:思维不够暴力来凑。。感觉很像是威海线段树维护哈希暴力取模的那个题,事实证明是可以类比过去的

先说我的思路,对于任意两个相邻的数列来说,先找出其首个不相同的位置 pos,然后记录一下其值,在代码中我记做了 a 和 b,因为对于这两个数列来说,a 和 b 的大小关系就直接决定了这两个数列的相对大小关系,所以只需要关注这里即可

然后用线段树维护一下这最多 n - 1 个大小关系,也就是每个节点维护一下每个关系中 b - a 的值,因为我们想要使得 n 个数按照字典序非降序排列,也就是所有的 a <= b ,也就是 b - a >= 0,此时我们就可以暴力枚举更新次数,每次将所有的 a 和 b 都加一,此时考虑三种情况:

  1. 如果 a > b,且 a == mod,那么在一次更新后,a = 1,且 b - a 的值会发生改变
  2. 如果 b > a,且 b == mod,那么在一次更新后,b = 1,且 b - a 的值会发生改变
  3. 否则 b - a 的值不变

不难看出每个关系中的 a 和 b 至多更新一次,因为暴力枚举更新次数的话只需要枚举 [ 0 , mod - 1 ] 就足够了,所以对于每个位置维护一个变量 mmin 用来记录当前节点还剩几次 “加一操作” 后才需要更新即可,这样均摊时间复杂度是 O( nlogn ) 的

然后去网上看了题解,发现果然有简单做法,那就是更需要思维的差分

依然是借助上文中的 a 和 b 继续讲,对于一对相对大小关系 ( a , b ) 来说,仍然是分两种情况讨论一下:

  1. a > b:更新次数 x 在 [ mod - a + 1 , mod - b ] 内是合法的,也就是满足了 ( x + a )%mod + 1 < ( x + b )%mod + 1
  2. b > a:同上,更新次数在 [ 0 , mod - b ] 和 [ mod - a + 1 , mod ] 内是合法的
  3. 没有冲突,比如 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(线段树+暴力/差分)相关推荐

  1. 【codeforces 731D】80-th Level Archeology

    [题目链接]:http://codeforces.com/contest/731/problem/D [题意] 给你n个象形文; 每个象形文由l[i]个数字组成; 你可以把所有的组成象形文的数字同时增 ...

  2. Codeforces 1004F Sonya and Bitwise OR (线段树)

    题目链接 https://codeforces.com/contest/1004/problem/F 题解 这种水题都不会做了怎么.. 考虑一个序列的前缀 \(\text{or}\) 值只会变化 \( ...

  3. CodeForces - 1529E Trees of Tranquillity(贪心+线段树)

    题目链接:https://vjudge.net/problem/CodeForces-1529E 题目大意:给出两棵根节点为 111 的树,分别称为 AAA 树和 BBB 树,现在通过两棵树可以构造出 ...

  4. Codeforces Round #723 (Div. 2) D. Kill Anton 线段树 + 暴力

    传送门 文章目录 题意: 思路: 题意: 给你一个只有ANTOANTOANTO四个字母的字符串,你每次可以交换相邻两个,花费为111,让后让你打乱字符串,使得将打乱的字符串还原为原来的字符串的花费最小 ...

  5. Codeforces 1045. A. Last chance(网络流 + 线段树优化建边)

    题意 给你 \(n\) 个武器,\(m\) 个敌人,问你最多消灭多少个敌人,并输出方案. 总共有三种武器. SQL 火箭 - 能消灭给你集合中的一个敌人 \(\sum |S| \le 100000\) ...

  6. [codeforces] 383C Propagating tree(dfs序+线段树)

    题意: 给你一棵n个结点的树, 以1为根.每个结点有点权.有m次操作: 1.x结点权值 +val,x的儿子权值 −val,x的孙子们 +val,以此类推. 2.询问x的点权: 题解: 我们首先跑一边d ...

  7. CodeForces - 1217F Forced Online Queries Problem(线段树分治+并查集撤销)

    题目链接:点击查看 题目大意:给出 nnn 个点,初始时互相不存在连边,需要执行 mmm 次操作,每次操作分为两种类型: 1xy1 \ x \ y1 x y:如果 (x,y)(x,y)(x,y) 之间 ...

  8. CodeForces - 504B Misha and Permutations Summation(线段树模拟康托展开与逆展开)

    题目链接:点击查看 题目大意:给出两个排列 ppp 和 qqq,现在要求输出 Perm((Ord(p)+Ord(q))modn!)Perm((Ord(p)+Ord(q)) \bmod n!) Perm ...

  9. codeforces CF438D The Child and Sequence 线段树

    $ \Rightarrow $ 戳我进CF原题 D. The Child and Sequence time limit per test: 4 seconds memory limit per te ...

最新文章

  1. 一个KVO 实现WKWebView加载进度条的例子 (注意最后移除观察者)
  2. 数据结构--折半查找法 详解
  3. 计算机不会输入函数怎么办,函数不正确_电脑上文件打不开,显示函数不正确怎么解决?...
  4. android phonegap 服务器ip配置,android + phoneGap 环境搭建
  5. mysql数据库恢复数据_【技术分享】使用Innodb存储引擎的mysql数据库恢复
  6. python 规则引擎 drools_Drools规则引擎入门demo
  7. SIP中第三方呼叫控制(3PCC)建立流程
  8. 电脑双系统--我想体验不一样的感觉
  9. error: ignoring return value of 编译错误处理
  10. Javascript 编程风格
  11. 计算机毕设 SpringBoot+Vue旧物置换系统 旧物交易管理系统 旧物二手交易系统Java Vue MySQL数据库 远程调试 代码讲解
  12. 管理好项目——带好技术团队的秘籍
  13. Ubuntu 18.04 中Chrome浏览器安装与使用
  14. docker push 过程 distribution源码 分析
  15. java基于ssm的道路求援车队管理系统
  16. (改进GM(1,1)模型)灰色残差马尔科夫预测模型的matlab实现
  17. 基于docker安装的rabbitmq如何安装rabbitmq_delayed_message_exchange-3.8.0.ez插件
  18. laravel物流地址查询
  19. 智能垃圾桶(八)——红外对管传感器(树莓派pico)
  20. repeater导出excel html,Repeater控件数据导出Excel(附演示动画)

热门文章

  1. 文件上传下载-修改文件上传大小
  2. Redis添加从节点
  3. Nacos源码处理心跳请求
  4. TopicPartition的存储
  5. 释放锁的逻辑-LockInternals.releaseLock
  6. 为什么需要动态SQL?
  7. base64补等号规则说明
  8. 概述类的加载器及类加载过程
  9. war包发布找不见路径 weblogic getResource 与getRealPath
  10. 选择结构_标准的switch语句