zoukankan      html  css  js  c++  java
  • 记codevs第一次月赛

    第一次参加这种有奖励的比赛(没错,我就是为猴子而去的

    一年没怎么碰代码果然手生,还是用没写多久的C++,差点全跪了

    T1数学奇才琪露诺:

    首先定义一个函数F(x),F(x)=x的各个数位上的数字和

    然后在区间[l,r]求F(x)k*p+q=x的所有x,按升序输出

    T1题解:

    枚举x肯定是不行的,F(x)的值只有0到81,我们枚举F(x)的值,然后算出F(x)k*p+q,看数位和是不是符合

    可能会爆int,所以要开long long

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <set>
    using namespace std;
    
    long long k,p,q,l,r,a[10000],tot;
    
    long long s(long long x){
        long long ss=0;
        while(x>0){
            ss+=x%10;
            x=x/10;
        }
        return ss;
    }
    
    long long pow(long long x,long long y){
        long long ipow=1;
        long long i;
        for(i=1;i<=y;++i)ipow=ipow*x;
        return ipow;
    }
    
    int main(){
        scanf("%lld%lld%lld%lld%lld",&k,&p,&q,&l,&r);
        long long i;
        tot=0;
        for(i=0;i<=81;++i){
            long long tmp;
            tmp=pow(i,k)*p+q;
            if((tmp>=0)&&(s(tmp)==i)&&(tmp>=l)&&(tmp<=r))a[++tot]=tmp;
        }
        sort(a+1,a+1+tot);
        printf("%lld
    ",tot);
        for(i=1;i<=tot;++i)printf("%lld ",a[i]);
        return 0;
    }
    T1

    T2完美拓印:

    给你一条轮廓线和一个印章,问有多少种方法可以让印章的一条边缘(上下两边)与轮廓线重合,印章可以180°旋转

    T2题解:

    我们注意到只要相邻两格的高度差一样就行,所以我们把相邻两项的差拿出来做kmp就行了

    注意要做四次kmp,下面平的也要考虑,还有就是特判n=1的情况

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <set>
    using namespace std;
    
    int n,m,a[1000100],b[1000100],nex[1000100],ans;
    
    int work(){
        int i,j;
        for(i=n-1;i>0;--i)a[i]=a[i-1]-a[i];
        nex[1]=0;
        nex[0]=0;
        for(i=2;i<n;++i){
            j=nex[i-1];
            while((j>0)&&(a[i]!=a[j+1]))j=nex[j];
            if(a[i]==a[j+1])nex[i]=j+1;
            else nex[i]=0;
        }
        i=0;j=0;
        while(j<m-1){
            if(a[i+1]==b[j+1])++i,++j;
            else
            if(i==0)++j;
            else i=nex[i];
            if(i==n-1){
                ++ans;
                i=nex[i];
            }
        }
        for(i=1;i<n;++i)a[i]=a[i-1]-a[i];
        return 0;
    }
    
    int swap(int &a,int &b){
        int t;
        t=a;a=b;b=t;
        return 0;
    }
    
    int main(){
        int i;
        ans=0;
        scanf("%d%d",&n,&m);
        for(i=0;i<n;++i)scanf("%d",&a[i]);
        for(i=0;i<m;++i)scanf("%d",&b[i]);
        if(n==1){
            printf("%d
    ",4*m);
            return 0;
        }
        for(i=m-1;i>0;--i)b[i]=b[i-1]-b[i];
        work();
        for(i=0;i<n/2;++i)swap(a[i],a[n-i-1]);
        for(i=0;i<n;++i)a[i]=-a[i];
        work();
        for(i=0;i<n;++i)a[i]=0;
        work();
        work();
        printf("%d
    ",ans);
        return 0;
    }
    T2

    T3幻影阁的难题:

    给你两棵树,你可以分别在两棵树上找一个点,然后在这两个点之间连一条长度为t的边

    1.求连边之后最长路的最小值

    2.求最长路的期望长度

    T3题解:

    首先我们看第一问,我们只要树dp算出从某个点出发的最长链,然后取两棵树的最小值相加再加t,但是我们还要考虑不经过新边的情况,那么就是原来树上的最长链,从这两个中取最大值就行了

    第二问要求期望,所以我们要把所有的情况都算出来,然后总长除以n*m,我们先把两棵树计算好的最长链排好序

    然后我们要计算的就是∑max(最长链,a[i]+b[j]),因为我们排好了序,所以对于每一个i,取最长链的是一段连续的区间,我们只要记一下前缀和就可以快速计算了

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <set>
    using namespace std;
    
    long long n,m,t,tot;
    long long nex[400400],las[400400],l[400400],aa[200200];
    long long s1[200200],s2[200200],fa[200200],fir[200200],q[200200],len[200200];
    bool f[200200];
    long long ss2[200200],g[200200];
    long long ans,ans1,ans2;
    
    int insert(int x,int y,int z){
        ++tot;
        l[tot]=z;
        las[tot]=y;
        nex[tot]=fir[x];
        fir[x]=tot;
    }
    
    int work(){
        int i,x,y,z;
        tot=0;
        for(i=1;i<=n;++i)fir[i]=0,f[i]=false,s1[i]=0,s2[i]=0;
        for(i=1;i<n;++i){
            scanf("%d%d%d",&x,&y,&z);
            insert(x,y,z);
            insert(y,x,z);
        }
        f[1]=true;
        int ll,rr;
        ll=1;rr=1;
        q[1]=1;
        for(;ll<=rr;++ll){
            int j;
            for(j=fir[q[ll]];j!=0;j=nex[j])
            if(!f[las[j]]){
                f[las[j]]=true;
                q[++rr]=las[j];
                len[rr]=l[j];
                fa[rr]=ll;
            }
        }
        len[1]=0;g[0]=0;
        s1[0]=0;s2[0]=0;
        for(i=n;i>1;--i){
            if(s1[i]+len[i]>s1[fa[i]])s2[fa[i]]=s1[fa[i]],s1[fa[i]]=s1[i]+len[i];
            else
            if(s1[i]+len[i]>s2[fa[i]])s2[fa[i]]=s1[i]+len[i];
        }
        long long tmp=2000000000;
        for(i=1;i<=n;++i){
            if(s1[i]+len[i]!=s1[fa[i]])g[i]=s1[fa[i]]+len[i];
            else g[i]=s2[fa[i]]+len[i];
            g[i]=max(g[i],g[fa[i]]+len[i]);
            tmp=min(tmp,max(g[i],s1[i]));
            ans1=max(ans1,g[i]+s1[i]);
        }
        ans2+=tmp;
        return 0;
    }
    
    long long gcd(long long a,long long b){
        if(b==0)return a;
        return gcd(b,a%b);
    }
    
    int main(){
        scanf("%d%d%d",&n,&m,&t);
        ans=0;ans1=0;ans2=0;
        work();
        int i,j;
        for(i=1;i<=n;++i)aa[i]=max(g[i],s1[i]);
        swap(n,m);
        work();
        for(i=1;i<=n;++i)g[i]=max(g[i],s1[i]);
        sort(aa+1,aa+1+m);
        sort(g+1,g+1+n);
        ans1-=t;
        ss2[1]=aa[1];
        for(i=2;i<=m;++i)ss2[i]=ss2[i-1]+aa[i];
        j=m;
        for(i=1;i<=n;++i){
            while((j>0)&&(g[i]+aa[j]>ans1))--j;
            ans+=ans1*j+g[i]*(m-j)+ss2[m]-ss2[j];
        }
        ans+=t*n*m;
        ans2=max(ans2+t,ans1+t);
        printf("%lld
    ",ans2);
        long long tmp;
        tmp=gcd(ans,n*m);
        printf("%lld",ans/tmp);
        printf("/");
        printf("%lld",n*m/tmp);
        return 0;
    }
    T3
  • 相关阅读:
    JS LeetCode 1423. 可获得的最大点数简单题解
    SpringBoot 学集 (第六章) Docker
    Linux 学记 (第三章)
    Linux 学记 (第二章)
    Linux 学记 (第一章)
    SpringBoot 学集 (第五章) Web开发续
    SpringBoot 学集 (第四章)Web开发
    SpringBoot 学集 (第三章) 日志框架
    SpringBoot 学集 (第二章) 配置文件
    SpringBoot 学集 (第一章)
  • 原文地址:https://www.cnblogs.com/Randolph87/p/4678058.html
Copyright © 2011-2022 走看看