博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
codeforces 540E"Infinite Inversions"
阅读量:5050 次
发布时间:2019-06-12

本文共 3541 字,大约阅读时间需要 11 分钟。

 

题意:

  给你一个无限大的整数序列  p = {1, 2, 3, ...};

  有 n 次操作,每次操作交换第 ai 个数和第 aj 个数;

  求序列中逆序对的个数;

题解:

  考虑交换完后的序列,存在连续的区间 [ i , j ] 使得 p[ i ] = i , 那么分下一下这种区间的特点

  假设 i 之前有 x 个数大于 p[ i ],那么可知对于第 i 个数有 x 个逆序对,同理,因为 p[ i+1 ] = p[ i ]

  所以 i+1 之前也一定有且只有 x 个数大于 p[ i+1 ],那么第 i+1 个数也有 x 个逆序对,那么对于连续的区间[i,j]

  易的区间 [ i , j ] 与其之前的数可构成的逆序对的个数为 (j-i+1)*x 个,那么可将其映射为一个值 i ,并记录其有 (j-i+1) 个数;

  例如,假设 n 次操作为

  1  4

  1  8

  那么交换完后,前 8 个数的排列状况为:

  1  2  3  4  5  6  7  8

  8  2  3  1  5  6  7  4

  那么可得区间 [2,3] 和区间[5,6]的值未发生改变,当然区间[9,+∞]也为发生改变,但[9,+∞]并不影响答案,所以不用考虑。

  那么根据之前提到的,将为改变的大区间映射到某个值身上,并记录有多少数映射到这个值上了,如下所示:

  1  2  3  4  5

  8  2  1  5  4

  映射完后,区间[2,3]合并到了2上,区间[5,7]合并到了5上,接下来就是求映射完后的数组的逆序对总个数,这就变成了经典的

  树状数组求逆序对个数的题了。

  这就完事了么????当然不是~~~

  考虑 4 这个值,其之前的 5 只给 4 提供了一个逆序对,但实际上 6,7 也会提供,那么这就少算了两个逆序对数,这该怎么办呢?

  考虑某个区间 [i , j],一共有 j-i+1 个数,易得区间 [ i , j ] 只会影响其之后且值小于 i 的数,那么就再用一次树状数组,如果来到了某个

  映射的值,那么将 i 之后的数通过树状数组 +(j-i),对于某个在其之后且值小于 i 的数 x ,直接在答案上额外加上 Sum(x+1)即可。

AC代码:

1 #include
2 #include
3 #include
4 #include
5 #include
6 using namespace std; 7 #define lowbit(x) (x&-x) 8 #define ll long long 9 #define mem(a,b) memset(a,b,sizeof(a)) 10 const int maxn=1e6+50; 11 12 int n; 13 map
f;//记录交换后的序列状况 14 int diff[maxn]; 15 int sum[maxn]; 16 struct Date 17 { 18 int val; 19 int id;//初始编号 20 int tot;//如果某个区间映射到值val上,那么tot记录的就是区间的总个数 21 int newVal;//离散后的值 22 Date(int val=0,int id=0,int tot=0):val(val),id(id),tot(tot){} 23 }_date[maxn]; 24 25 struct BIT 26 { 27 int bit[maxn]; 28 void Init() 29 { 30 mem(bit,0); 31 } 32 void Add(int t,int x,int k) 33 { 34 while(t <= k) 35 { 36 bit[t] += x; 37 t += lowbit(t); 38 } 39 } 40 int Sum(int t) 41 { 42 int sum=0; 43 while(t > 0) 44 { 45 sum += bit[t]; 46 t -= lowbit(t); 47 } 48 return sum; 49 } 50 }_bit; 51 52 bool cmp1(Date a,Date b) 53 { 54 return a.val < b.val; 55 } 56 bool cmp2(Date a,Date b) 57 { 58 return a.id < b.id; 59 } 60 61 int Trans() 62 { 63 map
::iterator it; 64 int index=0; 65 int preIndex=f.begin()->first; 66 int nexIndex; 67 68 for(it=++f.begin();it != f.end();++it) 69 { 70 _date[++index]=Date(f[preIndex],index,1); 71 nexIndex=it->first; 72 73 //判断是否为未改变的区间 74 int tot=nexIndex-preIndex-1; 75 if(tot >= 1) 76 _date[++index]=Date(preIndex+1,index,tot); 77 78 preIndex=nexIndex; 79 } 80 _date[++index]=Date(f[preIndex],index,1); 81 82 sort(_date+1,_date+index+1,cmp1);//按其val由小到大排序,方便离散化 83 for(int i=1;i <= index;++i) 84 _date[i].newVal=i;//离散化 85 sort(_date+1,_date+index+1,cmp2);//按 id 从小到大复原 86 87 return index; 88 } 89 90 ll Solve() 91 { 92 //离散化 93 int index=Trans(); 94 _bit.Init();//树状数组初始化 95 ll ans=0; 96 97 //经典树状数组求逆序对个数 98 for(int i=1;i <= index;++i) 99 {100 int x=_date[i].newVal;101 _bit.Add(x,1,index);102 ans += 1ll*(i-_bit.Sum(x))*_date[i].tot;103 }104 105 //求解区间少加的逆序对个数106 _bit.Init();107 for(int i=1;i <= index;++i)108 {109 int x=_date[i].newVal;110 _bit.Add(x,_date[i].tot-1,index);//只有 tot > 1才会加入到树状数组中111 112 //求解 i 前值 > x 的未改变的区间少加的数的总个数113 if(_date[i].tot == 1)114 ans += _bit.Sum(index)-_bit.Sum(x);115 116 }117 118 return ans;119 }120 int main()121 {122 // freopen("C:/Users/hyacinthLJP/Desktop/stdin/contest","r",stdin);123 scanf("%d",&n);124 for(int i=1;i <= n;++i)125 {126 int a,b;127 scanf("%d%d",&a,&b);128 int x,y;129 x=(!f.count(a) ? a:f[a]);130 y=(!f.count(b) ? b:f[b]);131 132 f[a]=y;133 f[b]=x;134 }135 printf("%I64d\n",Solve());136 137 return 0;138 }
View Code

 

转载于:https://www.cnblogs.com/violet-acmer/p/10502978.html

你可能感兴趣的文章
对Feature的操作插入添加删除
查看>>
javascript String
查看>>
【转】码云source tree 提交超过100m 为什么大文件推不上去
查看>>
Oracle数据库的增、删、改、查
查看>>
MySql执行分析
查看>>
git使用中的问题
查看>>
yaml文件 .yml
查看>>
linux字符集修改
查看>>
phpcms 添加自定义表单 留言
查看>>
mysql 优化
查看>>
读书笔记 ~ Nmap渗透测试指南
查看>>
WCF 配置文件
查看>>
动态调用WCF服务
查看>>
oracle导出/导入 expdp/impdp
查看>>
类指针
查看>>
css修改滚动条样式
查看>>
2018.11.15 Nginx服务器的使用
查看>>
Kinect人机交互开发实践
查看>>
百度编辑器UEditor ASP.NET示例Demo 分类: ASP.NET...
查看>>
JAVA 技术类分享(二)
查看>>