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
原文地址:https://www.cnblogs.com/Blue233333/p/8511027.html