zoukankan      html  css  js  c++  java
  • 7.15 集训总结

    A、数列

    题目描述


    分析

    非常显然的矩阵快速幂
    首先我们要构造如下的两个矩阵
    (left[ egin{matrix} b &c &d &1\1 &0 &0 &0\ 0 &1 &0 &0\0 &0 &0 &1end{matrix} ight])

    (left[ egin{matrix} a_2 &0 &0 &0\a_1 &0 &0 &0\ a_0 &0 &0 &0\e &0 &0 &0end{matrix} ight])

    然后做矩阵乘法就可以了

    要注意的是,矩阵乘法不满足交换律,所以哪一行哪一列相乘一定要搞清

    而且比较恶心的是,由于模数为(10^{18}),所以两个数相乘会爆(long long),因此在做乘法的时候还要用到高精度

    考试的时候写完矩阵快速幂又写了一个暴力的对拍,却一直出错

    后来输出中间变量才发现是暴力溢出了,最后5分钟才交上

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ll;
    const ll mod=1000000000000000000;
    struct jz{
        ll sz[10][10];
        jz(){
            memset(sz,0,sizeof(sz));
        }
    }now,ans;
    ll jla[100],jlb[100],jg[100];
    ll wdcf(ll aa,ll bb){
        memset(jla,0,sizeof(jla));
        memset(jlb,0,sizeof(jlb));
        ll cnta=0,cntb=0;
        while(aa){
            jla[++cnta]=aa%10;
            aa/=10;
        }
        while(bb){
            jlb[++cntb]=bb%10;
            bb/=10;
        }
        memset(jg,0,sizeof(jg));
        for(ll i=1;i<=cnta;i++){
            for(ll j=1;j<=cntb;j++){
                jg[i+j-1]+=jla[i]*jlb[j];
            }
        }
        ll mans=0,jl=1;
        for(ll i=1;i<=19;i++){
            if(jg[i]>=10){
                ll zj=jg[i]/10;
                jg[i+1]+=zj;
                jg[i]%=10;
            }
            mans+=jg[i]*jl;
            jl*=10;
        }
        return mans;
    }
    jz cf(jz aa,jz bb){
        jz cc;
        memset(cc.sz,0,sizeof(cc.sz));
        for(int i=1;i<=4;i++){
            for(int j=1;j<=4;j++){
                for(int k=1;k<=4;k++){
                    cc.sz[i][j]=(cc.sz[i][j]%mod+wdcf(aa.sz[i][k],bb.sz[k][j])%mod)%mod;
                }
            }
        }
        return cc;
    }
    int num[50],cnt=0;
    int main(){
        ll a0,a1,a2,b,c,d,e,n;
        scanf("%llu%llu%llu%llu%llu%llu%llu%llu",&a0,&a1,&a2,&b,&c,&d,&e,&n);
        ans.sz[1][1]=a2%mod;
        ans.sz[2][1]=a1%mod;
        ans.sz[3][1]=a0%mod;
        ans.sz[4][1]=e%mod;
        now.sz[1][1]=b%mod;
        now.sz[1][2]=c%mod;
        now.sz[1][3]=d%mod;
        now.sz[1][4]=1;
        now.sz[2][1]=1;
        now.sz[3][2]=1;
        now.sz[4][4]=1;
        ll jg;
        if(n==0) jg=a0;
        else if(n==1) jg=a1;
        else if(n==2) jg=a2;
        else {
            ll zs=n-2;
            while(zs){
                if(zs&1) ans=cf(now,ans);
                now=cf(now,now);
                zs>>=1;
            }
            jg=ans.sz[1][1]%mod;
        }
        while(jg){
            num[++cnt]=jg%10;
            jg/=10;
        }
        int dy=18-cnt;
        for(int i=1;i<=dy;i++){
            printf("0");
        }
        printf("%llu
    ",ans.sz[1][1]%mod);
        return 0;
    }
    
    

    B、旗木双翼

    题目描述




    分析

    很有思维含量的一道题
    我们可以把题意转换成一个人从坐标为((n,m))的开始走,走到坐标为((0,0))的点
    而且只能向上向右走的方案数
    看下面的图可能会更好理解一些

    因此最终的结果就是(C_{n+m}^{n})
    因为结果要取模,而且涉及到除法运算,因此要求逆元

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const int maxn=200005;
    ll ny[maxn];
    int main(){
        ll n,m;
        scanf("%lld%lld",&n,&m);
        ny[1]=1;
        for(ll i=2;i<=n+m;i++){
            ny[i]=(mod-mod/i)*ny[mod%i]%mod;
        }
        ll ans=1;
        for(ll i=1;i<=n+m;i++){
            ans=ans*i%mod;
        }
        for(ll i=1;i<=n;i++){
            ans=ans*ny[i]%mod;
        }
        for(ll i=1;i<=m;i++){
            ans=ans*ny[i]%mod;
        }
        printf("%lld
    ",ans%mod);
        return 0;
    }
    

    C、乌龟棋

    题目描述




    分析

    我们设(f[a][b][c][d])为使用了(a)张标有数字(1)的卡片,(b)张标有数字(2)的卡片,(c)张标有数字(3)的卡片,(d)张标有数字(4)的卡片所能得到的最大得分
    状态转移方程就很显然了

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 45;
    int f[maxn][maxn][maxn][maxn];
    const int N = 400;
    int nn[N],mm[N];
    int n,m;
    int sum[maxn];
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i){
    		scanf("%d",&nn[i]);
    	}
    	for(int i=1;i<=m;++i){
    		scanf("%d",&mm[i]);
    		sum[mm[i]]++;
    	}
    	for(int a=0;a<=sum[1];++a){
    		for(int b=0;b<=sum[2];++b){
    			for(int c=0;c<=sum[3];++c){
    				for(int d=0;d<=sum[4];++d){
    					int jl1=0,jl2=0,jl3=0,jl4=0;
    					if(a)jl1=f[a-1][b][c][d];
    					if(b)jl2=f[a][b-1][c][d];
    					if(c)jl3=f[a][b][c-1][d];
    					if(d)jl4=f[a][b][c][d-1];
    					f[a][b][c][d]=max(max(jl1,jl2),max(jl3,jl4))+nn[a+2*b+3*c+4*d+1];
    				}
    			}
    		}
    	}
    	printf("%d
    ",f[sum[1]][sum[2]][sum[3]][sum[4]]);
    	return 0;	
    }
    

    D、假面舞会

    题目描述



    分析

    传送门

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+5;
    int head[maxn],tot=2;
    struct asd{
    	int from,to,next,val;
    }b[maxn];
    void ad(int aa,int bb,int cc){
        b[tot].from=aa;
        b[tot].to=bb;
        b[tot].next=head[aa];
        b[tot].val=cc;
        head[aa]=tot++;
    }
    bool vis[maxn];
    int dis[maxn],ans;
    void DFS(int now){
        vis[now]=1;
        for (int i=head[now];i!=-1;i=b[i].next){
    		int u=b[i].to;
    		if(!vis[u]){
    			dis[u]=dis[now]+b[i].val;
    			DFS(u);
    		} else {
                if(ans==0) ans=abs(dis[now]+b[i].val-dis[u]);
    			else ans=__gcd(ans,abs(dis[now]+b[i].val-dis[u]));
    		}
    	}
    }
    int mmin,mmax;
    int jud[maxn];
    void dfs(int now){
        mmax=max(mmax,dis[now]);
        mmin=min(mmin,dis[now]);
        vis[now]=1;
        for(int i=head[now];i!=-1;i=b[i].next){
            if(!jud[i]){
                jud[i]=jud[i^1]=1;
                int u=b[i].to;
                dis[u]=dis[now]+b[i].val;
                dfs(u);
            }
        }
    }
    int main(){
        memset(head,-1,sizeof(head));
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            int aa,bb;
            scanf("%d%d",&aa,&bb);
            ad(aa,bb,1);
            ad(bb,aa,-1);
        }
        for(int i=1;i<=n;i++){
            if(!vis[i]) DFS(i);
        }
        if(ans){
            if(ans<3) printf("-1 -1
    ");
            else {
                int now;
                for(int i=3;i<=ans;i++){
                    if(ans%i==0) {
                        now=i;
                        break;
                    }
                }
                printf("%d %d
    ",ans,now);
            }
            return 0;
        }
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++){
            if(!vis[i]){
                mmin=mmax=dis[i]=0;
                dfs(i);
                ans+=mmax-mmin+1;
            }
        }
    	if(ans>=3) printf("%d 3
    ",ans);
    	else printf("-1 -1
    ");
        return 0;
    }
    
  • 相关阅读:
    element ui 表单清空
    element ui 覆盖样式 方法
    element ui 修改表单值 提交无效
    element ui 抽屉里的表单输入框无法修改值
    element ui 抽屉首次显示 闪烁
    css 左侧高度 跟随右侧内容高度 自适应
    PICNUF框架
    elementui 抽屉组件标题 出现黑色边框
    vue 子组件跨多层调用父组件中方法
    vue 编辑table 数据 未点击提交,table里的数据就发生了改变(深拷贝处理)
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/13307833.html
Copyright © 2011-2022 走看看