目录
1.汤姆猫的天堂梦
题目
汤姆斯生活在一个等级为 00 的星球上。那里的环境极其恶劣,每天 1212 小时的工作和成堆的垃圾让人忍无可忍。他向往着等级为 NN 的星球上天堂般的生活。
有一些航班将人从低等级的星球送上高一级的星球,有时需要向驾驶员支付一定金额的费用,有时却又可以得到一定的金钱。
汤姆斯预先知道了从 00 等级星球去 NN 等级星球所有的航线和需要支付(或者可以得到)的金钱,他想寻找一条价格最低(甚至获得金钱最多)的航线。
输入格式
第一行一个正整数 NN(N \le 100N≤100),接下来的数据可分为 NN 个段落,每段的第一行一个整数 K_iKi(K_i \le 100Ki≤100),表示等级为 ii 的星球有 K_iKi 个。
接下来的 K_iKi 行中第 jj 行依次表示与等级为 ii,编号为 jj 的星球相连的等级为 i - 1i−1 的星球的编号和此航线需要的费用(正数表示支出,负数表示收益,费用的绝对值不超过 10001000)。
每行以 00 结束,每行的航线数 \le 100≤100。
输出格式
输出所需(或所得)费用。正数表示支出,负数表示收益。
输入输出样例
输入 #1复制
3 2 1 15 0 1 5 0 3 1 -5 2 10 0 1 3 0 2 40 0 2 1 1 2 5 3 -5 0 2 -19 3 -20 0
输出 #1复制
-1
题解
简单的dp
代码
#include<bits/stdc++.h>
using namespace std;
int dp[200][200]={0};
int main(){
int n,a;
cin>>n;
for(int i=1;i<=n;++i){
cin>>a;
for(int j=1;j<=a;++j){
dp[i][j]=INT_MAX-1000;
int b,c;
cin>>b;
while(b!=0){
cin>>c;
dp[i][j] = dp[i-1][b]+c < dp[i][j] ? dp[i-1][b]+c:dp[i][j];
cin>>b;
}
}
}
int min=INT_MAX;
for(int i=1;i<=a;++i) min=dp[n][i]<min?dp[n][i]:min;
printf("%d",min);
return 0;
}
2.跑步
题目
路人甲准备跑 nn 圈来锻炼自己的身体,他准备分多次(\gt1>1)跑完,每次都跑正整数圈,然后休息下再继续跑。
为了有效地提高自己的体能,他决定每次跑的圈数都必须比上次跑的多。
可以假设他刚开始跑了 00 圈,那么请问他可以有多少种跑完这 nn 圈的方案?
输入格式
一行一个整数,代表 nn。
输出格式
一个整数表示跑完这 nn 圈的方案数。
输入输出样例
输入 #1复制
212
输出 #1复制
995645335
题解
使用动态规划最正确,注意dp的数组要开long long 的。
代码
#include<bits/stdc++.h>
using namespace std;
long long n,dp[501];
int main(){
cin>>n;
dp[0]=1;
for (int i=1;i<=n;i++){
for (int j=n;j>=i;j--){
dp[j] += dp[j-i];
}
}
cout<<dp[n]-1<<endl;
return 0;
}
3.砝码称重
题目
你有一架天平和 NN 个砝码, 这 NN 个砝码重量依次是 W_{1}, W_{2}, \cdots, W_{N}W1,W2,⋯,WN 。 请你计算一共可以称出多少种不同的重量?
注意砝码可以放在天平两边。
输入格式
输入的第一行包含一个整数 NN 。
第二行包含 NN 个整数: W_{1}, W_{2}, W_{3}, \cdots, W_{N}W1,W2,W3,⋯,WN 。
输出格式
输出一个整数代表答案。
输入输出样例
输入 #1复制
3 1 4 6
输出 #1复制
10
题解
状态方程:
代码
#include<bits/stdc++.h>
using namespace std;
const int max1=150000;
int n,sum,w;
bool dp[2][300010];
int main(){
cin>>n;
dp[0][max1]=1;
for(int i=1;i<=n;++i) {
cin>>w;
sum += w;
for(int j=-sum; j<=sum;++j)
dp[i&1][j+max1] = dp[i-1&1][j-w+max1]||dp[i-1&1][j+w+max1]||dp[i-1&1][j+max1];
}
int ans=0;
for(int i=1;i<=sum;++i) ans += dp[n&1][i+max1];
printf("%d\n",ans);
return 0;
}
4.遗址
题目
很久很久以前有一座寺庙,从上往下看寺庙的形状正好是一个正方形,由 44 个角上竖立的圆柱搭建而成。现在圆柱都倒塌了,只在地上留下圆形的痕迹,可是现在地上有很多这样的痕迹,专家说一定是最大的那个。
写一个程序,给出圆柱的坐标,找出由 44 个圆柱构成的最大的正方形,因为这就是寺庙的位置,要求计算出最大的面积。注意正方形的边不一定平行于坐标轴。
例如图有 1010 根柱子,其中 (4,2),(5,2),(5,3),(4,3)(4,2),(5,2),(5,3),(4,3) 可以形成一个正方形,(1,1),(4,0),(5,3),(2,4)(1,1),(4,0),(5,3),(2,4) 也可以,后者是其中最大的,面积为 1010。
第一行包含一个 N(1\leq N\leq 3000)N(1≤N≤3000),表示柱子的数量。
接下来 NN 行,每行有两个空格隔开的整数表示柱子的坐标(坐标值在 00 到 50005000 之间),柱子的位置互不相同。
输出格式
如果存在正方形,输出最大的面积,否则输出 00。
输入输出样例
输入 #1复制
10 9 4 4 3 1 1 4 2 2 4 5 8 4 0 5 3 0 5 5 2
输出 #1复制
10
题解
找到正方形的四个顶点,找到两个点 即可确定这个正方形,所以两个for循环确定,最后依次比较即可得出答案。
代码
#include<bits/stdc++.h>
#define max(a,b) a>b?a:b
using namespace std;
bool dp[5020][5020];
int x[3020],y[3020],n,m;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d%d",x+i,y+i);
dp[x[i]][y[i]]=1;
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int a=x[i]-x[j];
int b=y[i]-y[j];
int Ax=x[i]-b;
int Bx=x[j]-b;
int Ay=y[i]+a;
int By=y[j]+a;
if(Ax<1||Ax>5000||Bx<1||Bx>5000||Ay<1||Ay>5000||By<1||By>5000)continue;
if(dp[Ax][Ay] && dp[Bx][By])ans=max(ans,a*a+b*b);
}
}
printf("%d\n",ans);
return 0;
}
5.环境治理
题目
LQ 国拥有 nn 个城市,从 00 到 n - 1n−1 编号,这 nn 个城市两两之间都有且仅有一条双向道路连接,这意味着任意两个城市之间都是可达的。每条道路都有一个属性 DD,表示这条道路的灰尘度。当从一个城市 A 前往另一个城市 B 时,可能存在多条路线,每条路线的灰尘度定义为这条路线所经过的所有道路的灰尘度之和,LQ 国的人都很讨厌灰尘,所以他们总会优先选择灰尘度最小的路线。
LQ 国很看重居民的出行环境,他们用一个指标 PP 来衡量 LQ 国的出行环境,PP 定义为:
P=\sum \limits_{i=0}^{n-1} \sum \limits_{j=0}^{n-1} d(i,j)P=i=0∑n−1j=0∑n−1d(i,j)
其中 d(i,j)d(i,j) 表示城市 ii 到城市 jj 之间灰尘度最小的路线对应的灰尘度的值。
为了改善出行环境,每个城市都要有所作为,当某个城市进行道路改善时,会将与这个城市直接相连的所有道路的灰尘度都减少 11,但每条道路都有一个灰尘度的下限值 LL,当灰尘度达到道路的下限值时,无论再怎么改善,道路的灰尘度也不会再减小了。
具体的计划是这样的:
- 第 11 天,00 号城市对与其直接相连的道路环境进行改善;
- 第 22 天,11 号城市对与其直接相连的道路环境进行改善;
……
- 第 nn 天,n - 1n−1 号城市对与其直接相连的道路环境进行改善;
- 第 n + 1n+1 天,00 号城市对与其直接相连的道路环境进行改善;
- 第 n + 2n+2 天,11 号城市对与其直接相连的道路环境进行改善;
……
LQ 国想要使得 PP 指标满足 P \leq QP≤Q。请问最少要经过多少天之后,PP 指标可以满足 P \leq QP≤Q。如果在初始时就已经满足条件,则输出 00;如果永远不可能满足,则输出 -1−1。
输入格式
输入的第一行包含两个整数 n, Qn,Q,用一个空格分隔,分别表示城市个数和期望达到的 PP 指标。
接下来 nn 行,每行包含 nn 个整数,相邻两个整数之间用一个空格分隔,其中第 ii 行第 jj 列的值 D_{i,j} (D_{i,j}=D_{j,i},D_{i,i} = 0)Di,j(Di,j=Dj,i,Di,i=0) 表示城市 ii 与城市 jj 之间直接相连的那条道路的灰尘度。
接下来 nn 行,每行包含 nn 个整数,相邻两个整数之间用一个空格分隔,其中第 ii 行第 jj 列的值 L_{i,j} (L_{i,j} = L_{j,i}, L_{i,i} = 0)Li,j(Li,j=Lj,i,Li,i=0) 表示城市 ii 与城市 jj 之间直接相连的那条道路的灰尘度的下限值。
输出格式
输出一行包含一个整数表示答案。
输入输出样例
输入 #1复制
3 10 0 2 4 2 0 1 4 1 0 0 2 2 2 0 0 2 0 0
输出 #1复制
2
题解
最短路问题,套Floyd模板,加上二分查找,最后得出答案。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int x[101][101],dis[101][101],diss[101][101], n,m;
int cheak(int k){
int p=k/n;
int o=k%n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
diss[i][j]=max(dis[i][j]-p,x[i][j]);
if(o >= i)diss[i][j]=max(diss[i][j]-1,x[i][j]);
}
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
diss[j][k]=min(diss[j][k],diss[j][i]+diss[i][k]);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ans+=diss[i][j];
}
}
if(ans<=m)return 1;
return 0;
}
inline int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=(x<<3)+(x<<1)+ch-48;
ch=getchar();
}
return x*f;
}
signed main(){
n=read();
m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=read();
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
x[i][j]=read();
}
}
int p=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
dis[j][k]=min(dis[j][k],dis[j][i]+dis[i][k]);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
p += dis[i][j];
}
}
if(p<=m){
cout<<"0";
return 0;
}
int l=1,r=1e6;
while(l<=r){
int mid=(l+r)>>1;
if(cheak(mid)==1)r=mid-1;
else l=mid+1;
}
if(l==1e6+1){
cout<<"-1";
return 0;
}
cout<<l;
return 0;
}