NOI2020D1T1美食家

传送门:QAQQAQ

完了完了NOI签到题全班打不出来,真就全部成为时代的眼泪了。。。

首先$O(mT)$的$dp$显然,然后因为$T$很大$w$很小矩阵快速幂显然,但是有$k=200$卡不过去。

然后因为行向量乘上转移矩阵是$O(n^{2})$的,所以我们枚举的$k$时只用行向量乘上转移矩阵,转移矩阵的自乘放在外面倍增预处理,这样复杂度是$O(n^{2}*k*log(V)+(n^{3}*log(V)))$,开了O2非常稳

所以最近两道几乎正解的矩乘都没打出来。。一道倍增预处理转移矩阵优化,一道先DFT转点值再快速幂而不是每次快速幂用FFT优化来降复杂度。。

菜是原罪。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const ll inf=(ll)1e15;
#define mk make_pair
void checkmin(ll &x,ll y){if(x>y) x=y;}
void checkmax(ll &x,ll y){if(x<y) x=y;}
const int N=2010;
vector<pii> v[N],G[N];
int t[N],X[N],Y[N],c[N];
int n,m,T,k;
struct Edge
{
    int from,to,cost;
}E[N];


void init()
{
    scanf("%d%d%d%d",&n,&m,&T,&k);
    for(int i=1;i<=n;i++) scanf("%d",&c[i]);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&E[i].from,&E[i].to,&E[i].cost);
        v[E[i].from].push_back(mk(E[i].to,E[i].cost));
        G[E[i].to].push_back(mk(E[i].from,E[i].cost));
    }
    for(int i=1;i<=k;i++) scanf("%d%d%d",&t[i],&X[i],&Y[i]);
}

namespace solver1{
    ll dp[52600][55]; int a[52600][55];
    void init()
    {
        memset(a,0,sizeof(a));
        for(int i=1;i<=k;i++) a[t[i]][X[i]]=Y[i];
    }
    void main()
    {
        init();
        for(int i=0;i<=T;i++)
            for(int j=1;j<=n;j++) dp[i][j]=-inf;
        dp[0][1]=c[1];
        for(int i=1;i<=T;i++)
        {
            for(int j=1;j<=n;j++)
            {
                for(int p=0;p<(int)G[j].size();p++)
                {
                    int to=G[j][p].first,w=G[j][p].second;
                    if(i<w) continue;
                    checkmax(dp[i][j],dp[i-w][to]+c[j]);
                }
            }
            for(int j=1;j<=n;j++) dp[i][j]+=a[i][j];
        }
        if(dp[T][1]<=0) puts("-1");
        else printf("%lld\n",dp[T][1]);
    }
}

struct matrix{
    ll a[255][255];
    int n,m;
    matrix(){}
    matrix(int n,int m):n(n),m(m){
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++) a[i][j]=-inf;
    }
};

matrix operator * (matrix A,matrix B)
{
    matrix C(A.n,B.m);
    for(int i=1;i<=C.n;i++)
    {
        for(int k=1;k<=A.m;k++)
        {
            if(A.a[i][k]==-inf) continue;
            for(int j=1;j<=C.m;j++) 
                checkmax(C.a[i][j],A.a[i][k]+B.a[k][j]);
        }
    }
    return C;
}

struct LI{
    int t,x,y;
    LI(){}
    LI(int t,int x,int y):t(t),x(x),y(y){}
    bool operator < (const LI &rhs) const{
        return t<rhs.t;
    }
}limit[N];

matrix Base[31];
void Qpow(matrix &A,int y)
{
    matrix ret(A.n,A.m);
    for(int i=1;i<=A.n;i++) ret.a[i][i]=0;
    for(int i=30;i>=0;i--)
    {
        if((1<<i)<=y) y-=(1<<i),A=A*Base[i];
    }
}

namespace solver2{
    ll dp1[7][55]; int a[7][55];
    void init()
    {
        memset(a,0,sizeof(a));
        for(int i=1;i<=k;i++) 
            if(t[i]<=5) a[t[i]][X[i]]=Y[i];
    }
    void build()
    {
        init();
        for(int i=0;i<=5;i++)
            for(int j=1;j<=n;j++) dp1[i][j]=-inf;
        dp1[0][1]=c[1];
        for(int i=1;i<=5;i++)
        {
            for(int j=1;j<=m;j++)
            {
                int u=E[j].from,to=E[j].to,w=E[j].cost;
                if(i<E[j].cost) continue;
                if(dp1[i-w][u]==-inf) continue;
                checkmax(dp1[i][to],dp1[i-w][u]+c[to]);
            }
            for(int j=1;j<=n;j++) dp1[i][j]+=a[i][j];
        }
    }
    void main()
    {
        build();
        int TMP=0;
        for(int i=1;i<=k;i++)
        {
            if(t[i]<=5) i--,k--,TMP++;
            limit[i]=LI(t[i+TMP],X[i+TMP],Y[i+TMP]);
        }
        sort(limit+1,limit+k+1);
        matrix A(1,n*5);
        for(int i=1;i<=5;i++)
        {
            for(int j=1;j<=n;j++) A.a[1][(i-1)*n+j]=dp1[i][j]; 
        }
        //print(A);
        for(int i=0;i<=30;i++) 
        {
            Base[i].m=Base[i].n=5*n; 
            for(int j=1;j<=5*n;j++)
            {
                for(int t=1;t<=5*n;t++)
                {
                    Base[i].a[j][t]=-inf;
                }
            }
        }
        for(int j=1;j<=n*4;j++) Base[0].a[j+n][j]=0;
        for(int i=1;i<=m;i++)
        {
            int u=E[i].from,to=E[i].to,w=E[i].cost;
            int from=(5-w)*n+u; to=4*n+to;
            Base[0].a[from][to]=c[E[i].to];
        }
        //print(Base);
        for(int i=1;i<=30;i++) Base[i]=Base[i-1]*Base[i-1];

        T-=5;
        for(int i=1;i<=k;i++) limit[i].t-=5;
        int now=0;
        for(int i=1;i<=k;i++)
        {
            int pos=limit[i].t;
            Qpow(A,pos-now);
            now=pos;
            if(A.a[1][4*n+limit[i].x]==-inf) continue;
            else A.a[1][4*n+limit[i].x]+=limit[i].y;
        }

        Qpow(A,T-now);
        if(A.a[1][4*n+1]<=0) puts("-1");
        else printf("%lld\n",A.a[1][4*n+1]);
    }
}

namespace solver3{
    int dis[N],vis[N];
    ll tot=0;
    void dfs(int u){
        if(vis[u]) return;
        vis[u]=1;
        for(int i=0;i<(int)v[u].size();i++)
        {
            int to=v[u][i].first,w=v[u][i].second;
            dis[to]=dis[u]+w;
            dfs(to);
        }
    }
    void main()
    {
        memset(vis,0,sizeof(vis)); dis[1]=0;
        dfs(1);
        if(T%dis[1]!=0) 
        {
            puts("-1");
            return;
        }
        ll ans=c[1];
        for(int i=1;i<=k;i++)
        {
            if((t[i]-dis[X[i]])%dis[1]==0) ans+=Y[i];
        }
        for(int i=1;i<=n;i++) tot+=c[i];
        ans+=T/dis[1]*tot;
        printf("%lld\n",ans);
    }
}

bool iscircle()
{
    if(n!=m) return 0;
    for(int i=1;i<=m;i++)
    {
        if(E[i].to!=E[i].from%n+1) return 0;
    }    
    return 1;
}

void solve()
{
    if(T<=52600) 
    {
        solver1::main();
        return;
    }
    if(iscircle())
    {
        solver3::main();
        return;
    }
    solver2::main();
    return;
}

int main()
{
    //freopen("delicacy.in","r",stdin);
    //freopen("delicacy.out","w",stdout);
    init();
    solve();
    fclose(stdin); fclose(stdout);
    return 0;
}
View Code

 

posted @ 2020-08-18 22:08  'Clovers'  阅读(188)  评论(1编辑  收藏  举报