您的位置:首页 > 其它

ZOJ Monthly, July 2012浙大月赛解题报告

2012-07-29 18:59 489 查看

http://acm.zju.edu.cn/onlinejudge/showContestProblems.do?contestId=339

为了做浙大月赛,洗澡都没有去成,哎要等到下个星期三才能洗成吧!比完赛立马写解题报告,可以涨涨访问量把!

A题:

思路:枚举全是2 和 5 为素因子组成的数形如 2^a*5^b,然后判断他们的max(a,b) 是否下于等于 2^a*5^b 用十进制表示的位数即可因为10=2*5

代码:

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

int abs(int a)
{
    return a<0?-a:a;
}
int solve(long long n)
{
    long long ans=0,dd=1;
    int bit=(int)(log10(n*1.0)+1.0000001);
   // cout<<n<<" "<<bit<<endl;

    for(int n1=0;dd<=n&&n1<=bit; dd*=2,n1++)
    {
        long long tmp=1;
        int cnt=0;
        for(int n2=0;tmp*dd<=n&&n2<=bit;n2++,tmp*=5) cnt+=(max(n1,n2)<=(int)(log10(tmp*1.0*dd)+1.0000001));
        //cout<<dd<<" dd "<<cnt<<endl;
        ans+=cnt;
    }
    return ans;
}
int main()
{
    long long n,m;
    while(cin>>m>>n)
    {
        cout<<solve(n)-solve(m-1)<<endl;
    }
    return 0;
}


J题:开始用dp做,发现不是超内存,就是超时间,然后一看才30,果断搜索,稍微剪一下枝就行了

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

int a[30];
int N,M,ans;

void dfs(int id,int sum)
{
    if(ans==M) return;
    if(ans<sum) ans=sum;
    for(int i=id;i<N&&a[i]+sum<=M;i++)
    {
        dfs(i+1,sum+a[i]);
    }
}

int main()
{
    long long tot;
    while(scanf("%d%d",&N,&M)==2)
    {
        tot=0;
        for(int i=0;i<N;i++)
           scanf("%d",a+i),tot+=a[i];
        if(tot<=M)
        {
            printf("%lld\n",tot);
            continue;
        }
        sort(a,a+N);
        ans=0;
        dfs(0,0);
        printf("%d\n",ans);
    }
    return 0;
}


K 题: 算是比较好的题目,分析题意后,仔细想想发现,如果第N天如果买西瓜的话,他只能从N-1天后后如果有西瓜那天开始截断,就是把之后多余的扔掉,开始买该天的习惯,那么果断贪心选择能维持到N-1 天后任意某一天后并且有西瓜的最小花费值,然后更新就行了,然后线段树就可以搞了,或者树状数组

#include <iostream>
#include <cstdio>

using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int maxn=500010;
typedef long long ll;
const ll inf=9999999999999LL;
ll d[maxn*4];

void build(int l,int r,int rt)
{
    d[rt]=inf;
    if(l==r) return;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
void update(int p,ll val,int l,int r,int rt)
{
    if(l==r)
    {
        d[rt]=min(d[rt],val);
        return;
    }
    int m=(l+r)>>1;
    if(p<=m) update(p,val,lson);
    else update(p,val,rson);
    d[rt]=min(d[rt<<1],d[rt<<1|1]);
}
ll query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r) return d[rt];
    int m=(l+r)>>1;
    ll ret1=inf,ret2=inf;
    if(L<=m) ret1=query(L,R,lson);
    if(R>m)  ret2=query(L,R,rson);
    return min(ret1,ret2);
}
int day[maxn],cost[maxn];

int main()
{
    int n;
    while(scanf("%d",&n)==1)
    {
        for(int i=1;i<=n;i++)
          scanf("%d",&cost[i]);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&day[i]);
            if(day[i]>n)  day[i]=n;
        }
        build(1,n,1);
        update(day[1],cost[1],1,n,1);
        for(int i=2;i<=n;i++)
        {
            ll Min=query(i-1,n,1,n,1);
            int pos=i-1+day[i];
            if(pos>n) pos=n;
            //cout<<Min<<endl;
            update(pos,Min+cost[i],1,n,1);
        }
        printf("%lld\n",query(n,n,1,n,1));
    }
    return 0;
}
/*
4
10 20 1 40
3 2 3 1
*/


E题 发现时很简单的树形dp,但是为什么没人做呢,不懂得。dp[node ] [ m ] 表示回到node节点 遍历以node 为根的子树花费时间m的最优值,也就是获得最大财富。背包dp就行了。有于节点数才100,直接用矩阵存图就可了

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn=110;
int n,val[maxn];
int map[maxn][maxn];
int dp[maxn][2*maxn],M;

void dfs(int u,int fa)
{
    dp[u][0]=val[u];
    int tmp[2*maxn]={0};
    for(int v=1;v<=n;v++)
    if(map[u][v]&&v!=fa)
    {
        dfs(v,u);
        //cout<<v<<" "<<map[u][v]<<endl;
        for(int i=0;i<=M;i++)
        for(int j=0;i+j+2*map[u][v]<=M;j++)
          tmp[i+j+2*map[u][v]]=max(tmp[i+j+2*map[u][v]],dp[u][i]+dp[v][j]);
        for(int i=0;i<=M;i++)
          dp[u][i]=max(dp[u][i],tmp[i]),tmp[i]=0;
    }
}
int main()
{
    int a,b,c;
    while(scanf("%d",&n)==1)
    {
        for(int i=1;i<=n;i++)
          scanf("%d",val+i);
        memset(map,0,sizeof(map));
        memset(dp,0,sizeof(dp));
        for(int i=1;i<n;i++)
        {
            scanf("%d %d %d",&a,&b,&c);
            map[a][b]=map[b][a]=c;
        }
        int start;
        scanf("%d%d",&start,&M);
        dfs(start,-1);
        int ans=0;
        for(int i=0;i<=M;i++)
          ans=max(ans,dp[start][i]);
        printf("%d\n",ans);
    }
    return 0;
}


PS:

H 题我找到规律了,但是就是wa,为什么结果用我暴力程序的结果对拍都对呀,不懂得为什么wa,泪……

B题 看到好多人都过了,我就是不知道怎么dp,想用搜索水过过去,但是不是wa就是TLE,泪……明明好多人都过了

B题原来就是01背包就行了,很巧妙的样子,想别人要的代码,谢谢别人的代码

#include<iostream>
#include<stdio.h>
#include<stdio.h>
#include<cstring>
using namespace std;

int ti[40];
int wi[40];
int dp[350];

int N,L;

int ma(int a,int b)
{
    return a > b ? a: b;
}

int main( )
{
    int i,j,max;
    while( scanf("%d%d",&N,&L) != EOF )
    {
        memset(ti,0,sizeof(ti));
        memset(wi,0,sizeof(wi));
        for( i = 0; i < 350; i++ )
            dp[i] = 0;
        for( i = 1; i <= N;  i++ )
            scanf("%d%d",&ti[i],&wi[i]);
        max = 999999999;
        for( i = 1; i <= N; i++ )
        {
            for( j = 1; j <= 330; j++ )
            {
                dp[ti[i]+j] = ma( dp[ti[i]+j],dp[j] + wi[i]*j );
                if( dp[j] >=  L && max > j )
                    max = j;
            }
        }
        cout<<max<<endl;
    }
    //system("pause");
    return 0;
}


Treasure Hunt IV

当时比赛的时候没有做出来,隔几天之后再想想发现是个水题呀!原因就是当时虽然也找到规律了,但是没有想好,就一直在哪儿调试……悲剧

规律我都不说了,很容易找到的

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

typedef long long ll;

ll solve(ll n)
{
    if(n<0) return 0;
    ll ret=(ll)(sqrt(n*1.0)+0.00000001);
    ll ans=0;
    if(ret%2==0) ans+=n-ret*ret+1,ret--;
    ans+=ret*(ret+1)/2;
    return ans;
}
int main()
{
    ll a,b;
    while(scanf("%lld %lld",&a,&b)==2)
    {
        printf("%lld\n", solve(b) - solve(a-1));
        //cout<< solve(b) <<endl;
    }
    return 0;
}


C 题 Count Path pair 组合数学公式就是( C(m + n, n) * C(m + q - p, q) - C(m + q, q) * C(n + m - p, n)) % 100000007 ,然后利用欧拉函数求逆元即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>

using namespace std;
typedef long long ll;
const int mod=100000007;

ll quick_pow(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
int main()
{
    ll n,m,p,q;
    while(scanf("%lld %lld %lld %lld",&m,&n,&p,&q)==4)
    {
       ll ans1=1,ans2=1,ans3=1,ans4=1;
       for(ll i=0;i<n;i++)
        ans1=ans1*(m+n-i)%mod;
       for(ll i=0;i<q;i++)
        ans2=ans2*(m-p+q-i)%mod;
       for(ll i=0;i<m;i++)
        ans3=ans3*(m+q-i)%mod;
       for(ll i=0;i<n;i++)
        ans4=ans4*(m-p+n-i)%mod;

       ll tmp1=1,tmp2=1,tmp3=1;
       for(int i=0;i<n;i++)
         tmp1=tmp1*(n-i)%mod;
       for(int i=0;i<q;i++)
         tmp2=tmp2*(q-i)%mod;
       for(int i=0;i<m;i++)
         tmp3=tmp3*(m-i)%mod;

       ans1=ans1*quick_pow(tmp1,mod-2)%mod;
       ans2=ans2*quick_pow(tmp2,mod-2)%mod;
       ans3=ans3*quick_pow(tmp3,mod-2)%mod;
       ans4=ans4*quick_pow(tmp1,mod-2)%mod;

       ll ans=(ans1*ans2%mod - ans3*ans4%mod)%mod;
       printf("%lld\n",(ans+mod)%mod);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: