您的位置:首页 > 大数据 > 人工智能

2014 Multi-University Training Contest 7 题解

2014-08-13 17:08 344 查看


<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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: