原题链接

题意简介

给定一个长度为 n 的排列 {1,2,3,...,n} 。现有两种操作:

  1. 对某个区间 [l,r] 求和
  2. 将排列往后推 x 次 (按字典序)

其中 \(n,q \leq 2\times10^5 , x\leq 10^5\) 。

思路分析

乍一看毫无思路。

因为排列变换是毫无疑问的暴力,变换后怎么维护区间和是一个非常玄妙的问题。好像没有什么特殊的维护技巧。

仔细观察数据范围:\(x\leq 10^5 , q\leq 2\times 10^5\)

这意味着 \(\sum x_i \leq 2\times 10^{10}\)

而经过简单的打表观察我们不难发现 \(13! <2\times 10^{10}<14!\)

换句话说,所有的操作过后,会改变的实际上只有最后的 14 个数

于是问题就简单了,每次更新暴力更改后 14 个数,维护一下前缀和就行了。

那么让我们来考虑如何生成一个排名为 x 的排列。

其实类比如何计算某个排列的排名,反过来就行了。

我的做法是利用树状数组维护比某个数小的数里有几个被选过,然后用二分查找确定当前位置的数字。

详见代码。

代码库

1. 排列生成模板

  1. #include <cstdio>
  2. typedef long long ll;
  3. #define REG register
  4. #define rep(i,a,b) for(REG int i=a;i<=b;i++)
  5. #define Rep(i,a,b) for(REG int i=a;i>=b;i--)
  6. int n,tr[25],A[25]; ll d,fact[25];
  7. inline int lowbit(int x){
  8. return x&-x;
  9. }
  10. inline int sum(int x){
  11. REG int ans=0;
  12. while(x) ans+=tr[x],x-=lowbit(x);
  13. return ans;
  14. }
  15. inline void add(int x){
  16. while(x<=n) tr[x]++,x+=lowbit(x);
  17. }
  18. inline bool check(int x,ll r,int i){
  19. // x-sum(x) 表示这个数往下的没用过的数的个数
  20. // x 在 i 位置上的所有情况之和仍不足以达到 d
  21. return r+(x-sum(x))*fact[n-i]<d;
  22. }
  23. int main(){
  24. fact[0]=1; rep(i,1,20) fact[i]=fact[i-1]*i;
  25. while(scanf("%d%lld",&n,&d)==2){
  26. //tr 用于存储用过的数字
  27. rep(i,1,n) tr[i]=0;
  28. REG ll rest=0;
  29. rep(i,1,n){
  30. REG int l=1,r=n,mid,ans=0;
  31. while(l<=r){
  32. //找到最大的恰不能使序号比 d 大的数字
  33. mid=(l+r)>>1;
  34. if(check(mid,rest,i)) ans=mid,l=mid+1;
  35. else r=mid-1;
  36. }
  37. // ans+1 必然没用过,假如用过了,必然会被记为 ans
  38. A[i]=ans+1; rest+=(ans-sum(ans))*fact[n-i]; add(A[i]);
  39. }
  40. rep(i,1,n) printf("%d ",A[i]); putchar('\n');
  41. }
  42. return 0;
  43. }

2. 本题题解

  1. #include <cstdio>
  2. #include <cstring>
  3. typedef long long ll;
  4. #define REG register
  5. #define rep(i,a,b) for(REG int i=a;i<=b;i++)
  6. #define Rep(i,a,b) for(REG int i=a;i<=b;i++)
  7. inline char getc(){
  8. static char buf[1<<14],*p1=buf,*p2=buf;
  9. return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++;
  10. }
  11. inline ll scan(){
  12. REG ll x=0; REG char ch=0;
  13. while(ch<48) ch=getc();
  14. while(ch>=48) x=x*10+ch-48,ch=getc();
  15. return x;
  16. }
  17. inline int max(const int&a,const int&b){
  18. return a>b?a:b;
  19. }
  20. inline int min(const int&a,const int&b){
  21. return a<b?a:b;
  22. }
  23. const int N=2e5+5;
  24. //注意初始排列的排名为 1
  25. int n,q,tr[17]; ll sum[N],D=1,fact[17];
  26. inline int lowbit(int x){
  27. return x&-x;
  28. }
  29. inline int query(int x){
  30. REG int ans=0;
  31. while(x) ans+=tr[x],x-=lowbit(x);
  32. return ans;
  33. }
  34. inline void add(int x){
  35. //注意这里不是 x<=n
  36. while(x<=14) tr[x]++,x+=lowbit(x);
  37. }
  38. inline bool check(int x,int i,ll r){
  39. return r+(x-query(x))*fact[n-i]<D;
  40. }
  41. inline void test(){
  42. printf("Now:\n");
  43. rep(i,1,n) printf("%d ",sum[i]-sum[i-1]);
  44. putchar('\n');
  45. }
  46. int main(){
  47. n=scan(),q=scan();
  48. rep(i,1,n) sum[i]=sum[i-1]+i;
  49. fact[0]=1;
  50. rep(i,1,14) fact[i]=fact[i-1]*i;
  51. while(q--){
  52. REG int opt=scan();
  53. if(opt==1){
  54. REG int l=scan(),r=scan();
  55. printf("%lld\n",sum[r]-sum[l-1]);
  56. }else{
  57. D+=scan(); REG ll rest=0;
  58. memset(tr,0,sizeof(tr));
  59. //只有最后的 14 个数会发生变化
  60. for(REG int i=max(1,n-13);i<=n;i++){
  61. REG int l=1,r=min(14,n),mid,ans=0;
  62. while(l<=r){
  63. //找到最大的恰不能使序号比 d 大的数字
  64. mid=(l+r)>>1;
  65. if(check(mid,i,rest)) l=mid+1,ans=mid;
  66. else r=mid-1;
  67. }
  68. sum[i]=sum[i-1]+ans+max(1,n-13);
  69. rest+=(ans-query(ans))*fact[n-i];
  70. add(ans+1);
  71. }
  72. //test();
  73. }
  74. }
  75. return 0;
  76. }

END

【CF1443E】Long Permutation 题解(排列生成模板)的更多相关文章

  1. 【原创】开源.NET排列组合组件KwCombinatorics使用(二)——排列生成

           本博客所有文章分类的总目录:本博客博文总目录-实时更新 本博客其他.NET开源项目文章目录:[目录]本博客其他.NET开源项目文章目录 KwCombinatorics组件文章目录: 1. ...

  2. [BILL WEI]stimulsoft reports DEMO自动生成模板

    stimulsoft reports是一款强大的报表开发工具,能够开发各式各样的报表. 对于初学者而言,任何报表开发,刚开始都是去模仿,熟练掌握之后,自己才能独立开发,而在报表开发实际过程中, 我们所 ...

  3. C# T4 模板 数据库实体类生成模板(带注释,娱乐用)

     说明:..,有些工具生成实体类没注释,不能和SqlServer的MS_Description属性一起使用,然后照着网上的资源,随便写了个生成模板,自娱自乐向,其实卵用都没有参考教程    1.htt ...

  4. HDU 1027 Ignatius and the Princess II 排列生成

    解题报告:1-n这n个数,有n!中不同的排列,将这n!个数列按照字典序排序,输出第m个数列. 第一次TLE了,没注意到题目上的n和m的范围,n的范围是小于1000的,然后m的范围是小于10000的,很 ...

  5. springboot mail整合freemark实现动态生成模板

    目标:1:springboot 整合 mail2: mail 使用freemark 实现模板动态生成(就是通过字符串生成模板,不需要在工程中写入固定模板)3: springboot 整合aop 实现日 ...

  6. uniapp - 更改项目生成模板、页面

    每次生成项目目录都需要删除一些再添加太麻烦了,就想着能不能修改一下模板 - 当然自定义模板也能实现 好了,被我找到了. 修改以后源文件名称和格式覆盖回去即可,重新启动hbuilderx 这里可以修改e ...

  7. mybatis配eclise模板,mybatis快速生成模板

    eclipse中mybatis得mapper文件不提示(mybatis-3-mapper.dtd,mybatis-3-config.dtd) 1.下载该文件到你的硬盘文件夹下 2.windows -- ...

  8. Android Studio 配置快速生成模板代码

    前言 Android studio 有提供快速生成模板代码的功能,其实这个功能也可以自定义配置.此篇博客将讲解如何使用此功能 进入Settings 选择 Editor > Live Templa ...

  9. ACM-挑战题之排列生成

    题目描述:挑战题之排列生成 一自然数N,设N为3,则关于N的字典序排列为123,132,213,231,312,321.对于一个自然数N(1<= N <= 9 ) , 你要做的便是生成它的 ...

随机推荐

  1. 我竟在arm汇编除法算法里找到了leetcode某道题的解法

    今天讲讲arm汇编中除法的底层实现.汇编代码本身比较长了,如需参考请直接拉到文末. 下面我直接把arm的除法算法的汇编代码转译成C语言的代码贴出来,并进行解析. 因为篇幅有限,所以在此只解析无符号整型 ...

  2. .NET Standard 简介

    系列目录     [已更新最新开发文章,点击查看详细] .NET Standard 是一套正式的 .NET API 规范,有望在所有 .NET 实现中推出. 推出 .NET Standard 的背后动 ...

  3. java swing 按钮事件触发两次或者多次

    按钮事件触发多次? 如果是JButton,八成是由于粗心,多次添加了监听事件 保持只添加一个监听事件就解决了~

  4. linux网卡驱动程序架构

    以cs89x0网卡驱动为例:

  5. 多测师讲解selenium_输入性弹框定位_高级讲师肖sir

    #输入性弹框from selenium import webdriverfrom time import sleepdrvier=webdriver.Chrome()url='file:///F:\d ...

  6. day03 Pyhton学习

    昨日回顾 1.while循环 语法 while 条件: 语句 else: 语句 执行语句:判断语句是否为真.如果真,执行循环,然后再次判断条件,如果不满足执行else语句. break 结束循环 co ...

  7. 如何使用 Gin 和 Gorm 搭建一个简单的 API 服务 (二)

    创建 API   我们之前已经跑过 Gin 框架的代码,现在是时候加些功能进去了. 读取全部信息   我们先从"增删改查"中的"查"入手,查询我们之前添加的信息.我接下来要删除几行代码,并把 Gin ...

  8. ImageLoader简介和使用方法

    1.功能概要 Android-Universal-Image-Loader是一个开源的UI组件程序,该项目的目的是提供一个可重复使用的仪器为异步图像加载,缓存和显示. (1).使用多线程加载图片(2) ...

  9. node初学

    安装node.js 往往需要解析环境,但是现在直接安装时就已经配置好了, cmd打开 输入cd/ 在输入node -v   显示版本号 Node与php比较:https://www.techug.co ...

  10. java应用启动报错Unable to access jarfile xxxxx.jar

    当使用命令:javar -jar xxxx.jar 启动应用时,报错Unable to access jarfile xxxxx.jar,这种主要是 jar 的名称或者路径有问题: