求最少的步数使得序列升序,无重复数据,每步只能交换两个相邻的数。树状数组求逆序对。
1 #include<iostream> 2 #include<sstream> 3 #include<fstream> 4 #include<algorithm> 5 #include<cstring> 6 #include<iomanip> 7 #include<cstdlib> 8 #include<cctype> 9 #include<vector> 10 #include<string> 11 #include<cmath> 12 #include<ctime> 13 #include<stack> 14 #include<queue> 15 #include<map> 16 #include<set> 17 #define mem(a,b) memset(a,b,sizeof(a)) 18 #define random(a,b) (rand()%(b-a+1)+a) 19 #define ll long long 20 #define ull unsigned long long 21 #define e 2.71828182 22 #define Pi acos(-1.0) 23 #define ls(rt) (rt<<1) 24 #define rs(rt) (rt<<1|1) 25 #define lowbit(x) (x&(-x)) 26 using namespace std; 27 const int MAXN=5000+5; 28 int a[MAXN],Tree[MAXN],n; 29 inline void update(int x,int k) 30 { 31 for(int i=x;i<=n;i+=lowbit(i)) 32 Tree[i]+=k; 33 } 34 int getsum(int x) 35 { 36 int ans=0; 37 for(int i=x;i>=1;i-=lowbit(i)) 38 ans+=Tree[i]; 39 return ans; 40 } 41 int read() 42 { 43 int s=1,x=0; 44 char ch=getchar(); 45 while(!isdigit(ch)) {if(ch=='-') s=-1;ch=getchar();} 46 while(isdigit(ch)) {x=10*x+ch-'0';ch=getchar();} 47 return x*s; 48 } 49 int main() 50 { 51 while(~scanf("%d",&n)) 52 { 53 int ans=0; 54 mem(Tree,0); 55 for(int i=1;i<=n;++i) 56 { 57 a[i]=read(); 58 update(a[i],1); 59 ans+=i-getsum(a[i]); 60 } 61 cout<<ans<<endl; 62 } 63 }
最多移动n步,每步只能交换两个相邻的数,求过程中最少的逆序数。求出逆序数后和k进行比较,输出差值或0。
把一个序列交换成递增序列所需的最少步数即逆序数。
这题还用到了离散化。
1 #include<iostream> 2 #include<sstream> 3 #include<fstream> 4 #include<algorithm> 5 #include<cstring> 6 #include<iomanip> 7 #include<cstdlib> 8 #include<cctype> 9 #include<vector> 10 #include<string> 11 #include<cmath> 12 #include<ctime> 13 #include<stack> 14 #include<queue> 15 #include<map> 16 #include<set> 17 #define mem(a,b) memset(a,b,sizeof(a)) 18 #define random(a,b) (rand()%(b-a+1)+a) 19 #define ll long long 20 #define ull unsigned long long 21 #define e 2.71828182 22 #define Pi acos(-1.0) 23 #define ls(rt) (rt<<1) 24 #define rs(rt) (rt<<1|1) 25 #define lowbit(x) (x&(-x)) 26 using namespace std; 27 const int MAXN=1e5+5; 28 int Tree[MAXN],Hash[MAXN],n,k; 29 struct node 30 { 31 int val,pos; 32 bool operator < (node& a) 33 { 34 if(val!=a.val) return val<a.val; 35 return pos<a.pos; 36 } 37 }b[MAXN]; 38 void update(int x,int k) 39 { 40 for(int i=x;i<=n;i+=lowbit(i)) 41 Tree[i]+=k; 42 } 43 int getsum(int x) 44 { 45 int ans=0; 46 for(int i=x;i>=1;i-=lowbit(i)) 47 ans+=Tree[i]; 48 return ans; 49 } 50 int read() 51 { 52 int s=1,x=0; 53 char ch=getchar(); 54 while(!isdigit(ch)) {if(ch=='-') s=-1;ch=getchar();} 55 while(isdigit(ch)) {x=10*x+ch-'0';ch=getchar();} 56 return x*s; 57 } 58 int main() 59 { 60 while(~scanf("%d%d",&n,&k)) 61 { 62 for(int i=1;i<=n;++i) 63 b[i].val=read(),b[i].pos=i; 64 mem(Tree,0); 65 sort(b+1,b+n+1); 66 /*for(int i=1;i<=n;++i) 67 Hash[b[i].pos]=i;*/ //无重复数据 68 //有重复数据 69 int cnt=1; 70 Hash[b[1].pos]=1; 71 for(int i=2;i<=n;++i) 72 { 73 if(b[i].val!=b[i-1].val) Hash[b[i].pos]=++cnt; 74 else Hash[b[i].pos]=cnt; 75 } 76 ll num=0; 77 //离散后的数据 78 //for(int i=1;i<=n;++i) cout<<Hash[i]<<' ';cout<<endl; 79 for(int i=1;i<=n;++i) 80 { 81 update(Hash[i],1); 82 num+=(i-getsum(Hash[i])); 83 } 84 if(num<k) cout<<0<<endl; 85 else cout<<num-k<<endl; 86 } 87 return 0; 88 }
3、HDU1394 Minimum Inversion Number
相当于环状序列找到点切成链状的最少逆序数。
1 #include<iostream> 2 #include<sstream> 3 #include<fstream> 4 #include<algorithm> 5 #include<cstring> 6 #include<iomanip> 7 #include<cstdlib> 8 #include<cctype> 9 #include<vector> 10 #include<string> 11 #include<cmath> 12 #include<ctime> 13 #include<stack> 14 #include<queue> 15 #include<map> 16 #include<set> 17 #define mem(a,b) memset(a,b,sizeof(a)) 18 #define random(a,b) (rand()%(b-a+1)+a) 19 #define ll long long 20 #define ull unsigned long long 21 #define e 2.71828182 22 #define Pi acos(-1.0) 23 #define ls(rt) (rt<<1) 24 #define rs(rt) (rt<<1|1) 25 #define lowbit(x) (x&(-x)) 26 using namespace std; 27 const int MAXN=5e3+5; 28 int Tree[MAXN],a[MAXN],n; 29 void update(int x,int v) 30 { 31 for(int i=x;i<=n;i+=lowbit(i)) 32 Tree[i]+=v; 33 } 34 int getsum(int x) 35 { 36 int ans=0; 37 for(int i=x;i>=1;i-=lowbit(i)) 38 ans+=Tree[i]; 39 return ans; 40 } 41 int read() 42 { 43 int s=1,x=0; 44 char ch=getchar(); 45 while(!isdigit(ch)) {if(ch=='-') s=-1;ch=getchar();} 46 while(isdigit(ch)) {x=10*x+ch-'0';ch=getchar();} 47 return x*s; 48 } 49 int main() 50 { 51 while(~scanf("%d",&n)) 52 { 53 int ans=0; 54 mem(Tree,0); 55 for(int i=1;i<=n;++i) 56 { 57 a[i]=read()+1; 58 update(a[i],1); 59 ans+=i-getsum(a[i]); 60 } 61 //比a[1]小的数有a[1]-1个,将a[1]移至末尾逆序数会减少a[1]-1 ; 62 //但同时,比a[1]大的数有n-a[1]个,逆序数会加n-a[1] 63 int tmp=ans; 64 //cout<<ans<<endl; 65 for(int i=1;i<=n;++i) 66 { 67 tmp=tmp-(a[i]-1)+(n-a[i]); 68 ans=min(ans,tmp); 69 } 70 cout<<ans<<endl; 71 } 72 return 0; 73 }
4、VJ Aizu1395 What Goes Up Must Come Down
对每个数来说,只有两种情况,要么参与非递减部分要么参与非递增部分,对于前者它要移的次数就是在它之前与他构成的逆序对数,对于后者它要移的次数就是在它之后与他构成的逆序对数,那我们取较小的加入到答案就做完了。
求一个数的后面比它小的数可以用上述三题的方法将序列倒过来求。
可以不用离散化的,练一下。
1 #include<iostream> 2 #include<sstream> 3 #include<fstream> 4 #include<algorithm> 5 #include<cstring> 6 #include<iomanip> 7 #include<cstdlib> 8 #include<cctype> 9 #include<vector> 10 #include<string> 11 #include<cmath> 12 #include<ctime> 13 #include<stack> 14 #include<queue> 15 #include<map> 16 #include<set> 17 #define mem(a,b) memset(a,b,sizeof(a)) 18 #define random(a,b) (rand()%(b-a+1)+a) 19 #define ll long long 20 #define ull unsigned long long 21 #define e 2.71828182 22 #define Pi acos(-1.0) 23 #define ls(rt) (rt<<1) 24 #define rs(rt) (rt<<1|1) 25 #define lowbit(x) (x&(-x)) 26 using namespace std; 27 const int MAXN=1e5+5; 28 int Tree[MAXN],Hash[MAXN],n; 29 int pre[MAXN],suf[MAXN]; 30 struct node 31 { 32 int val,pos; 33 bool operator < (node& a) 34 { 35 if(val!=a.val) return val<a.val; 36 return pos<a.pos; 37 } 38 }a[MAXN]; 39 void update(int x,int v) 40 { 41 for(int i=x;i<=n;i+=lowbit(i)) 42 Tree[i]+=v; 43 } 44 int getsum(int x) 45 { 46 int ans=0; 47 for(int i=x;i>=1;i-=lowbit(i)) 48 ans+=Tree[i]; 49 return ans; 50 } 51 int read() 52 { 53 int s=1,x=0; 54 char ch=getchar(); 55 while(!isdigit(ch)) {if(ch=='-') s=-1;ch=getchar();} 56 while(isdigit(ch)) {x=10*x+ch-'0';ch=getchar();} 57 return x*s; 58 } 59 int main() 60 { 61 n=read(); 62 for(int i=1;i<=n;++i) 63 a[i].val=read(),a[i].pos=i; 64 sort(a+1,a+n+1); 65 int cnt=1; 66 Hash[a[1].pos]=1; 67 for(int i=2;i<=n;++i) 68 if(a[i].val==a[i-1].val) Hash[a[i].pos]=cnt; 69 else Hash[a[i].pos]=++cnt; 70 for(int i=1;i<=n;++i) 71 { 72 update(Hash[i],1); 73 pre[i]=i-getsum(Hash[i]); 74 } 75 mem(Tree,0); 76 for(int i=n;i>=1;i--) 77 { 78 update(Hash[i],1); 79 suf[i]=(n-i+1)-getsum(Hash[i]); 80 } 81 ll ans=0; 82 /*for(int i=1;i<=n;++i) 83 { 84 cout<<pre[i]<<' '<<suf[i]<<endl; 85 }*/ 86 for(int i=1;i<=n;++i) 87 ans+=min(pre[i],suf[i]); 88 cout<<ans<<endl; 89 }