BZOJ 1786: [Ahoi2008]Pair 配对 题解

【原题】

1786: [Ahoi2008]Pair 配对

Time Limit: 10 Sec  Memory Limit: 64 MB

Submit: 399  Solved: 241

[Submit][Status]

Description

Input

Output

Sample Input

5 4

4 2 -1 -1 3

Sample Output

4

HINT

Source

Day1

【分析】一看到就感觉有思路,好像-1的格子有什么规律。于是开始YY。

简单的脑补:设A,B,C三个点,A,C是-1。显然,A、C的大小关系和A左边、B右边的无关。

若A<=C。如果B>C逆序对就是1 ,否则是0。

若A>C。如果B>C逆序对就是2 ,否则是1。

显然-1的格子是单调上升的最好。

然后的DP真的是太水了。先求出原来数的逆序对个数,然后只考虑-1的点造成的逆序对增量。

设f[i][j]是到第i个-1的点,改成数字j的最少逆序增量。显然f[i][j]=min(f[i-1][k]+cost)。而代价是1--i中比j大的数和i+1--n中比j小的数的和。可以先预处理出来。

还有,根据这个方程,除了状压外,还可以把时间效率从NK^2压成NK。

【造数据程序】无限WA!于是就找了个标程对拍。

#include<cstdio>
#include<cstdlib>
#include<ctime>
using namespace std;
int main()
{
  freopen("1786.in","w",stdout);
  srand((int)time(0));
  int n=1000,k=100;
  printf("%d %d\n",n,k);
  for (int i=1;i<=n;i++)
  {
    int num=rand()%10;
    if (!num) printf("-1 ");else printf("%d ",rand()%10+1);
  }
  return 0;
}

好不容易发现错误:最后更新Min的时候我用f数组。看上去因为f和g是一样的(memcpy),但其实如果-1只有1个,就不会有f了,而边界条件是g。于是应该改用g来更新Min。

【代码】

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 10005
#define K 105
using namespace std;
int place[N],big[N][K],small[N][K],f[K],g[K],a[N];
int n,L,i,j,m,now,last,ans,Min;
int main()
{
  freopen("1786.in","r",stdin);
  freopen("1786.out","w",stdout);
  scanf("%d%d",&n,&L);
  for (i=1;i<=n;i++) {scanf("%d",&a[i]);if (a[i]==-1) place[++m]=i;}
  for (i=2;i<=n;i++)
  {
    memcpy(big[i],big[i-1],sizeof(big[i-1]));
    if (a[i-1]>-1) for (j=1;j<a[i-1];j++) big[i][j]++;
  }
  for (i=n-1;i;i--)
  {
    memcpy(small[i],small[i+1],sizeof(small[i+1]));
    if (a[i+1]>-1) for (j=L;j>a[i+1];j--) small[i][j]++;
  }
  for (i=1;i<=n;i++) if (a[i]>-1) ans+=small[i][a[i]];
  for (i=1;i<=L;i++) g[i]=big[place[1]][i]+small[place[1]][i];
  for (i=2;i<=m;i++)
  {
    for (last=2;last<=L;last++)
      g[last]=min(g[last],g[last-1]);
    for (now=1;now<=L;now++)
      f[now]=g[now]+big[place[i]][now]+small[place[i]][now];
    memcpy(g,f,sizeof(f));
  }
  Min=g[1];for (i=2;i<=L;i++) Min=min(Min,g[i]);
  printf("%d",ans+Min);
  return 0;
}

BZOJ 1786: [Ahoi2008]Pair 配对 题解

时间: 2024-10-05 14:30:47

BZOJ 1786: [Ahoi2008]Pair 配对 题解的相关文章

【BZOJ1786】[Ahoi2008]Pair 配对 DP

[BZOJ1786][Ahoi2008]Pair 配对 Description Input Output Sample Input 5 4 4 2 -1 -1 3 Sample Output 4 题解:结论!!!为了使逆序对最少,我们在-1位置填入的数一定是单调不减的.(可以用反证法证明,很简单.) 所以DP,我们用f[i][j]表示枚举到第i个数,上一个在-1位置填入的数是j个最少逆序对个数.然后转移也很简单~ #include <cstdio> #include <cstring&g

BZOJ1786 [Ahoi2008]Pair 配对 动态规划 逆序对

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1786 题意概括 给出长度为n的数列,只会出现1~k这些正整数.现在有些数写成了-1,这些-1可以变成任何数. 求把这些-1变成1~k中的正整数之后,最少的逆序对个数为多少. 题解 我们可以判断,这些-1中写的数字一定是单调不降的. 为什么?我们把答案序列的所有-1位抽出来,如果答案序列中有一组是逆序的,那么交换他们,一定可以保证小的那个换到大的那个的位置的时候,它左右产生的逆序对数一定比大的原先

BZOJ1786: [Ahoi2008]Pair 配对/1831: [AHOI2008]逆序对

这两道题是一样的. 可以发现,-1变成的数是单调不降. 记录下原有的逆序对个数. 预处理出每个点取每个值所产生的逆序对个数,然后dp转移. #include<cstring> #include<iostream> #include<cstdio> #include<map> #include<cmath> #include<algorithm> #define rep(i,l,r) for (int i=l;i<=r;i++)

bzoj1786: [Ahoi2008]Pair 配对&amp;&amp;1831: [AHOI2008]逆序对

一个自以为很对的东西,我们往-1放的数肯定是不增的. 然后就预处理一下,假如i这个位置放j会多多少逆序对. DP一下,我的复杂度应该是O(n*m^2)的,然而你随便搞都能省掉一个m吧,我算了算好像可以过就不管了. 注意树状数组的时候getsum是a[i]-1,相同是不算逆序对的 #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorit

bzoj 2109 &amp; 2535 航空管制 题解

[] [分析]真的是一道贪心好题.开始我以为是一道大水题.建立拓扑图后(没环就是方便!),直接把最外层设定序号为1,第二层为2,bfs下去即可...结果发现:飞行序号不能相同...于是开始想. 先考虑第一个问题:打印一个合法序列.我开始是这么想的: 观察每个飞机的最晚飞行序号Ki,因为必定有解,所以我们可以让它的序号就是Ki.然后用它的时间去更新前面的时间(图可以反向建立).应该可以维护一个大根堆,每次挑出最大的一个进行处理. [简易代码] memset(T,0x7f,sizeof(T)); f

bzoj 2802: [Poi2012]Warehouse Store 题解

[原题] 2802: [Poi2012]Warehouse Store Time Limit: 10 Sec  Memory Limit: 64 MBSec  Special Judge Submit: 94  Solved: 54 Description 有一家专卖一种商品的店,考虑连续的n天. 第i天上午会进货Ai件商品,中午的时候会有顾客需要购买Bi件商品,可以选择满足顾客的要求,或是无视掉他. 如果要满足顾客的需求,就必须要有足够的库存.问最多能够满足多少个顾客的需求. Input 第一

bzoj 1858: [Scoi2010] 序列操作 题解

[原题] 1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 1031  Solved: 529 [Submit][Status] Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[a,b]区间内

矩阵乘法专题3——bzoj 1898 [Zjoi2004]Swamp 沼泽鳄鱼 题解

[原题] 1898: [Zjoi2004]Swamp 沼泽鳄鱼 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 425  Solved: 256 [Submit][Status] Description 潘塔纳尔沼泽地号称世界上最大的一块湿地,它地位于巴西中部马托格罗索州的南部地区.每当雨季来临,这里碧波荡漾.生机盎然,引来不少游客.为了让游玩更有情趣,人们在池塘的中央建设了几座石墩和石桥,每座石桥连接着两座石墩,且每两座石墩之间至多只有一座石桥.这

矩阵乘法专题4——bzoj 2326 [HNOI2011] 数学作业 题解

转载请注明:http://blog.csdn.net/jiangshibiao/article/details/24963747 [原题] 2326: [HNOI2011]数学作业 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 853  Solved: 473 [Submit][Status] Description [分析]我们按数字的位数来划分.对于K位数,我们就可以专门设计一个矩阵来计算. 然后就是注意细节了. [代码] #include