poj3735-Training little cats

poj3735 Training little cats

Training little cats
Time Limit: 2000MS

Memory Limit: 65536K
Total Submissions: 14750

Accepted: 3648
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 n, m 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 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

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 105;
typedef long long LL;

struct Matrix{
    LL n, m;
    LL a[MAXN][MAXN];
    void clear(){
      n = m = 0;
      memset(a, 0, sizeof(a));
    }
    Matrix operator * (const Matrix &b) const{
      Matrix tmp;
      tmp.clear();
      for(int i = 1; i <= m; i++)
        for(int k = 1; k <= m; k++)
          if(a[i][k])
            for(int j = 1; j <= m; j++)
              tmp.a[i][j] += a[i][k] * b.a[k][j];   
      tmp.n = n, tmp.m = m;
      return tmp;
    }
}S, A, I;

Matrix Fast(LL x){
    Matrix ans = I;
    while(x){
      if(x & 1) ans = ans * A;
      A = A * A;
      x >>= 1; 
    }
    return ans;
} 

void init(int n){
    A.clear(); S.clear(); I.clear();
    A.n = n+1, A.m = n+1;
    S.n = 1, S.m = n+1,S.a[1][n+1] = 1;
    I.n = n+1, I.m = n+1; 
    for(int i = 1; i<= n+1; i++) A.a[i][i] = 1;
    for(int i = 1; i <= n+1; i++) I.a[i][i] = 1;
}

int main()
{
    LL n, m, k;
    while((~scanf("%lld%lld%lld", &n, &m, &k)) && n){
      init(n);
      LL qi, qj;
      char qus[5];
      for(int i = 1; i <= k; i++){
        scanf("%s", qus);
        if(qus[0] == 'g'){
          scanf("%lld", &qi);
          A.a[n+1][qi]++;
        }
        else if(qus[0] == 'e'){
          scanf("%lld", &qi);
          for(int i = 1; i <= n+1; i++) A.a[i][qi] = 0;
        }
        else{
          scanf("%lld%lld", &qi, &qj);
          for(int i = 1; i <= n+1; i++)
            swap(A.a[i][qi], A.a[i][qj]);
        }
      }
      Matrix ans = S * Fast(m);
      for(int i = 1; i <= n; i++)
        printf("%lld ", ans.a[1][i]);
      printf("\n");
    }
    return 0;
}

注意到m的範圍很大而n的最大取值只有100,所以想到主要的思路:快速冪 S * (A ^ m)
爲了能支持添加操作,故作一個1*(n+1)的矩陣,初始時(1,1)~(1,n) = 0,(1, n+1)=1用於進行加法。
三個操作中比較難想的是刪除操作,其實只需要把矩陣中對應列的所有項清空即可。後續添加操作在第n+1行進行,而做矩陣乘法時,該列與S相乘便不再添加上一步的糖果數。
僅僅這樣會tle
注意到矩陣A有很多的0,要用稀鬆矩陣乘法,即:

Matrix operator * (const Matrix &b) const{
      Matrix tmp;
      tmp.clear();
      for(int i = 1; i <= m; i++)
        for(int k = 1; k <= m; k++)
          if(a[i][k])
            for(int j = 1; j <= m; j++)
              tmp.a[i][j] += a[i][k] * b.a[k][j];   
      tmp.n = n, tmp.m = m;
      return tmp;
    }n tmp;
    }

即對Matrix tmp, a, b
tmp = a * b 只有a[i][j] != 0時把所有tmp中與a[i][j]有關的相加上a與b對應的乘積。

發佈了32 篇原創文章 · 獲贊 1 · 訪問量 3988
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章