第一题
天平 (Standard IO)
Time Limits: 1000 ms Memory Limits: 65536 KB Detailed Limits
Description
FJ有一架用来称牛的体重的天平。与之配套的是N(1<=N<=40)个已知质量的砝码(所有砝码质量的数值都在31位二进制内)。每次称牛时,他都把某头奶牛安置在天平的某一边,然后往天平另一边加砝码,直到天平平衡,于是此时砝码的总质量就是牛的质量(FJ不能把砝码放到奶牛的那边,因为奶牛不喜欢称体重,每当FJ把砝码放到她的蹄子底下,她就会尝试把砝码踢到FJ脸上)。天平能承受的物体的质量不是无限的,当天平某一边物体的质量大于C(1<=C<2^30)时,天平就会被损坏。
砝码按照它们质量的大小被排成一行。并且,这一行中从第3个砝码开始,每个砝码的质量至少等于前面两个砝码(也就是质量比它小的砝码中质量最大的两个)的质量的和。
FJ想知道,用他所拥有的这些砝码以及这架天平,能称出的质量最大是多少。由于天平的最大承重能力为C,他不能把所有砝码都放到天平上。
现在FJ告诉你每个砝码的质量,以及天平能承受的最大质量。你的任务是选出一些砝码,使它们的质量和在不压坏天平的前提下是所有组合中最大的。
Input
第1行: 两个用空格隔开的正整数,N和C。
第2..N+1行: 每一行仅包含一个正整数,即某个砝码的质量。保证这些砝码的质量是一个不下降序列。
Output
第1行: 一个正整数,表示用所给的砝码能称出的不压坏天平的最大质量。
Sample Input
3 15
1
10
20
Sample Output
11
Hint
【样例说明】
FJ有3个砝码,质量分别为1,10,20个单位。他的天平最多只能承受质量为15个单位的物体。用质量为1和10的两个砝码可以称出质量为11的牛。这3个砝码所能组成的其他的质量不是比11小就是会压坏天平。
题解:由于各种原因这题打个dfs就可以AC,但纯dfs只能拿60分,所以我们要用一点小技巧,那就是剪枝。具体代码见。
#include<iostream>
#include<cstdio>
using namespace std;
long long n,nn,c,a[50],summ[50];
long long ans=0;
void dfs(long long n,long long sum)
{
if(sum+summ[n]<=ans) return ;//重点,剪枝操作,可以助你从60分变为100分
if(ans<sum) ans=sum;//更新ans的值
for(int i=n;i;i--)
{
if(sum+a[i]<=c)
{
dfs(i-1,sum+a[i]);
}
}
}
int main()
{
cin>>n>>c;
nn=n;
int r=0;
for(int i=1;i<=nn;i++)
{
scanf("%lld",&a[i]);
if(a[i]>c&&r==0)//如果第i个数大于c,那么我们要求的有效数字就是从1到当前的i-1个数
{
n=i-1;
r=1;
}
if(a[i]<=c)
summ[i]=summ[i-1]+a[i];//求前缀和
}
dfs(n,0);
cout<<ans;
return 0;
}
第二题
游历的路线(lines.pas/cpp)
(File IO): input:lines.in output:lines.out
Time Limits: 1000 ms Memory Limits: 131072 KB Detailed Limits
Description
我们的郭嘉大大经过一段时间发现了袁绍这个人干大事而惜身,见小利而忘义,又逢曹操在招兵买马,决定逃离袁绍去投曹操,而我们的曹操在第M天招募良材,我们的郭嘉大大既不能早去,也不能晚去,于是乎,他就趁着这一段时间到其他的城市游历一番,而每两个城市之间只能坐马车来往,由于我们的郭嘉大大很贪钱,他想用最少的费用,所以需要我们帮他求出这一个最小的费用。
Input
第一行包含两个数n,m, 表示有n个城市,和m天后曹操招纳良材。城市一就是郭嘉所在的城市,城市n就是曹操处。接下来n * (n – 1)行描述马车乘坐表。 第2到第n行就是描述的城市1到2… n的马车乘坐表. 第n + 1到第2n-1行描述的城市2到城市1,3..n的马车乘坐表… … 对每一行,首先有一个数T,表示城市I到城市J的马车以T为周期,接下来有T个数,表示每天的马车的价格,如果价格为0则表示没有马车可坐。(n <= 100, m <= 200, T <= 20, Price <= 50000)
Output
如果存在这样的路线使郭嘉第m天到达曹操处,则输出最少的费用,否则输出0!
Sample Input
3 5
2 130 150
3 75 0 80
2 110 100
4 60 70 60 50
3 0 135 140
2 70 80
Sample Output
355
题解:
题目大意:有m-1次坐车的机会,要使最后到n市,从一个市出发到其他市的马车都有一个周期,周期不同费用不一样。现在要求满足情况的最小费用
我们可以想到用dp解决此题,方程式也是很好推,设f[k][i]为第k天到i城市的最小花费,
然后输入时用一个a[k][i][j]保存周期内的第几天从i城市走到j城市的花费。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
long long int n,m,a[21][101][101],f[201][101],t,ans=0,next,maxt=-1;
int wei(int k,int i)
{
if(k%i==0)
return i;
else return k%i;
}
int main()
{
//freopen("lines.in","r",stdin);
//freopen("lines.out","w",stdout);
memset(a,0,sizeof(a));
memset(f,0x7f,sizeof(f));
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(j!=i)
{
scanf("%lld",&t);
//cin>>t;
a[0][i][j]=t;
for(int k=1;k<=t;k++)
{
scanf("%lld",&a[k][i][j]);
//cin>>a[k][i][j];
if(a[k][i][j]==0)
a[k][i][j]=0x7fffffff;//如果为0,就赋值一个超大值
}
}
}
}
f[0][1]=0;//初始化
for(int k=1;k<=m;k++)
{
for(int j=1;j<=n;j++)
{
for(int i=1;i<=n;i++)
{
if(i!=j)
{
int kk=wei(k,a[0][i][j]);
f[k][j]=min(f[k-1][i]+a[kk][i][j],f[k][j]);//转移方程
}
}
}
}
cout<<f[m][n];
return 0;
}
第三题
最短路(shortest)
Time Limits: 3000 ms Memory Limits: 262144 KB Detailed Limits
Description
小Y最近学得了最短路算法,一直想找个机会好好练习一下。话虽这么说,OJ上最短路的题目都被他刷光了。正巧他的好朋友小A正在研究一类奇怪的图,他也想凑上去求下它的最短路。
小A研究的图可以这么看:在一个二维平面上有任意点(x,y)(0<=x<=N,0<=y<=M,且x,y均为整数),且(x,y)向(x-1,y)(必须满足1<=x)和(x,y-1)(必须满足1<=y)连一条边权为0的双向边。
每个点都有一个非负点权,不妨设(x,y)的权值为F[x][y],则有:
1.x=0或y=0:F[x][y]=1;2.其他情况:F[x][y]=F[x-1][y]+F[x][y-1]。
现在,小Y想知道(0,0)到(N,M)的最短路,即使得经过的点的权值之和最小。为了炫耀自己学过最短路算法,他决定和你进行一场比赛,看谁的程序跑得快。然则小Y没有学过高精度算法,所以他希望输出答案时只输出答案模1000000007后的值。
Input
一行两个正整数N,M,表示图的大小。
Output
一行一个整数Ans,表示答案模1000000007后的值。
Sample Input
1 2
Sample Output
6
Data Constraint
见图。
Hint
10%的数据满足N,M<=20;
30%的数据满足N,M<=100;
60%的数据满足min(N,M)<=100;
100%的数据满足N*M<=10^12。
题解:
【最短路】
这个图就是个划分后的矩形,也就是网格图。
20分看这里:暴力求出每个点权,然后使用DP或最短路算法。总效率O(NM)或O(NMLog(NM))。答案的范围在Int64/long long范围内。
60分看这里:暴力求出每个点权,然后使用DP或最短路算法。使用高精度储存答案。总效率O(NMA)或O(NMALog(NM))。其中A为答案长度。
观察原图,将x+y值相同的点(x,y)归为一层,将层按x+y值从小到大看,会发现其实整个图是杨辉三角的一部分。
容易看出,每层权值最小的点或都在最左侧或都在最右侧。由于N,M互换并不影响答案,所以假如每层权值最小的点都在最右侧,则交换N,M,保证每层权值最小的点都在最左侧。
从本质上说,就是该图的最短路是确定的,都是沿着矩形外围一圈走,且一开始先走矩形长的一边。
保证N<=M,那么答案可以直接算出,也就是M+C[M][0]+C[M+1][1]+…+C[M+N][N]。
120分看这里:用一个矩阵维护C[K][0]-C[K][N]的值。通过快速幂可以迅速得出C[M][0]-C[M][N]的值,由于答案涉及的排列数只有N+1项,所以接着逐级递推即可。总效率O(N^3LogM)。
200分看这里:把后面的排列数分别拆解开看:
C[M][0]=1;
C[M+1][1]=(M+1)/1;
C[M+2][2]=(M+1)(M+2)/(1*2)=C[M+1][1]((M+2)/2);
C[M+3][3]=C[M+2][2]*((M+3)/3);
…
C[M+N][N]=C[M+N-1][N-1]*((M+N)/N)。
由于模的数是一个素数,所以除以数a直接转化成乘数a的逆元。接着直接递推即可。总效率O(NLogN)。