zoukankan      html  css  js  c++  java
  • 「USACO 2020.12 Platinum」Spaceship

    「USACO 2020.12 Platinum」Spaceship

    看到题目第一个想到的是:按照路径长度可以确定按钮次数和路径次数

    然而路径长度是(2^k)级别的。。

    下文认为(n,q,k)同阶

    既然无法考虑长度,那么就直接在(dp)时将路径作为状态压入

    (dp_{i,s,t})表示前面(i)个按钮未按过,从(s)走到(t)的路径数

    显然(dp_{i})可以看做一个类似矩阵的转移,设邻接矩阵为(E)

    那么得到(dp_{i}=dp_{i-1}+dp_{i-1}cdot Ecdot dp_{i-1})

    ((dp_i)不一定按了(i)这个按钮,所以考虑按或者不按)

    那么对于(b_s,b_t)的情况,考虑把操作序列分成两段

    显然操作序列有唯一一个按过恰好一次的最大的按钮(max),可以在这里将操作序列分成两段

    处理出(b_s)(max)(max)(b_t)的两部分方案数合并即可

    以处理(b_s ightarrow max)为例

    类似上面的操作,令(F_{i,j})表示最大按钮为(i),且按过(i)之后没有按过其他按钮,停留在(j)的方案数 ((F_i)是一个向量)

    初始显然有(F_{b_s,s}=1)

    (displaystyle i>b_s,F_{i}=sum_{j<i} F_{j}cdot dp_{j-1}cdot E)(按过(j)之后可以继续按([1,j-1]))

    前缀和即可,复杂度为(O(n^3))

    同理处理出(max ightarrow b_t)的权值合并即可

    #include<bits/stdc++.h>
    using namespace std;
    #define Mod1(x) ((x>=P)&&(x-=P))
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    
    const int N=62,P=1e9+7,INF=1e9+10;
    
    int n,m,q;
    struct Mat{
    	int a[N][N];
    	void clear(){ memset(a,0,sizeof a); }
    	Mat operator * (const Mat &x) const {
    		Mat res; res.clear();
    		rep(i,1,n) rep(j,1,n) if(a[i][j]) rep(k,1,n) res.a[i][k]=(res.a[i][k]+1ll*a[i][j]*x.a[j][k])%P;
    		return res;
    	}
    	Mat operator + (const Mat &x) const {
    		Mat res;
    		rep(i,1,n) rep(j,1,n) res.a[i][j]=a[i][j]+x.a[i][j],Mod1(res.a[i][j]);
    		return res;
    	}
    } I,E,dp[N];
    int F[N][N],G[N][N];
    int S[N][N];
    
    int main(){
    	freopen("spaceship.in","r",stdin),freopen("spaceship.out","w",stdout);
    	scanf("%d%d%d",&n,&m,&q);
    	rep(i,1,n) I.a[i][i]=1;
    	rep(i,1,n) rep(j,1,n) scanf("%1d",&E.a[i][j]);
    	dp[0]=I;
    	rep(i,1,m) dp[i]=dp[i-1]+dp[i-1]*E*dp[i-1];
    	while(q--) {
    		int bs,s,bt,t; scanf("%d%d%d%d",&bs,&s,&bt,&t);
    		memset(F,0,sizeof F),memset(G,0,sizeof G);
    		memset(S,0,sizeof S);
    		F[bs][s]=1;
    		rep(i,1,n) S[bs][i]=dp[bs-1].a[s][i];
    		rep(i,bs+1,m) {
    			rep(a,1,n) if(S[i-1][a]) rep(b,1,n) F[i][b]=(F[i][b]+1ll*S[i-1][a]*E.a[a][b])%P;
    			rep(a,1,n) S[i][a]=S[i-1][a];
    			rep(a,1,n) if(F[i][a]) rep(b,1,n) S[i][b]=(S[i][b]+1ll*F[i][a]*dp[i-1].a[a][b])%P;
    		}
    
    		memset(S,0,sizeof S);
    		G[bt][t]=1;
    		rep(i,1,n) S[bt][i]=dp[bt-1].a[i][t];
    		rep(i,bt+1,m) {
    			rep(a,1,n) rep(b,1,n) G[i][a]=(G[i][a]+1ll*S[i-1][b]*E.a[a][b])%P;
    			rep(a,1,n) S[i][a]=S[i-1][a];
    			rep(a,1,n) rep(b,1,n) S[i][a]=(S[i][a]+1ll*G[i][b]*dp[i-1].a[a][b])%P;
    		}
    
    		int ans=0;
    		rep(i,1,m) rep(j,1,n) ans=(ans+1ll*F[i][j]*G[i][j])%P;
    		printf("%d
    ",ans);
    	}
    }
    
    
  • 相关阅读:
    数据统计
    判断文件是否改变
    多列表统计之后的数组排序
    被弃用的php函数以及被那个代替
    curl数据采集
    MySQL教程
    使用多次join数据重复的问题
    ThinkPHP5高阶实战教程 --诠释为API开发而生
    SpringBoot使用thymeleaf模板
    SpringBoot与JPA
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14429068.html
Copyright © 2011-2022 走看看