首页 > 代码库 > POJ 3735 Training little cats 矩阵快速幂应用

POJ 3735 Training little cats 矩阵快速幂应用

点击打开链接


Training little cats
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 9807 Accepted: 2344

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 integersn, m and k are given firstly, where n is the number of cats andk 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 6
g 1
g 2
g 2
s 1 2
g 3
e 2
0 0 0

Sample Output

2 0 1

Source

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

有n只猫,一共有三种操作分别是:
g x 让第x只猫得到一个花生
e x 让第x只猫吃掉所有的花生
s x y  将第x只猫和第y只猫的花生数换一换
对于这些操作一共有k次,成为一整套。
重复这一整套操作m次,问最后每只猫有多少花生米。

巧妙的转换为矩阵相乘来操作。
设一个(n+1)*(n+1)
的矩阵,每一列代表一只猫,最后一行代表猫的花生米的个数。如果g操作则将最后一行+1,如果e操作,则将这一列置零,如果是s操作,则将x列和y列进行交换。这样就得到这样一个矩阵:              
                            {                               }
                            {        A             B     }
                            {                               }
                            {                               }
                            {        C              D   }
这四部分当中A是由0,1构成的稀疏矩阵,B是最后一列 (除了最后一个元素) 并且全由0构成,C是最后一行 (除了最后一个元素) 代表每只猫的花生米数,D只有一个元素是1.
因为iM太大,即使是矩阵快速幂也会超时,因此可以对于稀疏矩阵进行优化。
对于稀疏矩阵可以这么计算:
for(int i=0;i<=n;i++)
        for(int k=0;k<=n;k++)
        if(a.m[i][k])
            for(int j=0;j<=n;j++)
                c.m[i][j]+=a.m[i][k]*b.m[k][j];
这样的话就可以愉快的在oj上跑200多MS。


//1768K	235MS
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 127
#define ll long long
using namespace std;
ll n,m,k;
struct Matrax
{
    ll m[maxn][maxn];
    void clear(){memset(m,0,sizeof(m));}
}a,per;
void init()//建立矩阵
{
    a.clear();
    per.clear();
    char s[2];
    ll x,b;
    for(int i=0;i<=n;i++)
        {a.m[i][i]=1;per.m[i][i]=1;}
    for(ll j=0;j<k;j++)
    {
        scanf("%s",s);
        if(s[0]=='g')
        {
            scanf("%I64d",&x);
            a.m[n][x-1]++;
        }
        if(s[0]=='e')
        {
            scanf("%I64d",&x);
            for(int i=0;i<=n;i++)
                a.m[i][x-1]=0;
        }
        if(s[0]=='s')
        {
            scanf("%I64d%I64d",&x,&b);
            for(ll i=0;i<=n;i++)
                swap(a.m[i][x-1],a.m[i][b-1]);
        }
    }
}
Matrax multi(Matrax a,Matrax b)//矩阵相乘
{
    Matrax c;
    c.clear();
    for(int i=0;i<=n;i++)
        for(int k=0;k<=n;k++)
        if(a.m[i][k])
            for(int j=0;j<=n;j++)
                c.m[i][j]+=a.m[i][k]*b.m[k][j];
    return c;
}
Matrax power(ll k)//矩阵快速幂
{
    Matrax p,ans=per;
    p=a;
    while(k)
    {
        if(k&1){ans=multi(ans,p);k--;}
        else {k/=2;p=multi(p,p);}
    }
    return ans;
}
int main()
{
    while(scanf("%I64d%I64d%I64d",&n,&m,&k),n|m|k)
    {
        init();
        Matrax ans=power(m);
        for(int i=0;i<n-1;i++)
            printf("%I64d ",ans.m[n][i]);
        printf("%I64d\n",ans.m[n][n-1]);
    }
    return 0;
}