[CmdOI2019]任务分配问题
题目描述
在某台有kk个CPU的计算机中,有nn个计算任务等待执行。
a_iai为第ii个任务的优先级,方便起见,aa为一个排列。
现在,要将这些任务分配给CPU去解决。
由于内存等原因,一个CPU只能负责连续一段的任务,并且要按(从左到右的)顺序执行。
在某个CPU内,无序度定义为 : 前者先执行,而后者优先级高的任务对的个数。
请最小化每个CPU的无序度之和。
输入格式
第一行两个整数n,kn,k,分别表示任务个数和CPU个数。
第二行nn个整数,表示a_{1...n}a1...n
输出格式
输出一个整数,表示最小的无序度之和。
输入输出样例
输入 #1复制
5 1
1 5 4 2 3
输出 #1复制
5
输入 #2复制
5 2
1 5 4 2 3
输出 #2复制
1
输入 #3复制
8 3
1 3 5 2 7 4 8 6
输出 #3复制
4
说明/提示
测试点编号 n k
1~2 25000 1
3 25000 2
4~5 1000 10
6~10 25000 25
(保证k\leq nk≤n , #6~10时限2S)
样例解释:
样例1
此时只能把所有任务交给单独的一个CPU。
第一个任务和其他所有任务都形成无序任务对。
此外最后两个任务也形成无序任务对,共5个。
样例2
第一个CPU单独处理任务1,无序度为0;
第二个CPU处理\{5,4,2,3\}{5,4,2,3}无序度为1;
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int c[50005],tr,tl,f[30][25005],a[25005],s,n,k; 7 void del(int x) 8 { 9 while (x<=n) 10 { 11 c[x]-=1; 12 x+=(x&(-x)); 13 } 14 } 15 void add(int x) 16 { 17 while (x<=n) 18 { 19 c[x]+=1; 20 x+=(x&(-x)); 21 } 22 } 23 int query(int x) 24 { 25 int sum=0; 26 while (x) 27 { 28 sum+=c[x]; 29 x-=(x&(-x)); 30 } 31 return sum; 32 } 33 int get(int l,int r) 34 { 35 while (tl<l) 36 { 37 del(a[tl]); 38 s-=tr-tl-query(a[tl]); 39 tl++; 40 } 41 while (tl>l) 42 { 43 tl--; 44 s+=tr-tl-query(a[tl]); 45 add(a[tl]); 46 } 47 while (tr<r) 48 { 49 tr++; 50 s+=query(a[tr]); 51 add(a[tr]); 52 } 53 while (tr>r) 54 { 55 del(a[tr]); 56 s-=query(a[tr]); 57 tr--; 58 } 59 return s; 60 } 61 void solve(int x,int l,int r,int L,int R) 62 {int i,Mid; 63 if (l>r) return; 64 int mid=(l+r)/2; 65 Mid=mid; 66 for (i=L;i<=min(mid-1,R);i++) 67 { 68 int t=f[x-1][i]+get(i+1,mid); 69 if (f[x][mid]>=t) 70 { 71 f[x][mid]=t; 72 Mid=i; 73 } 74 } 75 solve(x,l,mid-1,L,Mid); 76 solve(x,mid+1,r,Mid,R); 77 } 78 int main() 79 {int i,j; 80 scanf("%d%d",&n,&k); 81 for (i=1;i<=n;i++) 82 scanf("%d",&a[i]); 83 memset(f,127/2,sizeof(f)); 84 tl=1;tr=0; 85 for (i=1;i<=n;i++) 86 { 87 f[1][i]=get(1,i); 88 } 89 for (i=2;i<=k;i++) 90 { 91 solve(i,i,n,i-1,n); 92 } 93 printf("%d",f[k][n]); 94 }