2014 Multi-University Training Contest 7 题解

<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 1600
using 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 1600
using 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 100009
using 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 16
1 1 1
1 2 2
1 3 3
1 4 4
2 1 5
2 2 6
2 3 7
2 4 8
3 1 9
3 2 10
3 3 11
3 4 12
4 1 13
4 2 14
4 3 15
4 4 16
6
1 1 2
2 1 2
3 2 2
3 3 2



3 3 5
1 1 1
1 3 2
2 1 3
2 2 4
3 3 5
5
*/

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 7009
int 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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值