POJ 3735 Training little cats

来源:互联网 发布:windows有多少行代码 编辑:程序博客网 时间:2024/05/22 18:23

题目连接:Training little cats

题目大意:有n只猫咪,开始时每只猫咪有花生0颗,现有一组操作,由下面三个中的k个操作组成:
1. g i 给i只猫咪一颗花生米
2. e i 让第i只猫咪吃掉它拥有的所有花生米
3. s i j 将猫咪i与猫咪j的拥有的花生米交换
现将上述一组操作做m次后,问每只猫咪有多少颗花生?

题目思路:我们想到m是1e9的次数,所以我们是不可以使用朴素的方法来计算的,所以这个时候我们可以想到使用矩阵来解决这样一个问题,我们需要有一个矩阵来计算快速幂,幂次之后得到的就是再重复一次操作,我们可以去构造一个单位矩阵,然后,g i,就使a[0][i]++;e i,就使第j列的数全部清空;s i j就使i列和j列交换,这样去模拟一下发现是可以做到重复操作的,比如这样的一个操作:
g 1;g 2;s 3 4,现在我们去模拟一下,初始矩阵(只操作这些操作一遍)为

1000110000011010
,然后做一次乘法后发现矩阵变成了:
1000210010101001
刚好是重复一次操作,然后输出第一行的数就好了,需要注意的是n为100,直接裸乘复杂度会炸,所以我们需要使用优化,因为矩阵中有很多的非零数,所以我们在处理的时候需要处理一下0以防止复杂度爆炸,这样处理一下就好了

#include <map>#include <set>#include <queue>#include <stack>#include <cmath>#include <vector>#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;const int maxn = 105;ll N,M,K,x,y;struct mat{    ll m[maxn][maxn];    void Clear(){memset(m,0,sizeof(m));}    void unit(){        Clear();        for(int i = 0;i <= maxn-1;i++) m[i][i] = 1;    }};mat operator *(mat a,mat b){    mat ret;    for(ll i = 0;i <= maxn-1;i++)        for(ll j = 0;j <= maxn-1;j++)            ret.m[i][j] = 0;    for(ll i = 0;i <= maxn-1;i++){        for(ll k = 0;k <= maxn-1;k++){            if(a.m[i][k]){                for(ll j = 0;j <= maxn-1;j++)                    ret.m[i][j] += a.m[i][k]*b.m[k][j];            }        }    }    return ret;}mat pow_mat(mat a,ll n){    if(n == 1) return a;    mat ret;    ret.unit();    while(n){        if(n&1) ret = ret*a;        a = a*a;        n >>= 1;    }    return ret;}int main(){    char ch[10];    while(~scanf("%lld%lld%lld",&N,&M,&K)&&N+M+K){        mat a;        a.unit();        while(K--){            scanf("%s",&ch);            if(ch[0] == 'g'){                scanf("%lld",&x);                a.m[0][x]++;            }            else if(ch[0] == 'e'){                scanf("%lld",&x);                for(int j = 0;j <= maxn-1;j++)                    a.m[j][x] = 0;            }            else if(ch[0] == 's'){                scanf("%lld%lld",&x,&y);                if(x == y) continue;                for(int j = 0;j <= maxn-1;j++)                    swap(a.m[j][x],a.m[j][y]);            }        }        if(M == 0){            for(int j = 1;j <= N;j++)                printf("0%c",j == N?'\n':' ');        }        else{            a = pow_mat(a,M);            for(int j = 1;j <= N;j++)                printf("%lld%c",a.m[0][j],j == N?'\n':' ');        }    }    return 0;}
原创粉丝点击