2014 Multi-University Training Contest 7 题解

来源:互联网 发布:软件开发专业就业方向 编辑:程序博客网 时间:2024/06/05 22:43

<a target=_blank href="http://acm.hdu.edu.cn/showproblem.php?pid=4939"></a>
http://acm.hdu.edu.cn/showproblem.php?pid=4939

HDU 4939题解

题意:

1.红塔,每单位时间造成x的伤害

2.绿塔,在经过之后每单位时间造成y的伤害

3.蓝塔,在经过之后每走一单位距离需要多花z的时间

题解:

显然,红塔肯定放在最后面。绿塔和蓝塔就进行DP求解。dp[i][j]表示前i个塔有j个塔是绿塔时,造成的最大伤害。同时以剩下的n-i个全为红塔,来求出最大伤害ans。


#include<stdio.h>http://blog.csdn.net/lyhvoyage/article/details/38533545#include<string.h>#include<math.h>#include<algorithm>#define LL long long int#define MAX 1600using namespace std;LL dp[3][MAX];int main(){    LL T,n,x,y,z,t;    LL ans=0,best;    while(~scanf("%I64d",&T)){        for(int cas=1;cas<=T;cas++){            scanf("%I64d %I64d %I64d %I64d %I64d",&n,&x,&y,&z,&t);            ans=n*t*x;            memset(dp,0,sizeof(dp));            for(int i=1;i<=n;i++){                int cur=i%2;                int pas=(i+1)%2;                dp[cur][0]=0;                best=(i*z+t)*x*(n-i);//注意这个地方也需要处理,开始我就搞忘了                 if(best>ans) ans=best;                for(int j=1;j<=i;j++){//表示持续伤害的塔的个数                     if(j==i) {//i==j时要特殊处理,dp[i-1][i]这种状况不存在。只能是从dp[i-1][i-1]到dp[i][i]                         dp[cur][j]=(dp[pas][j-1]+((i-j)*z+t)*(j-1)*y);                    }else {                        dp[cur][j]=max((dp[pas][j]+((i-j-1)*z+t)*(j*y)),(dp[pas][j-1]+((i-j)*z+t)*(j-1)*y));                     }                    best=dp[cur][j]+(n-i)*(x+j*y)*((i-j)*z+t);                    if(best>ans) ans=best;                }                }            printf("Case #%d: %I64d\n",cas,ans);        }    }    return 0;}

计算机在做四则运算的时候,括号,加减乘除法的优先顺序也和笔算的优先级是一样的?(忘大牛指点)

开始n,x,y,z,t是int型的,在计算的过程中爆int了,我就进行了一下强转。

在什么地方开始转的呢?

按照四则运算的优先级的顺序算的时候,什么地方可能开始爆int,就把它转成Long Long int,

在后面计算的过程中,编译器会自动把int转化为long long int进行运算。

最后AC掉了


计算机进行四则运算的优先级和人是一样的。要是强转的话,就转优先级最高处就好啦?

#include<stdio.h>#include<string.h>#include<math.h>#include<algorithm>#define LL long long int#define MAX 1600using namespace std;LL dp[3][MAX];int main(){    int T,n,x,y,z,t;    LL ans=0,best;    while(~scanf("%d",&T)){        for(int cas=1;cas<=T;cas++){            scanf("%d %d %d %d %d",&n,&x,&y,&z,&t);            ans=(LL)n*t*x;            memset(dp,0,sizeof(dp));            for(int i=0;i<MAX;i++){                dp[0][i]=0;                dp[1][i]=0;            }            for(int i=1;i<=n;i++){                int cur=i%2;                int pas=(i+1)%2;                dp[cur][0]=0;                best=(i*z+t)*(LL)x*(n-i);                if(best>ans) ans=best;                for(int j=1;j<=i;j++){//表示持续伤害的塔的个数                     if(j==i) {                        dp[cur][j]=(dp[pas][j-1]+((i-j)*(LL)z+t)*(j-1)*y);                    }else {                        dp[cur][j]=max((dp[pas][j]+((i-j-1)*(LL)z+t)*(j*y)),(dp[pas][j-1]+((i-j)*(LL)z+t)*(j-1)*y));                     }                    best=dp[cur][j]+(n-i)*((LL)x+j*y)*((i-j)*z+t);                    if(best>ans) ans=best;                }                }            printf("Case #%d: %I64d\n",cas,ans);        }    }    return 0;}

http://acm.hdu.edu.cn/showproblem.php?pid=4941

HDU 4941 Magical Forest

题意:

N*M的矩阵,有K(10^5)个位置上有水果,交换行或者列T(10^5)次。

比赛的时候,我们用的STL的map和vector一起做的。

map的key代表的是横坐标或者纵坐标,value表示的是vector的下标。这样vecor实际占的内存不会超过10^5的int。

在交换两行或者两列的时候,会修改vector[i].szie()的时间复杂度。

感觉这个做法的时间复杂度在n(10^5)-n^2之间,着看他的数据的坑爹程度了,正常的复杂度应该在10^5-10^6之间吧。

http://blog.csdn.net/lyhvoyage/article/details/38533545  可参考

#include<stdio.h>#include<map>#include<iostream>#include<vector>#define MAX 100009using namespace std;struct node {int x;int y;int w; }a[MAX];map <int ,int>map1;map <int ,int>map2;map<int, int>::iterator  iter,iter1,iter2;vector <int> vector1[MAX];vector <int> vector2[MAX];int main(){int T,N,M,K,Q;while(~scanf("%d",&T)){for(int t=1;t<=T;t++){map1.clear();map2.clear();for(int i=0;i<MAX;i++)vector1[i].clear();for(int i=0;i<MAX;i++)vector2[i].clear();printf("Case #%d:\n",t);scanf("%d %d %d",&N,&M,&K);for(int i=0;i<K;i++){scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].w);if(map1.find(a[i].x)==map1.end()){map1[a[i].x]=i;vector1[i].push_back(i);}else{iter=map1.find(a[i].x);int tmp=iter->second;vector1[tmp].push_back(i);}if(map2.find(a[i].y)==map2.end()){map2[a[i].y]=i;vector2[i].push_back(i);}else{iter=map2.find(a[i].y);int tmp=iter->second;vector2[tmp].push_back(i);}}scanf("%d",&Q);int x1,x2,flag;for(int i=0;i<Q;i++){scanf("%d %d %d",&flag,&x1,&x2);if(flag==1){if(map1.find(x1)==map1.end()) continue;iter1=map1.find(x1);iter2=map1.find(x2);int tmp1=iter1->second;int tmp2=iter2->second;int cc1=vector1[tmp1].size();int cc2=vector1[tmp2].size();for(int j=0;j<cc1;j++){a[vector1[tmp1][j]].x=x2;}for(int j=0;j<cc2;j++){a[vector1[tmp2][j]].x=x1;}vector1[tmp1].swap(vector1[tmp2]);}if(flag==2){if(map2.find(x1)==map2.end())continue;iter1=map2.find(x1);iter2=map2.find(x2);int tmp1=iter1->second;int tmp2=iter2->second;int cc1=vector2[tmp1].size();int cc2=vector2[tmp2].size();for(int j=0;j<cc1;j++){a[vector2[tmp1][j]].y=x2;}for(int j=0;j<cc2;j++){a[vector2[tmp2][j]].y=x1;}vector2[tmp1].swap(vector2[tmp2]);}if(flag==3){bool ok=false;iter=map1.find(x1);int tmp=iter->second;int siz=vector1[tmp].size();for(int j=0;j<siz;j++){int cc=vector1[tmp][j];if(a[cc].y==x2) {ok=true;printf("%d\n",a[vector1[tmp][j]].w);break;}}if(ok==false) printf("0\n");}}}}return 0;}/*4 4 161 1 11 2 21 3 31 4 42 1 52 2 62 3 72 4 83 1 93 2 103 3 113 4 124 1 134 2 144 3 154 4 1661 1 22 1 23 2 23 3 23 3 51 1 11 3 22 1 32 2 43 3 55*/

HDU 4937 Lucky Number 题解

题意:

Love_Kid将3,4,5,6认为是幸运数字。给定一个十进制数n。现在可以讲起任意转换成其他进制,但转换后的数必须是由3,4,5,6构成的,而这个进制称为幸运进制。问有多少个幸运进制。若有无数个,则输出-1。例如19在5进制下是34,所以5是幸运进制。

题解:

1.对于只有一位数的情况,显然3、4、5、6都应该输出-1.
2.如果有2位数,假设这2位中高位为a,低位为b,进制为base,则 n = a * base + b,解一元一次方程即可。
3. 如果有3位数,假设这3为从高到低分别为a、b、c,进制为base,则 n = a * base * base + b * base + c,即一元二次方程即可。
4.如果位数>= 4,可以暴力枚举进制数。base>min(3,4,5,6),所以从base=4开始枚举。又因为 x1 + x2 * base + x3 * base * base + x4 * base *base *base + ……>= 3*7000+3 *7000 ^2 +3 * 7000 ^3 = 1.029e12 > max(n).
所以枚举4到7000就可以了。(i*i*i<n)
总结:本题的数据的大小在200组左右,每个数据的<10^12,把只有1,2,3位的书特殊处理后,其他的暴力枚举时间复杂度刚好可以控制在100*10000之内。

本题转化成一元二次方程来解题也是很妙的想法。

#include<stdio.h>#include<math.h>#define LL long long int#define INF 7009int main(){    LL T,n,ans;    while(~scanf("%I64d",&T)){        for(LL cas=1;cas<=T;cas++){            scanf("%I64d",&n);            ans=0;            if(n>=3&&n<=6){                printf("Case #%I64d: -1\n",cas);                continue;            }            for(LL i=3;i<=6;i++){                for(LL j=3;j<=6;j++){                    if((n-i)/j>i&&(n-i)/j>j&&(n-i)%j==0){//解一次方程                         ans++;                    }                }            }            for(LL i=3;i<=6;i++){                for(LL j=3;j<=6;j++){                    for(LL k=3;k<=6;k++){                        LL a=i;                        LL b=j;                        LL c=k-n;                        LL tmp=sqrt(b*b-4*a*c);                        if(tmp*tmp!=b*b-4*a*c) continue;//说明灯儿塔(b^2-4*a*c)是否为整数                         if((tmp-b)%(2*a)!=0) continue;//说明base是不是整数.如果 a,b,c为这种组合时,base没有整数解                         LL base=(tmp-b)/(2*a);                        if(base>i&&base>j&&base>k) ans++;                    }                }            }            for(LL i=4;i*i*i<=n;i++){//i*i*i限制了,肯定是大于等于4位的                  LL tmp=n;                while(tmp%i<i&&tmp%i>=3&&tmp%i<=6){                    tmp=tmp/i;                }                if(!tmp) ans++;            }            printf("Case #%I64d: %I64d\n",cas,ans);        }    }    return 0;}



0 0
原创粉丝点击