2019 牛客多校 第五场

A:

  题意:签到

B:

  题意:给出fn的递推关系式和n,求fn。n的范围10^(10^6)

  题解:转化成矩阵连乘,这个数据量10进制优化可以过。 

#include <bits/stdc++.h>
using namespace std; 
typedef long long ll;

const int MAXN=2e6+5;

ll f0, f1, a, b, mod;
char s[MAXN]; 

struct Matrix{
    ll m[2][2]; 
};

Matrix Mul(Matrix a, Matrix b)
{
    Matrix ans; 
    ans.m[0][0]=0; ans.m[0][1]=0; 
    ans.m[1][0]=0; ans.m[1][1]=0;
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            for(int k=0; k<2; k++)
                ans.m[i][j]=(ans.m[i][j]+a.m[i][k]*b.m[k][j])%mod; 
    return ans;
}

Matrix qpow(Matrix a, ll n)
{
    Matrix ans; 
    ans.m[0][0]=1; ans.m[0][1]=0; 
    ans.m[1][0]=0; ans.m[1][1]=1; 
    while(n)
    {
        if(n&1)
            ans=Mul(ans, a);
        a=Mul(a, a); 
        n>>=1;
    }
    return ans;
}

int main()
{
    cin>>f0>>f1>>a>>b; 
    cin>>s>>mod; 
    int len=strlen(s);
    Matrix ans, coe;
    ans.m[0][0]=1; ans.m[0][1]=0; 
    ans.m[1][0]=0; ans.m[1][1]=1; 
    coe.m[0][0]=a; coe.m[0][1]=b; 
    coe.m[1][0]=1; coe.m[1][1]=0; 
    for(int i=len-1; i>=0;  i--)
    {
        ans=Mul(ans, qpow(coe, s[i]-'0'));
        coe=qpow(coe, 10);
    }
    ll res=(ans.m[1][0]*f1+ans.m[1][1]*f0)%mod;
    cout<<res<<endl;
    return 0;
}
View Code

G:

  题意:给一个字符串t,一个字符串s,找出s中有多少个子序列大于字符串t

  题解:划分情况,当字串长度大于t的长度时:组合数学直接求。当长度相等时:dp【i】【j】表示s中长度为i的后缀中长度为j的子序列大于t中长度为j的后缀。

     此时,分s【n+1-i】和t【m+1-j】的大小关系进行讨论。注意当j的1的时候特别判定。   

     具体可参考:https://blog.csdn.net/qq_43857314/article/details/98212272

#include <bits/stdc++.h>
using namespace std; 
typedef long long ll;

const int MAXN=3e3+5; 
const ll mod=998244353;

ll dp[MAXN][MAXN], com[MAXN][MAXN]; 
char s[MAXN], t[MAXN];
int n, m;

void make_com()
{
    for(int i=0; i<MAXN; i++)
        com[i][i]=1, com[i][0]=1;
    for(int i=1; i<MAXN; i++)
        for(int j=1; j<MAXN; j++)
            com[i][j]=(com[i-1][j]+com[i-1][j-1])%mod;
}

int main()
{    
    make_com();
    int T;
    for(cin>>T; T--; )
    {
        cin>>n>>m;
        cin>>s+1>>t+1;
                
        //子序列的长度大于m时 
        ll ans1=0;
        for(int i=1; i<=n-m; i++)  //起点
        {
            if(s[i]=='0') continue;
            for(int j=m; j<=n-i; j++)
                ans1=(ans1+com[n-i][j])%mod;    
        }
        
        //长度相等的时候
        for(int i=0; i<=n; i++)
            for(int j=0; j<=m; j++)
                dp[i][j]=0;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=i; j++)
            {
                if(s[i]=='0') dp[i][j]=dp[i-1][j-1];
                if(j==1)
                {
                    if(s[n+1-i]>t[m+1-j]) dp[i][j]=(dp[i-1][j]+com[i-1][j-1])%mod;
                    else dp[i][j]=dp[i-1][j];
                }
                else if(s[n+1-i]>t[m+1-j]) dp[i][j]=(dp[i-1][j]+com[i-1][j-1])%mod;
                else if(s[n+1-i]==t[m+1-j]) dp[i][j]=(dp[i-1][j]+dp[i-1][j-1])%mod;
                else dp[i][j]=dp[i-1][j];
            } 
        cout<<(ans1+dp[n][m])%mod<<endl;
    }
    return 0;
} 
View Code

      

猜你喜欢

转载自www.cnblogs.com/Yokel062/p/11296185.html