2019河北省赛补题感悟

时间:2021-11-09 03:48:07

对于B题

链接:https://ac.nowcoder.com/acm/contest/903/B
来源:牛客网
看似是一个求一个等比数列的前n项和,似乎利用高中学的知识,a1(1-qn)/1-q在对p取模,可以利用同余定理,求分子的取余在乘以分母的取余,对于分母取余,可以用到乘法逆元,a*

ap-2=1(modp),用该定理需要考虑到gcd(a,p)=1,因为题目中并没有显示的给出两个数互质,所以该方法不行。

接下来就想着用矩阵快速幂来解决它。

先找出对应关系

Sn=qSn-1+q

q=0*Sn-1+q

所以矩阵可表示为

Sn=(q   q)  (Sn-1

q  =(0    q)   (  q   )

进而

 

Sn=(q   q) n-1 (S1

 

q  =(0    q)   (  q   )       然而S1=q

所以就可求解出答案,接下来看代码

#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
ll p;
struct Matrix{
    ll a[10][10];
    int x,y;
    Matrix operator* (Matrix b)
    {
        Matrix ans;
        memset(ans.a,0,sizeof(ans.a));
        ans.x=x;
        ans.y=b.y;
        for(int i=0;i<=ans.x;i++)
            for(int j=0;j<=ans.y;j++)
                for(int k=0;k<=y;k++)
                    ans.a[i][j]=(ans.a[i][j]+a[i][k]*b.a[k][j])%p;
        return ans;
    }
};
Matrix mpow(Matrix a,ll b)
{
    Matrix ans;
    memset(ans.a,0,sizeof(ans.a));
    for(int i=0;i<=a.x;i++)
        ans.a[i][i]=1;
    ans.x=a.x;
    ans.y=a.y;
    while (b)
    {
        if (b&1) ans=ans*a;
        a=a*a;
        b>>=1;
    }
    return ans;
}
int main()
{
    int q,t,n;
    Matrix o;
        o.x=1;
        o.y=1;
    Matrix one;
        one.x=1;
        one.y=0;

    cin>>t;
    while(t--)
    {
        cin>>q>>n>>p;

        o.a[0][0]=q;
        o.a[0][1]=1;
        o.a[1][0]=0;
        o.a[1][1]=1;
        one.a[0][0]=q;
        one.a[1][0]=q;
        Matrix s=mpow(o,n-1)*one;
        cout<<s.a[0][0]<<endl;
    }
    return 0;
}

对于H题:天神的密码

链接:https://ac.nowcoder.com/acm/contest/903/H
来源:牛客网

本来并没有多大难度,但是如果他的K值不在是0-2,而是非常大,又该如何求解呢?

此时我们学要运用到一个求余的法则:

X=Nk

X%9==(X的每一位相加)%9

why?

X%9==(a1*10n-1+a2*10n-2+.......an)%9==(a1*10n-1)%9+(a2*10n-2)%9+.....an%9==(a1%9)*(10n-1)%9.......=(a1+a2+a3+.....an)%9

而X我们可以用快速幂取模算出结果,由结果来反推各项相加的和(和小于10)

因此求余结果为0,则何为9,否则求余多少结果便是多少。

#include<iostream>
using namespace std;
typedef long long ll;
ll n,k;//当k无限次大时
ll qmpow(ll nn,ll x)
{
    ll ans=1;
    while(x)
    {
        if(x&1)
            ans=(ans*nn)%9;
        nn=(nn*nn)%9;
        x>>=1;
    }
    return ans;
}
int main()
{
    ll t,i,j;
    cin>>t;
    while(t--)
    {
        cin>>n>>k;
        if(qmpow(n,k)==0)
            cout<<"9"<<endl;
        else
            cout<<qmpow(n,k)<<endl;
    }
    return 0;
}

 L Smart Robot

链接:https://ac.nowcoder.com/acm/contest/903/L
来源:牛客网
这道题是一道典型的搜索题,难点在于求它最多应该搜多少步结束,先说一下思路,通过一个数组记录它达到该数下标时,令他下标的数字为1,最后通过循环判断不是1的那个数的下标就是最终答案。

博主比较菜,算不出来,随意代了一个5,就过了。

#include<iostream>
#include<cstring>
using namespace std;
int n,a[55][55];
int b[9000000];
int v[55][55];
int x[4]={0,0,1,-1},y[4]={1,-1,0,0};
void dfs(int c,int d,int step,int val)
{
    int xx,yy,i;
   // v[c][d]=1;
    if(step>=5)
        return ;
    for(i=0;i<4;i++)
    {
        xx=c+x[i];
        yy=d+y[i];
        if(xx>=1&&xx<=n&&yy>=1&&yy<=n&&v[xx][yy]==0)
        {
            int p=val*10+a[xx][yy];
            b[p]=1;
            dfs(xx,yy,step+1,p);
        }
    }
    return ;
}
int main()
{
    int i,j,k;
    cin>>n;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            cin>>a[i][j];
            b[a[i][j]]=1;
        }
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
            {
                memset(v,0,sizeof(v));
                dfs(i,j,1,a[i][j]);
            }
    }
    for(i=0;;i++)
    {
        if(b[i]==0)
        {
            cout<<i<<endl;
            break;
        }
    }
    return 0;
}

C 分治

链接:https://ac.nowcoder.com/acm/contest/903/C
来源:牛客网
该题最重要的就是推出: dp[l][r]=min(dp[l][r],cost[i]*(r-l)+dfs(i+1,r)+dfs(l,i-1));

再利用记忆化数组,优化速度。

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;

#define inf 0x3f3f3f3f
int dp[101][101];
int cost[101];
int t,n;
int dfs(int l,int r)
{
    if(l>=r) return 0;
    if(dp[l][r]!=inf) return dp[l][r];
    for(int i=l;i<=r;i++)
        dp[l][r]=min(dp[l][r],cost[i]*(r-l)+dfs(i+1,r)+dfs(l,i-1));
    return dp[l][r];
}
int main()
{
    int i,j,k,ans;
    cin>>t;
    while(t--)
    {
        cin>>n;
        memset(dp,0x3f,sizeof(dp));
        for(i=1;i<=n;i++)
            cin>>cost[i];
        ans=dfs(1,n);
        cout<<ans<<endl;
    }
    return 0;
}