[破碎的状态] cf 917C
迟到一天的题解QAQ
http://codeforces.com/contest/917/problem/C
题意:x个青蛙
每次让最左边的青蛙往前跳1~k步,不允许两只青蛙呆在同一个格子上
跳1~k格消耗c1~ck的体力
有q个特殊的点,第p个点每只青蛙跳上去会消耗额外的wp点体力(如果是负数那么就是增加体力)
一个长度为x的一条路(一共x个格子的路)
一开始x个青蛙在1,2...x的位置
问到达n-x+1,n-x+2....n的位置
最少需要多少体力(可以为负)
1<=x<=k<=8 n<=1e8 0<=q<=25 (q<=n-k)
思路:
感谢@FizzyDavid提供的题解
这个东西,首先想到dp
dp[i][j]表示 第一只青蛙在i,后续青蛙相对位置为j(因为最多跳k格所以j<2^k也就是2^8)
然后这个dp暴力转移是O(2^8 n*8)的,显然不可以
就算有别的转移姿势,也不太行
但是以往遇到相似的题我们会想矩阵乘法对吧
矩阵乘法的一个问题是只能转移一格,而这里i,"101"选k=3就跳成了i+2,"110"
当然我们可以考虑用i+1,"011"做过渡;换句话说我们定义
dp[i][j]表示,在第i个位置,后面j个位置青蛙相对位置为j
这个题的dp.....也有点相似于矩阵乘法对吧...
我们定义新的乘法,那么如果这个乘法也满足结合律,那么我们就可以用同样的矩阵乘法来做
虽然我不会证,但是FizzyDavid告诉我是对的(大雾)
转移方式是
新的矩阵C(i,k) = Min{A(i,j)+B(j,k)}
我觉得好像结合律其实挺对的,你在前A步到达某个点,消耗是多少
然后再走B步,那么我们枚举在第A步的状态就行
那么代码如下:
#include<set> #include<map> #include<list> #include<queue> #include<stack> #include<string> #include<time.h> #include<math.h> #include<memory> #include<vector> #include<bitset> #include<fstream> #include<stdio.h> #include<utility> #include<string.h> #include<iostream> #include<stdlib.h> #include<algorithm> using namespace std; int c[15]; int ma[305]; int cnt=0; const long long inf=1999999999999999999ll; struct matrix { long long a[75][75]; friend matrix operator * (const matrix &a,const matrix &b) { int i,j,k; matrix c; for (i=0;i<cnt;i++) { for (j=0;j<cnt;j++) { c.a[i][j]=inf; } } for (i=0;i<cnt;i++) { for (j=0;j<cnt;j++) { for (k=0;k<cnt;k++) { c.a[i][k]=min(c.a[i][k],a.a[i][j]+b.a[j][k]); } } } return c; } matrix () { int i; int j; for (i=0;i<75;i++) { for (j=0;j<75;j++) { a[i][j]=inf; } a[i][i]=0; } } }; matrix a; matrix mul(int x) { if (x==0) return matrix(); matrix b=mul(x/2); b=b*b; if (x%2==1) b=b*a; return b; } pair<int,int> p[75]; int main() { #ifdef absi2011 freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif int x,k; int n,q; scanf("%d%d%d%d",&x,&k,&n,&q); int i; for (i=0;i<k;i++) { scanf("%d",&c[i]); } memset(ma,-1,sizeof(ma)); for (i=0;i<(1<<k);i++) { int j; int sum=0; for (j=0;j<k;j++) { if ((1<<j)&i) sum++; } if (sum==x) ma[i]=cnt++; } int j; for (i=0;i<cnt;i++) { for (j=0;j<cnt;j++) { a.a[i][j]=inf; } } for (i=0;i<(1<<k);i++) { if (ma[i]==-1) continue; if (i&1) { //Can move! for (j=1;j<=k;j++) { if ((1<<j)&i) continue; a.a[ma[i]][ma[((1<<j)^i)>>1]]=c[j-1]; } } else { a.a[ma[i]][ma[i>>1]]=0; } } int now=1; for (i=0;i<q;i++) { scanf("%d%d",&p[i].first,&p[i].second); } sort(p,p+q); matrix xx; long long ans=0; for (i=0;i<q;i++) { if (p[i].first>=n-x+1) { ans+=p[i].second; continue; } xx=xx*mul(p[i].first-now); now=p[i].first; int j; for (j=1;j<(1<<k);j+=2) { if (ma[j]!=-1) { int l; for (l=0;l<cnt;l++) { xx.a[l][ma[j]]+=p[i].second; } } } } xx=xx*mul(n-x+1-now); cout<<xx.a[0][0]+ans<<endl; return 0; }
Aug 25, 2022 03:10:00 PM
Meghalaya Board Model Paper 2023 Class 2 Pdf Download with Answers for Bengali Medium, English Medium, Hindi Medium, Urdu Medium & Students for Small Answers, Long Answer, Very Long Answer Questions, and Essay Type Questions to Term1 & Term2 Exams at official website. Meghalaya Board 2nd Class Model Paper New Exam Scheme or Question Pattern for Sammittive Assignment Exams (SA1 & SA2): Very Long Answer (VLA), Long Answer (LA), Small Answer (SA), Very Small Answer (VSA), Single Answer, Multiple Choice and etc.