记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\n",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\n",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\n",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\n",ans2);

    long long tmp;

    tmp=gcd(ans,n*m);

    printf("%lld",ans/tmp);

    printf("/");

    printf("%lld",n*m/tmp);

    return 0;

}
T3

 

你可能感兴趣的:(code)