2013 Multi-University Training Contest 9(hdu 4686 - 4691)dp(好)+矩阵快速幂+一般图匹配带花树+后缀数组

A - 1001

Description

An Arc of Dream is a curve defined by following function:

AoD(n)=n1i=0aibi

where
a0=A0
ai=ai1AX+AY
b0=B0
bi=bi1BX+BY
What is the value of AoD(N) modulo 1,000,000,007?

Input
There are multiple test cases. Process to the End of File.
Each test case contains 7 nonnegative integers as follows:
N
A0 AX AY
B0 BX BY
N is no more than 10 18, and all the other integers are no more than 2×10 9.

Output
For each test case, output AoD(N) modulo 1,000,000,007.

Sample Input

1
1 2 3
4 5 6
2
1 2 3
4 5 6
3
1 2 3
4 5 6

Sample Output

4
134
1902
构造矩阵,其实就是由 aibi=(ai1AX+AY)(bi1BX+BY) 推出来的
|aibi| |AXBXAXBYAYBXAYBY00|
|ai| = |0AX0AY00|
|bi| |00BXBY00|
|1| |000100|
|S| |AXBXAXBYAYBXAYBY11|

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MOD=1e9+7;
LL N;
LL A0,AX,AY,B0,BX,BY;
struct Matrix{
    LL mat[10][10];
    int n;
    Matrix (int _n=5){
        n=_n;
        memset(mat,0,sizeof(mat));
    }
    Matrix operator*(const Matrix &a)const{
        Matrix res;
        for(int k=0;k<n;k++){
            for(int i=0;i<n;i++){
                if(mat[i][k]==0)continue;
                for(int j=0;j<n;j++){
                    if(a.mat[k][j]==0)continue;
                    res.mat[i][j]=(res.mat[i][j]+mat[i][k]*a.mat[k][j]%MOD);
                    if(res.mat[i][j]>=MOD)res.mat[i][j]-=MOD;
                }
            }
        }
        return res;
    }
};
Matrix pow_mul(Matrix A,LL n){
    Matrix res;
    for(int i=0;i<res.n;i++)res.mat[i][i]=1;
    while(n){
        if(n&1)res=res*A;
        A=A*A;
        n>>=1;
    }
    return res;
}
int main(){

    while(scanf("%I64d",&N)!=EOF){
        scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&A0,&AX,&AY,&B0,&BX,&BY);
        Matrix A,B;
        if(N==0){
            printf("0\n");
            continue;
        }
        A0%=MOD,B0%=MOD,AX%=MOD,AY%=MOD,BX%=MOD,BY%=MOD;
        A.mat[0][0]=A.mat[4][0]=AX*BX%MOD;
        A.mat[0][1]=A.mat[4][1]=AX*BY%MOD;
        A.mat[0][2]=A.mat[4][2]=AY*BX%MOD;
        A.mat[0][3]=A.mat[4][3]=AY*BY%MOD;A.mat[4][4]=1;
        A.mat[1][1]=AX;A.mat[1][3]=AY;
        A.mat[2][2]=BX,A.mat[2][3]=BY;
        A.mat[3][3]=1;
        B.mat[0][0]=B.mat[4][0]=A0*B0%MOD,B.mat[1][0]=A0,B.mat[2][0]=B0;
        B.mat[3][0]=1;
        A=pow_mul(A,N-1);
        A=A*B;
        printf("%I64d\n",A.mat[4][0]);
    }
    return 0;
}

B题是一般图匹配,见前面的博客:
hdu - 4687

D - 1004

Description

A derangement is a permutation such that none of the elements appear in their original position. For example, [5, 4, 1, 2, 3] is a derangement of [1, 2, 3, 4, 5]. Subtracting the original permutation from the derangement, we get the derangement difference [4, 2, -2, -2, -2], where none of its elements is zero. Taking the signs of these differences, we get the derangement sign [+, +, -, -, -]. Now given a derangement sign, how many derangements are there satisfying the given derangement sign?

Input

There are multiple test cases. Process to the End of File.
Each test case is a line of derangements sign whose length is between 1 and 20, inclusively.

Output

For each test case, output the number of derangements.

Sample Input

+-
++—

Sample Output

1
13
递推,令dp[i][j]表示错位排列的前i个数中有j个对应+的位置尚未填写。这里的j还有令一层意思,即0~i-1中也恰好有j个数未出现在已知的部分错位排列中。原因是如果某个位置填写了数,那么必须是0~i-1其中之一,而有j个位置尚未填写,故0~i-1中有j个未出现。

假如已经考虑了前i位,考虑a[i]:

+:这个位置的数也无法确定,算作“未填写”,而之前j个未填的地方可以挑一个填i,对应:dp[i+1][j] += dp[i][j] * j;
也可以不用i,对应:dp[i+1][j+1] += dp[i][j]
-:这个位置的数必须确定,由于0~i-1中恰有j个数未被填写,所以位置i可以填上这j个数中的任何一个。
另外之前j个未确定的位置可以填i(对应:dp[i+1][j-1] += dp[i][j] * j * j);
也可以不用i(对应:dp[i+1][j] += dp[i][j] * j)
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=50;
typedef long long LL;
LL dp[maxn][maxn];
int N;
char s[maxn];
LL DP(int i,int j){
    if(dp[i][j]!=-1)return dp[i][j];
    if(i==N){
        dp[i][j]=(j==0);
        return dp[i][j];
    }
    LL ans=0;
    if(s[i]=='+'){
        ans+=j*DP(i+1,j);
        ans+=DP(i+1,j+1);
    } else {
        ans+=j*j*DP(i+1,j-1);
        ans+=j*DP(i+1,j);
    }
    return dp[i][j]=ans;
}
int main(){
    while(scanf("%s",s)!=EOF){
        N=strlen(s);
        memset(dp,-1,sizeof(dp));
        printf("%I64d\n",DP(0,0));
    }
    return 0;
}

F后缀数组的简单应用,见以前的博客:
hdu 4691

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值