记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

 

posted @ 2015-07-26 17:49  Randolph87  阅读(565)  评论(2编辑  收藏  举报