codeforces 414 c
来源:互联网 发布:区域生长 分割算法 编辑:程序博客网 时间:2024/05/17 12:51
题意:
给出一个长度为2^n的数列,然后要将其分成每段长度为2^q的小段,将每段进行反转,问新数列的逆序数。每次操作都是建立在上一次的操作之上。
思想:
开始的时候进行了一次模拟,分段,反转,求逆序数,跪在了第10组上。数据是n=20
//// main.cpp// jixun//// Created by zhou yi on 14-4-8.// Copyright (c) 2014年 edward. All rights reserved.//#include "stdio.h"#include "string.h"#include <iostream>#include <algorithm>#include <queue>#include <stack>#include <math.h>using namespace std;const int MAX = 10000000;int num[MAX];int aa[MAX];int tt[MAX];int ans;void get_array(int i,int x){ reverse(num+i, num+i+x);}void msort(int s,int t){ if(s>=t) return ; int mid= (s+t)/2; msort(s, mid); msort(mid+1, t); int i = s,j = mid+1,p = 0; while(i <= mid && j <= t) { if (aa[i] <= aa[j]) { tt[p++]=aa[i++]; } else { tt[p++] = aa[j++]; ans += mid+1-i; } } while (i <= mid) { tt[p++] = aa[i++]; } while (j <= t) { tt[p++] = aa[j++]; } for (int i = s,j = 0; i <= t; ++ i) { aa[i] = tt[j++]; }}int main(){ int n; scanf("%d",&n); n = 1<<n; for (int i = 0; i < n; ++ i) { scanf("%d",&num[i]); } int m; scanf("%d",&m); while (m--) { ans = 0; int t = 0; int q; scanf("%d",&q); q = 1 << q; while (t < n) { get_array(t,q); t+=q; } for (int i = 0; i < n; ++ i) { aa[i] = num[i]; } msort(0, n-1); printf("%d\n",ans); } return 0;}
然后参考了一下网上的博客。发现讲的实在是简短……
首先,反转之后的逆序数,在反转之前是可以得到的(即把数列反过来看)。
然后,将数分解成2^q段,然后反转,其实相当于归并排序中的1-q层进行了反转(想想为什么,提示:归并排序是每次将数列分成两半),而反转后的逆序数在之前已经求到了,于是不需要进行归并排序,而只需要把所有归并排序的逆序数加起来就行了。
并且,归并排序还可以做简易的就可以了(每次都完完整整排序反而更加麻烦)。
#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;typedef long long int LL;int n,m,a[1<<21];LL dp[21][2];void merge_sort(int l,int r,int dep){ if(l>=r) return ; int m=(l+r)/2; merge_sort(l,m,dep-1); merge_sort(m+1,r,dep-1); for(int i=l;i<=m;i++) { dp[dep][0]+=lower_bound(a+m+1,a+r+1,a[i])-(a+m+1); dp[dep][1]+=r-m-(upper_bound(a+m+1,a+r+1,a[i])-(a+m+1)); } sort(a+l,a+r+1);}int main(){ scanf("%d",&n); for(int i=1,sz=(1<<n);i<=sz;i++) scanf("%d",a+i); merge_sort(1,(1<<n),n); scanf("%d",&m); while(m--) { int q; LL ans=0; scanf("%d",&q); for(int i=1;i<=q;i++) swap(dp[i][0],dp[i][1]); for(int i=1;i<=n;i++) ans+=dp[i][0]; printf("%I64d\n",ans); } return 0;}
注:此代码采自网络,N多相同代码,不知道原出处,引用希作者见谅
使用dp[i][0]表示第i层的原逆序数,dp[i][1]表示第i层的反向逆序数。反转只是将其值进行交换。
0 0
- codeforces 414 c
- codeforces 414C 归并排序
- CodeForces 414 C. Mashmokh and Reverse Operation
- codeforces 414C 分治思想运用
- 归并排序 逆序数 Codeforces 414 C
- 【Codeforces Round #414 C Naming Company】
- Codeforces Round #414 C. Naming Company 贪心
- Codeforces-340-C(c++)
- Codeforces-507-C(c++)
- CodeForces 731C C
- CodeForces-612C C
- CODEFORCES 265C CODEFORCES, 265C
- codeforces #78 div2 C
- Codeforces 117C Cycle
- CodeForces 209C
- CodeForces 156C Cipher
- codeforces 148 div2 C
- codeforces 242C
- Microsoft .NET Framework 4 Client Profile 导致DLL引用失败
- Spring环境下实现定时执行任务
- 简明python教程学习笔记(七)-模块
- JS正则表达式 验证 输入的是正负小数(保留3位小数)或者只能输入正负整数
- 程序员学习能力提升三要素
- codeforces 414 c
- Linux系统查看进程信息相关命令:
- Python开发WebService--使用soaplib库
- Json XSS (只是一个小窥)
- Alljoyn服务器框架2总线及会话
- 于繁华中寻觅一份淡然(街灯上的藤蔓)
- POI格式化Cell样式
- String reorder
- 设计模式-外观模式