jzoj5335 【NOIP2017提高A组模拟8.24】早苗 (递推优化矩乘)

题面

这里写图片描述
这里写图片描述

分析

很吼的一题。
看到1e16那肯定是矩阵乘法
考虑设状态 f[i][j] 表示1..i,现在有恰好连续j个颜色不一样的。
如何转移?
首先是到j+1的,只要他后面有j个不同,那么都有(m-j)种放法转移到 f[i+1][j+1]
然后是重复的,假设在第x个位置与当前放的有重复,那么重复的方案是多少呢?
考虑每一种确定的方案,他都有恰好一种放法能转移到 f[i+1][1..j]
所以这个转移就恰好是 f[i][j]>f[i+1][1..j]
直接套个矩阵乘法优化就OK了,注意矩阵乘法不要打得太浪费资源。 不过该传参还是得传参,该返回还是得返回,不要因小失大了。 (最好能测一下极限 这种题的话)

Demo

#include <cstdio>
#include <iostream>
#include <cstring>
#define add(x,y) (x=(x+y)%mo)
#define copy(x,y) memcpy(x.h,y.h,sizeof y.h)
using namespace std;
typedef long long ll;
const int mo=1e9+7,M=105;
struct mat{
    ll h[M][M];
    ll * operator[](int x) {return h[x];}
    void clear() {memset(h,0,sizeof h);}
} omat,f,tmp,c,rzksm,rzmu;
ll n,m;
void mult(mat &a,mat &b) {
    rzmu.clear();
    for (int i=1; i<=m+1; i++)
    for (int j=1; j<=m+1; j++) 
    for (int k=1; k<=m+1; k++) add(rzmu[i][j],a.h[i][k]*b.h[k][j]);
}
void ksm(mat &x,ll y) {
    if (y==1) {
        copy(rzksm,x);
        return;
    }
    ksm(x,y>>1);
    mult(rzksm,rzksm);
    copy(rzksm,rzmu);
    if ((y&1)==1) mult(rzksm,x),copy(rzksm,rzmu);
}

int main() {
    freopen("2.in","r",stdin);
    cin>>n>>m;
    for (int i=1; i<m; i++) {
        omat.h[i][i+1]=m-i;
        for (int j=1; j<=i; j++) omat.h[i][j]=1;
    }
    f.h[1][1]=m;
    ksm(omat,n-1);
    mult(f,rzksm);
    ll ans=0;
    for (int i=1; i<m; i++) add(ans, rzmu.h[1][i]);
    printf("%lld\n",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值