HDU 2276 & FZU 1692 (矩阵快速幂+循环同构优化)

HDU 2276

题意:

给定一个01**字符串环**(2<=字符串长度<=100)然后进行m次的变换。
定义变换的规则为:如果当前位置i的左边是1(下标为0的左边是n-1),那么i就要改变状态0->1 , 1->0
比如当前的状态为100101那么一秒过后的状态为010111。

思路:

用公式表示变化状态其实就是:
ai=(a(i+n1)%n+ai)%2
换成位操作就是:
ai=a(i+n1)%n ^ ai

于是我们可以建立一个变化矩阵:

1100...00110...00011...00001...0..................0000...11000...1a0a1a2a3...an1

左边是变换矩阵,右边是原序列,相乘一次后输出结果即是变换一次后序列。
然后快速幂就搞定啦~
ps.把矩阵乘法里的*改&,+改^可以快很多
pps.由于变换矩阵是循环同构的,可以求出第一行推出其他行,能从 O(n3) 降至 O(n2) ,然而这题 O(n3) 也就这么水过去了,但下一题就没那么好运了..

代码君:

/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

const int maxn = 105;
const int mod = 2;
lint n;

struct Matrix{
    int n,m;
    int a[maxn][maxn];
    Matrix(int n , int m){
        this->n = n;
        this->m = m;
        cls(a);
    }
    Matrix operator * (const Matrix &tmp){
        Matrix res(n,tmp.m);
        for(int i = 0 ; i < n ; i++)
            for(int j = 0 ; j < tmp.m ; j++)
                for(int k = 0 ; k < m ; k++)
                    res.a[i][j] = res.a[i][j] ^ (a[i][k] & tmp.a[k][j]);
        return res;
    }
};

void Matrix_print(Matrix x){
    for(int i = 0 ; i < x.n ; i++){
        for(int j = 0 ; j < x.m ; j++) cout << x.a[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
}

Matrix fast_pow(Matrix x , lint n){
    Matrix res(x.n , x.m);
    for(int i = 0 ;  i < x.n ; i++) res.a[i][i] = 1;
    while(n){
        if(n&1)
            res = res*x;
        x = x*x;
        n >>= 1;
    }
    return res;
}

void solve(string s , lint n){
    int l = s.length();
    Matrix fun(l,l);
    Matrix base(l,1);
    for(int i = 0 ; i < l - 1; i++) fun.a[i][i] = fun.a[i][i+1] = 1;
    fun.a[l-1][0] = fun.a[l-1][l-1] = 1;
    //Matrix_print(fun);
    for(int i = 0 ; i < l; i++) base.a[i][0] = s[i] - '0';

    fun = fast_pow(fun , n);
    base = fun*base;

    for(int i = 0 ; i < l ; i++) cout << base.a[(i - n%l + l)%l][0];
    puts("");
}
int main(){
  //freopen("input.txt","r",stdin);
    string s;
    lint n ;
    while(cin >> n >> s){
        solve(s,n);
    }
    return 0;
}

FZU 1692

题意:

类似上一题,
n个小朋友围成一个(2<=n<=100)然后进行m次的游戏。
一开始,第i个小朋友有 Ai 个苹果。
定义游戏的规则为:每一次游戏处于i位置的小朋友获得 RA(i+n1)%n+LA(i+1)%n 个苹果(题目有误。。大坑啊!!)
求m次游戏后每个小朋友的苹果数量。

思路:

凑样例愣是凑了半小时不明所以然,所幸搜了题解后被告知题目有误。
变化矩阵如下:

1R00...LL1R0...00L1R...000L1...0..................0000...RR000...1A0A1A2A3...An1

这题的trick点其实还是循环同构矩阵的乘法优化,通过求出第一行矩阵得到其他行,不这么做必吃TLE,谨记谨记。

代码君:

/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

const int maxn = 100 + 5;
lint n1 , m1 , L , R , M;
lint A[maxn];

struct Matrix{
    int n , m ;
    lint a[maxn][maxn];
    Matrix( int n , int m ){
        this->n = n ; 
        this->m = m ;
        cls(a);
    }
    Matrix operator * ( const Matrix &tmp ){
        Matrix res( n , tmp.m );
        for( int i = 0 ; i < tmp.m ; i++ )
            for( int j = 0 ; j < m ; j++ )
                res.a[0][i] = ( res.a[0][i] + ( a[0][j] * tmp.a[j][i] ) % M ) % M;
        for( int i = 1 ; i < n ; i++ )
            for( int  j = 0  ; j < m ; j++ )
                res.a[i][j] = res.a[i - 1][( j - 1 + n ) % n];
        return res;
    }
};

void Matrix_input( Matrix x ){
    for( int i = 0 ; i < x.n ; i++ ){
        for( int j = 0 ; j < x.m ; j++ ){
            cout << x.a[i][j] << ' ';
        }
        puts("");
    }
    puts("");
}
Matrix fast_pow( Matrix x , lint n ){
    Matrix res( x.n , x.m );
    for( int i = 0 ; i < x.n ; i++ ) res.a[i][i] = 1;
    while( n ){
        if( n & 1 )
            res = res * x;
        x = x * x ; 
        n >>= 1;
    }
    return res;
}

void input(){
    cin >> n1 >> m1 >> L >> R >> M;
    for( int i = 0 ; i < n1 ; i++ ){
        scanf( "%I64d" , &A[i] );
    }
}
void solve(){
    if( m1 == 0 ) {
        for( int i = 0 ; i < n1 ; i++ ){
            if( i ) printf( " " );
            printf( "%I64d" , A[i] % M);
        }
        puts("");
        return;
    }
    Matrix fun( n1 , n1 );
    for( int i = 0 ; i < n1 ; i++ ){
        fun.a[i][( i + 1 ) % n1] = L;
        fun.a[i][( i - 1 + n1 ) % n1] = R;
        fun.a[i][i] = 1;
    }
    //Matrix_input( fun );
    fun = fast_pow( fun , m1 );
    //Matrix_input( fun );
    for( int i = 0 ; i < n1 ; i++ ){
        lint sum = 0 ;
        for( int j = 0 ; j < n1 ; j++ )
            sum = ( sum + fun.a[i][j] * A[j] % M ) % M;
        if( i ) printf( " " );
        printf( "%I64d" , sum );
    }
    puts("");
}
int main(){
  //freopen("input.txt","r",stdin);
    int t ; cin >> t;
    while( t-- ){
        input();
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值