ZOJ_3563 Alices Sequence II(矩阵快速幂)

Alice’s Sequence II

Time Limit: 5000 ms
Memory Limit: 65536 KB
Problem Description

Alice loves play with the math, though she always doesn’t know how to solve her own problems.

Alice writes down a sequence(called a) of N integers on the blackboard, indexing from 1 to N, then she wants to do some operations on this sequence. She defines four types of operations.

  1. remove i: a i = 0 a_i=0 ai=0
  2. double i: a i = 2 ∗ a i a_i=2* a_i ai=2ai
  3. add i j: a i = a i + a j a_i= a_i + a_j ai=ai+aj
  4. swap i j: swap the number of a i a_i ai , a j a_j aj
  5. invert i j: invert the sequence from index i i i to index j j j ( i ≤ j ) (i ≤ j) (ij), for example, a = 1 , 2 , 3 , 4 , 5 , 6 a = 1,2,3,4,5,6 a=1,2,3,4,5,6, after operation “invert 1 6”, a will turn into sequence of 6 , 5 , 4 , 3 , 2 , 1 6,5,4,3,2,1 6,5,4,3,2,1
  6. transform c i d j: a i = c ∗ a i + d ∗ a j a_i = c*a_i + d*a_j ai=cai+daj and a j = 0 a_j = 0 aj=0

Alice will give out a operation sequence S with M operations, naming from 1 to M, you need to make P steps on this operation set S. You must make the operation S one by one, and if you reach the Mth operation, you should make the operation on the 1st operation in your next step. For example, if the size of S is 5, and we need to make 8 steps, we make operation S1, S2, …, S5, S1, S2 and S3. Alice wonders what would happen after all of P steps.

For the “double”, “add” and “transform” operations would lead the value of sequence become too large to express, so, you just need to output the sequence by mod 10000007 to each element.

Input

There are multiple cases. In each case, it contains an integer N ( 1 ≤ N ≤ 25 1≤ N ≤25 1N25) in the first line. The following line contains N integers representing the initial value of sequence of a. All of the initial value of sequence of a is a non-negative number and less than 100.

Then it comes an integer M ( 1 ≤ M ≤ 10 1 ≤ M ≤ 10 1M10) in one line, th following M lines contain M operations on each line. The operation is claimed above. The format is “name_of_operation parameters”, name_of_operation can be “remove”, “double”, “add”, “swap”, “invert”, “transform”. And the parameters is a list of parameter which has different length according to the description above. Specially, the integer c and the integer d are non-negative and less than 100.

Finally, the input contains an integer P ( 1 ≤ P ≤ 1 0 9 1≤ P ≤ 10^9 1P109) in one line, which means the total steps you need to make.

Output

For each case, you should output the result of sequence a after P steps.

Sample Input

10
1 2 3 4 5 6 7 8 9 10
6
transform 1 2 3 4
remove 1
swap 2 3
add 2 9
double 9
invert 2 6
8

Sample Output

0 6 5 0 14 12 7 8 18 10

题意

有n个数字的序列,可以执行以下指令:

  1. remove i: a i = 0 a_i=0 ai=0
  2. double i: a i = 2 ∗ a i a_i=2* a_i ai=2ai
  3. add i j: a i = a i + a j a_i= a_i + a_j ai=ai+aj
  4. swap i j: 交换 a i a_i ai , a j a_j aj
  5. invert i j:将 [ i , j ] [i,j] [i,j]的数逆序
  6. transform c i d j: a i = c ∗ a i + d ∗ a j a_i = c*a_i + d*a_j ai=cai+daj and a j = 0 a_j = 0 aj=0

一轮共有m条指令,共需要执行p条,一轮m条指令执行完成后,在从第一条指令开始执行。求最后的序列。

题解:

因为p较大,n较小,且指令都可用矩阵乘法来实现。将一轮的操作,利用矩阵乘法变为一个矩阵,求该矩阵的p/m次幂。再按顺序执行p%m条指令即可。
注意 i = = j i == j i==j的情况,以及最后一个操作,需要最后将 a [ j ] [ j ] a[j][j] a[j][j]赋为0。

#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
 
using namespace std;
typedef long long LL;   
typedef pair<int, int> P;
const int maxn = 12;
const int mod = 10000007;
struct matrix{
    LL a[32][32];
}s, t, p[maxn];
int n;
char str[40];
matrix Mul(matrix a, matrix b);
matrix Pow(matrix a, int b);

int main()
{
    int m, i, j, k, c, d, q;
    while(scanf("%d", &n)!=EOF)
    {
        memset(s.a, 0, sizeof(s.a));
        for(i=1;i<=n;i++)
            scanf("%lld", &s.a[1][i]);
        scanf("%d", &m);
        for(i=0;i<m;i++){
            scanf(" %s", str);
            memset(p[i].a, 0, sizeof(p[i].a));
            for(j=0;j<=n;j++)
                p[i].a[j][j] = 1;
            if(str[0] == 'r'){
                scanf("%d", &j);
                p[i].a[j][j] = 0;
            }else if(str[0] == 'd'){
                scanf("%d", &j);
                p[i].a[j][j] = 2;
            }else if(str[0] == 'a'){
                scanf("%d %d", &j, &k);
                p[i].a[k][j]++;
            }else if(str[0] == 's'){
                scanf("%d %d", &j, &k);
                p[i].a[j][j] = p[i].a[k][k] = 0;
                p[i].a[j][k] = p[i].a[k][j] = 1LL;
            }else if(str[0] == 'i'){
                scanf("%d %d", &j, &k);
                for(int z=j;z<=k;z++)p[i].a[z][z] = 0;
                for(int z1=j,z2=k;z1<=k;z1++,z2--)
                    p[i].a[z2][z1] = 1LL;
            }else if(str[0] == 't'){
                scanf("%d %d %d %d", &c, &j, &d, &k);
                p[i].a[j][j] = c;
                p[i].a[k][j] = d;
                //先执行c*aj+d*ak,在执行ak = 0;
                //当j == k 时,顺序需要注意
                p[i].a[k][k] = 0;
            }
        }
        p[m] = p[0];
        for(i=1;i<m;i++)
            p[m] = Mul(p[m], p[i]);
        scanf("%d", &q);
        t = Pow(p[m], q/m);
        for(i=0;i<q%m;i++)
            t = Mul(t, p[i]);
        s = Mul(s, t);
        for(i=1;i<n;i++)
            printf("%lld ", s.a[1][i]%mod);
        printf("%lld\n", s.a[1][n]%mod);
    }
    return 0;
}

matrix Pow(matrix a, int b)
{
    matrix as;
    memset(as.a, 0, sizeof(as.a));
    for(int i=0;i<=30;i++)
        as.a[i][i] = 1;
    while(b)
    {
        if(b%2)as = Mul(as, a);
        a = Mul(a, a);
        b /= 2;
    }
    return as;
}

matrix Mul(matrix a, matrix b)
{
    matrix c;
    memset(c.a, 0, sizeof(c.a));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            c.a[i][j] = 0;
            for(int k=1;k<=n;k++)
                c.a[i][j] = (c.a[i][j]+(a.a[i][k]*b.a[k][j]%mod))%mod;
        }
    return c;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值