• Codeforces917C. Pollywog


    $n leq 1e8$个石头,$x leq 8$个蝌蚪一开始在最左边$x$个石子,要跳到最右的$x$个,每次只能最左边的蝌蚪跳一次,一个石头不能站两个蝌蚪,跳可以跳$1到k,x leq k leq 8$步,跳$i$步的代价是$cost_i$,还有$q leq 25$个神奇石头,跳上去代价会$+w_i$,$w_i$可能为负数。问完成跳跃的最小代价。

    不知道跳蝌蚪是什么操作只听过跳蛤,大概是变相膜?

    好的严肃。从小数字$x$和$k$入手。由于每次只有最左的蝌蚪会跳,所以这$x$个蝌蚪一定每时每刻都在某连续的$k$个石头上。记这$k$个石头最左的那个(不一定上面有蝌蚪)为$i$,那么$i$处右边$k$个石子上的蝌蚪状态可以用二进制表示,最多是$C_8^4=70$个状态,挺小。这样就可以做转移了,转移复杂度是$C_k^x*k$,再乘个$n$直接爆炸。不过我们来看这个转移,$dp(i,j)=dp(i-1,k)+cost_t$,想到啥了?走若干步的最短路!这是可以用矩乘优化的,于是在不考虑$q$时,可以做$log_2n*(C_k^x)^3$的$dp$。

    然后来看$q$。一块神奇石头影响了$k$块地(di)的(de)转移,因此最多会有$q*k$块地受影响,挺小,矩乘到这些地段时停住,暴力转移。最终复杂度$log_2n*(C_k^x)^3+qk^2C_k^x$。

      1 //#include<iostream>
      2 #include<cstring>
      3 #include<cstdlib>
      4 #include<cstdio>
      5 //#include<map>
      6 #include<math.h>
      7 //#include<time.h>
      8 //#include<complex>
      9 #include<algorithm>
     10 using namespace std;
     11 
     12 int X,K,n,m,q;
     13 #define LL long long
     14 const LL inf=1e18;
     15 struct Mat
     16 {
     17     LL a[73][73];
     18     Mat() {for (int i=1;i<=70;i++) for (int j=1;j<=70;j++) a[i][j]=inf;}
     19     Mat operator * (const Mat &b)
     20     {
     21         Mat ans;
     22         for (int k=1;k<=m;k++)
     23             for (int i=1;i<=m;i++)
     24                 for (int j=1;j<=m;j++)
     25                     ans.a[i][j]=min(ans.a[i][j],a[i][k]+b.a[k][j]);
     26         return ans;
     27     }
     28 }base,f;
     29 
     30 Mat pow(Mat a,int b)
     31 {
     32     Mat ans,tmp=a; for (int i=1;i<=m;i++) ans.a[i][i]=0;
     33     while (b)
     34     {
     35         if (b&1) ans=ans*tmp;
     36         tmp=tmp*tmp; b>>=1;
     37     }
     38     return ans;
     39 }
     40 
     41 int state[266],ls,who[73];
     42 struct Ran{int l,r;}qq[33],ran[33]; int len;
     43 LL g[73],h[73];int cost[12];
     44 struct Block{int pos,w;}ww[33];
     45 bool cmpww(const Block &a,const Block &b) {return a.pos<b.pos;}
     46 struct Hash
     47 {
     48     int first[107],le; struct Edge{int to,v,next;}edge[33];
     49     Hash() {le=2;}
     50     void insert(int x,int y) {int h=x%107; Edge &e=edge[le]; e.to=x; e.v=y; e.next=first[h]; first[h]=le++;}
     51     int find(int x) {int h=x%107; for (int i=first[h];i;i=edge[i].next) if (edge[i].to==x) return edge[i].v; return -2e9;}
     52 }ha;
     53 
     54 int main()
     55 {
     56     scanf("%d%d%d%d",&X,&K,&n,&q);
     57     for (int i=1;i<=K;i++) scanf("%d",&cost[i]);
     58     for (int i=1;i<=q;i++) scanf("%d%d",&ww[i].pos,&ww[i].w); sort(ww+1,ww+1+q,cmpww);
     59     LL ans=0; for (int &i=q;i;i--) if (ww[i].pos>=n-X+1) ans+=ww[i].w; else break;
     60     for (int i=1;i<=q;i++) ha.insert(ww[i].pos,ww[i].w);
     61     for (int i=1;i<=q;i++) qq[i].l=max(ww[i].pos-K,2),qq[i].r=ww[i].pos;
     62     len=0; for (int i=1;i<=q;i++)
     63     {
     64         if (len && qq[i].l<=ran[len].r+1) ran[len].r=qq[i].r;
     65         else len++,ran[len].l=qq[i].l,ran[len].r=qq[i].r;
     66     }
     67     ls=0; for (int i=1;i<(1<<K);i++)
     68     {
     69         int cnt=0;
     70         for (int j=0;j<K;j++) if ((i>>j)&1) cnt++;
     71         if (cnt==X) ls++,state[i]=ls,who[ls]=i;
     72     } m=ls;
     73     for (int i=1;i<=ls;i++)
     74     {
     75         int s=who[i]>>1;
     76         if ((who[i]&1)==0) base.a[i][state[s]]=0;
     77         else for (int j=1;j<=K;j++) if (((s>>(j-1))&1)==0) base.a[i][state[s|(1<<(j-1))]]=cost[j];
     78     }
     79     f.a[1][1]=0; ran[0].r=1;
     80     for (int i=1;i<=len;i++)
     81     {
     82         f=f*pow(base,ran[i].l-ran[i-1].r-1);
     83         for (int j=1;j<=ls;j++) g[j]=f.a[1][j];
     84         for (int j=ran[i].l;j<=ran[i].r;j++)
     85         {
     86             for (int k=1;k<=ls;k++) h[k]=inf;
     87             for (int k=1;k<=ls;k++)
     88             {
     89                 int s=who[k]>>1;
     90                 if ((who[k]&1)==0) h[state[s]]=min(h[state[s]],g[k]);
     91                 else for (int l=1,tmp;l<=K;l++) if (((s>>(l-1))&1)==0)
     92                 {
     93                     int ns=s|(1<<(l-1));
     94                     if ((tmp=ha.find(j+l-1))!=-2e9) h[state[ns]]=min(h[state[ns]],g[k]+cost[l]+tmp);
     95                     else h[state[ns]]=min(h[state[ns]],g[k]+cost[l]);
     96                 }
     97             }
     98             for (int k=1;k<=ls;k++) g[k]=h[k];
     99         }
    100         for (int j=1;j<=ls;j++) f.a[1][j]=g[j];
    101     }
    102     f=f*pow(base,n-X+1-ran[len].r);
    103     printf("%lld
    ",ans+f.a[1][1]);
    104     return 0;
    105 }
    View Code
  • 相关阅读:
    数据增强
    变态跳台阶
    跳台阶
    数据分析--简单回测框架开发
    数据分析--羊驼交易法则(选股)
    数据分析--动量策略vs反转策略(选股)
    数据分析--PEG策略(选股)
    数据分析--布林带策略(择时)
    数据分析--均值回归策略(选股)
    数据分析--单因子选股策略、多因子选股策略(选股)
  • 原文地址:https://www.cnblogs.com/Blue233333/p/8511027.html
Copyright © 2020-2023  润新知