• [AtCoder-ARC073F]Many Moves


    题目大意:
      有一排n个格子和2枚硬币。
      现在有q次任务,每一次要你把其中一枚硬币移到x的位置上,移动1格的代价是1。
      两枚硬币不能同时移动,任务必须按次序完成。
      现在告诉你两枚硬币初始状态所在的位置a和b,问完成所有任务的最小代价。

    思路:
      很容易想到一个O(qn)的DP。
      由于完成任务的次序确定,每个任务的位置也确定,我们可以用f[i][j]表示完成第i个任务后,一个硬币在x[i],一个硬币在j的最小代价。
      转移方程为f[i][j]=min{f[i-1][j]+|x[i]-x[i-1]|},f[i][a[i-1]]=min{f[i-1][j]+|x[i]-j|}。
      然而这样还是会TLE,在AtCoder上只过了14/34的测试数据。
      不难发现,在状态转移方程中,如果我们能去掉绝对值,里面的东西就能用线段树维护。
      而绝对值的取值只与硬币的左右位置关系有关。
      因此我们可以建2棵线段树,一棵表示被转移的状态在目标状态左边,一棵表示在右边。
      左线段树中每个叶子结点x[i-1]维护f[i-1][j]-x[i-1]的值,右线段树每个叶子结点x[i-1]维护f[i-1][j]+x[i-1]的值。
      看了一下榜,发现排在前面的基本上都是用树状数组做的。
      然而用树状数组维护区间最值难道不是O(log^2 n)的吗?
      事实上我们可以发现线段树上维护的东西只会越来越小,这样我们可以直接在树状数组上修改,不用考虑原来的最小值没了怎么办。
      然后我又在树状数组里面加了一个剪枝。
      这样随随便便就能拿Rank1。

      1 #include<cstdio>
      2 #include<cctype>
      3 #include<cstdlib>
      4 #include<algorithm>
      5 typedef signed long long int int64;
      6 inline unsigned getint() {
      7     register char ch;
      8     while(!isdigit(ch=getchar()));
      9     register unsigned x=ch^'0';
     10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
     11     return x;
     12 }
     13 inline int64 min(const int64 &a,const int64 &b) {
     14     return a<b?a:b;
     15 }
     16 const int64 inf=0x7ffffffffffffff;
     17 const int N=200001;
     18 int n;
     19 class FenwickTree {
     20     private:
     21         int64 val[N];
     22         int lowbit(const int &x) const {
     23             return x&-x;
     24         }
     25     public:
     26         FenwickTree() {
     27             std::fill(&val[0],&val[N],inf);
     28         }
     29         void modify(int p,const int64 &x) {
     30             while(p<=n) {
     31                 if(x<val[p]) {
     32                     val[p]=x;
     33                 } else {
     34                     return;
     35                 }
     36                 p+=lowbit(p);
     37             }
     38         }
     39         int64 query(int p) const {
     40             int64 ret=inf;
     41             while(p) {
     42                 ret=min(ret,val[p]);
     43                 p-=lowbit(p);
     44             }
     45             return ret;
     46         }
     47 };
     48 FenwickTree ta;
     49 class RevFenwickTree {
     50     private:
     51         int64 val[N];
     52         int lowbit(const int &x) const {
     53             return x&-x;
     54         }
     55     public:
     56         RevFenwickTree() {
     57             std::fill(&val[0],&val[N],inf);
     58         }
     59         void modify(int p,const int64 &x) {
     60             while(p) {
     61                 if(x<val[p]) {
     62                     val[p]=x;
     63                 } else {
     64                     return;
     65                 }
     66                 p-=lowbit(p);
     67             }
     68         }
     69         int64 query(int p) const {
     70             int64 ret=inf;
     71             while(p<=n) {
     72                 ret=min(ret,val[p]);
     73                 p+=lowbit(p);
     74             }
     75             return ret;
     76         }
     77 };
     78 RevFenwickTree tb;
     79 int64 f[N];
     80 inline void modify(const int &p,const int64 x) {
     81     if(x<f[p]) {
     82         f[p]=x;
     83         ta.modify(p,x-p);
     84         tb.modify(p,x+p);
     85     }
     86 }
     87 int main() {
     88     n=getint();
     89     int q=getint(),a=getint(),b=getint();
     90     std::fill(&f[0],&f[N],inf);
     91     modify(a,0);
     92     int64 sum=0;
     93     while(q--) {
     94         a=b;
     95         b=getint();
     96         sum+=abs(a-b);
     97         int64 t1=ta.query(b)+b,t2=tb.query(b)-b;
     98         modify(a,min(t1,t2)-abs(a-b));
     99     }
    100     int64 tmp=inf;
    101     for(register int i=1;i<=n;i++) {
    102         tmp=min(tmp,f[i]);
    103     }
    104     printf("%lld
    ",tmp+sum);
    105     return 0;
    106 }

    原来的O(n^2)DP程序:

     1 #include<cstdio>
     2 #include<cctype>
     3 #include<cstring>
     4 #include<cstdlib>
     5 inline unsigned getint() {
     6     register char ch;
     7     while(!isdigit(ch=getchar()));
     8     register unsigned x=ch^'0';
     9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    10     return x;
    11 }
    12 inline unsigned min(const unsigned &a,const unsigned &b) {
    13     return a<b?a:b;
    14 }
    15 const unsigned N=200000;
    16 unsigned long long f[2][N];
    17 unsigned a[2];
    18 int main() {
    19     unsigned n=getint(),q=getint();
    20     memset(f[0],0xff,n<<3);
    21     a[0]=getint()-1,f[0][getint()-1]=0;
    22     for(register unsigned i=1;i<=q;i++) {
    23         a[i&1]=getint()-1;
    24         memset(f[i&1],0xff,n<<3);
    25         for(register unsigned j=0;j<n;j++) {
    26             if(!~f[~i&1][j]) continue;
    27             f[i&1][j]=min(f[i&1][j],f[~i&1][j]+abs(a[i&1]-a[~i&1]));
    28             f[i&1][a[~i&1]]=min(f[i&1][a[~i&1]],f[~i&1][j]+abs(a[i&1]-j));
    29         }
    30     }
    31     unsigned long long ans=~0;
    32     for(register unsigned i=0;i<n;i++) {
    33         ans=min(ans,f[q&1][i]);
    34     }
    35     printf("%llu
    ",ans);
    36     return 0;
    37 }
    View Code
  • 相关阅读:
    类数组(伪数组)
    go面试题[2]
    go面试题[1]
    go编程第十五课时
    php实现堆排序
    go编程第十三课时
    go第十一课时
    关于循环队列 -> 击鼓传花
    网栅格布局
    《学习JAVASCRIPT数据结构与算法》 ES6 部分笔记
  • 原文地址:https://www.cnblogs.com/skylee03/p/7609824.html
Copyright © 2020-2023  润新知