poj_3735_Training little cats(矩阵快速幂)

来源:互联网 发布:2017软件退税政策 编辑:程序博客网 时间:2024/05/01 18:41

Training little cats
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 8468 Accepted: 2033

Description

Facer's pet cat just gave birth to a brood of little cats. Having considered the health of those lovely cats, Facer decides to make the cats to do some exercises. Facer has well designed a set of moves for his cats. He is now asking you to supervise the cats to do his exercises. Facer's great exercise for cats contains three different moves:
g i : Let the ith cat take a peanut.
e i : Let the ith cat eat all peanuts it have.
s i j : Let the ith cat and jth cat exchange their peanuts.
All the cats perform a sequence of these moves and must repeat it m times! Poor cats! Only Facer can come up with such embarrassing idea. 
You have to determine the final number of peanuts each cat have, and directly give them the exact quantity in order to save them.

Input

The input file consists of multiple test cases, ending with three zeroes "0 0 0". For each test case, three integers nm and k are given firstly, where n is the number of cats and k is the length of the move sequence. The following k lines describe the sequence.
(m≤1,000,000,000, n≤100, k≤100)

Output

For each test case, output n numbers in a single line, representing the numbers of peanuts the cats have.

Sample Input

3 1 6g 1g 2g 2s 1 2g 3e 20 0 0

Sample Output

2 0 1

Source

PKU Campus 2009 (POJ Monthly Contest – 2009.05.17), Facer

题型:数论


题意

对n只猫进行操作,起始时所有猫都没有花生,操作有如下几种:

1、g i :给第i个猫一个花生

2、e i :让第i个猫吃掉它所有的花生

3、s i j :让第i个猫和第j个猫交换它们的花生

现在对猫有m轮操作,每轮有k个指令,问最后每个猫各有多少花生。


分析

解题的关键就是构造出一轮操作的矩阵。

设置花生的矩阵为行矩阵(0 0 0 …… 0 0 1)总共n+1个元素。

构造一轮操作的矩阵:

先初始化一个(n+1 n+1)的单位矩阵;

有g i时,第i列的最后一位加1;

有e i时,第i列的元素全部设置为0;

有s i j时,将第i列与第j列对调。


以样例为例:

初始化矩阵:p(0 0 0 1
 即每只猫咪的花生米个数为0。

初始化a为单位矩阵
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

经过一轮操作
g 1        //给1号1颗花生米,在第一列的最后一行加1
1 0 0 0
0 1 0 0
0 0 1 0
1 0 0 1

g 2
1 0 0 0
0 1 0 0
0 0 1 0
1 1 0 1

g 2
1 0 0 0
0 1 0 0
0 0 1 0
1 2 0 1

s 1 2                   //交换第1,2列
0 1 0 0
1 0 0 0
0 0 1 0
2 1 0 1

g 3
0 1 0 0
1 0 0 0
0 0 1 0
2 1 1 1

e 2                       //将第2列全部置为0
0 0 0 0
1 0 0 0
0 0 1 0
2 0 1 1


最后:

                                         p = p * a* a* a …… * a* a = p * (a ^ m)

使用矩阵快速幂即可解决。

注意在矩阵乘法中加一个优化,否则TLE(坑爹了,说多了都是泪啊~)。


代码:

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#define LL __int64using namespace std;const LL MAXN=110;struct Matrix{    LL mat[MAXN][MAXN];};LL n,m,k;Matrix mull(Matrix m1,Matrix m2){    Matrix ans;    memset(ans.mat,0,sizeof(ans.mat));        for(LL j=0;j<=n;j++)                for(LL k=0;k<=n;k++)                    if(m1.mat[0][k]&&m2.mat[k][j])//优化,否则TLE                        ans.mat[0][j]=(ans.mat[0][j]+m1.mat[0][k]*m2.mat[k][j]);    return ans;}Matrix mul(Matrix m1,Matrix m2){    Matrix ans;    memset(ans.mat,0,sizeof(ans.mat));    for(LL i=0;i<=n;i++)        for(LL j=0;j<=n;j++)                for(LL k=0;k<=n;k++)                    if(m1.mat[i][k]&&m2.mat[k][j])//优化,否则TLE                        ans.mat[i][j]=(ans.mat[i][j]+m1.mat[i][k]*m2.mat[k][j]);    return ans;}Matrix pow(Matrix m1,LL b){    Matrix ans;    for(LL i=0;i<=n;i++)        for(LL j=0;j<=n;j++)            ans.mat[i][j]=(i==j?1:0);    while(b){        if(b&1)            ans=mul(ans,m1);        m1=mul(m1,m1);        b/=2;    }    return ans;}int main(){    Matrix a,p;    while(1){        scanf("%I64d%I64d%I64d",&n,&m,&k);        if(n==0&&m==0&&k==0) break;        for(LL i=0;i<=n;i++){            for(LL j=0;j<=n;j++){                if(i==j){                    a.mat[i][j]=1;                    //p.mat[i][j]=1;                }                else{                    a.mat[i][j]=0;                    //p.mat[i][j]=0;                }            }        }        for(LL i=0;i<n;i++){            p.mat[0][i]=0;        }        p.mat[0][n]=1;        char str[5];        LL x,y;        while(k--){            scanf("%s",str);            if(str[0]=='g'){                scanf("%I64d",&x);                a.mat[n][x-1]++;            }            if(str[0]=='e'){                scanf("%I64d",&x);                for(LL j=0;j<=n;j++){                    a.mat[j][x-1]=0;                }            }            if(str[0]=='s'){                scanf("%I64d%I64d",&x,&y);                for(LL j=0;j<=n;j++){                    LL tmp=a.mat[j][x-1];                    a.mat[j][x-1]=a.mat[j][y-1];                    a.mat[j][y-1]=tmp;                }            }        }        Matrix ans=pow(a,m);        p=mull(p,ans);        printf("%I64d",p.mat[0][0]);        for(int i=1;i<n;i++){            printf(" %I64d",p.mat[0][i]);        }        printf("\n");    }    return 0;}


原创粉丝点击