zoukankan      html  css  js  c++  java
  • 2019河北省赛补题感悟

    对于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;
    }
  • 相关阅读:
    dapperHelper
    .NET Core Session的使用方法
    Wpf 关闭当前窗体 打开新窗体
    C#中Split分隔字符串的应用(C#、split、分隔、字符串)
    wpf日期控件
    SQLite数据库数据类型详解
    Asp.Net Core 2.2
    手写图片懒加载
    css动画常用属性总结
    css购物车(抛物线)运动
  • 原文地址:https://www.cnblogs.com/xiaofengzai/p/11175515.html
Copyright © 2011-2022 走看看