vijos1049——送给圣诞夜的礼品

vijos1049
这题。。我已经不想说什么了
这里写图片描述
(╯—﹏—)╯(┷━━━┷
这题根据题目意思,暴力做法应该是模拟,模拟k次
然而100%数据k=maxlongint-1;
模拟显然炸飞

好吧我一开始真的不知道这题要怎么搞到log或者sqrt
看了下题解
矩阵快速幂=_=
突然无言以对
其实思路很简单
例如n=4
我们构造一个初始矩阵
{1}
{2}
{3}
{4}
{..}
然后比如我们要一次变化:3214
那么我们再构造一个只有0,1的n*n的矩阵
{0,0,1,0}
{0,1,0,0}
{1,0,0,0}
{0,0,0,1}
就是v[i][s[i]]=1
至于为什么这样呢?
模拟一下就可以理解了
毕竟我这么傻的人都想到了
我们把m次变化看作一整个变化c(a)
这是很容易理解的,如果不能理解。。拿两个变化的矩阵乘一下就知道了
因为k远大于m
所以我们可以使用快速幂来很快的求出c(a)^k/m
余下小于m次的变化我们再去for循环乘一遍就好了

这里注意一下!
本题快速幂一定要非递归!!
递归快速幂re…
【请吸取前人血的教训 正确率已一蹶不振

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<string>
#include<cstring>
#define inf 1e9
#define ll long long
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Dow(i,j,k) for(int i=k;i>=j;i--)
using namespace std;
int n,m,k,tt;
struct mat
{
    int v[101][101];
    int size_x,size_y;
    mat(){memset(v,0,sizeof v);size_x=size_y=0;}
}tmp[201];
inline mat mul(mat x,mat y)
{
    mat rul;
    rul.size_y=y.size_y;rul.size_x=x.size_x;
    For(i,1,x.size_x)
        For(j,1,y.size_y)
        {
            int tmp=0;
            For(k,1,x.size_y)
                tmp=tmp+x.v[i][k]*y.v[k][j];
            rul.v[i][j]=tmp;
        }
    return rul;
}
inline void out(mat x)
{
    For(i,1,x.size_x)
    {
        For(j,1,x.size_y)
            cout<<x.v[i][j]<<' ';
    }
    cout<<endl;
}
inline mat ksm(mat x,int y)
{
    mat sum=x;y--;for(;y;y>>=1){if(y&1)sum=mul(sum,x);x=mul(x,x);}return sum;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    mat t;
    For(i,1,n)  
    {
        scanf("%d",&tt);
        t.v[i][tt]=1;
    }
    mat b;
    For(i,1,n)
        b.v[i][1]=i;
    b.size_x=n;b.size_y=1;
    t.size_x=t.size_y=n;
    tmp[1]=t;
    For(i,2,m)
    {
        For(j,1,n)
        {
            scanf("%d",&tt);
            tmp[i].v[j][tt]=1;
        }
        tmp[i].size_x=tmp[i].size_y=n;
        t=mul(tmp[i],t);
    }
    if(k>=m)
        b=mul(ksm(t,k/m),b);
    For(i,1,k%m)
        b=mul(tmp[i],b);
    out(b);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值