CSP第二轮前模拟赛
我太菜了
T1
题目描述
奶牛们对围栏的高度非常敏感。奶牛希望围栏高度既不太矮以至于他们没有安全感,也不太高以至于她们看不见围栏外的天地。所以每头奶牛都有自己喜欢的高度。奶牛有N头,每个奶牛有一个自己喜欢的高度在[1…10,000]范围里。
这对John来说是一个头疼的问题。作为一个美学观点强烈的人,他希望围栏的高度基本相同,但作为一个有同情心的人,他希望能尽可能的满足奶牛们的需求。(或许他只是一个自私的人,希望奶牛能给他多产点奶)
作为妥协,他决定将围栏的柱子做成不同的高度以满足大多数奶牛的需求(必须严格超过半数)。一个满意的条件是在所有的柱子中有它喜欢的那个高度。但同时John希望最高的柱子和最矮的柱子之间的高度差最小。请你帮他解决这个问题。
围栏的高度仅仅由柱子的高度决定。
输入格式
第1行:一个整数N。( 1 < = n < = 10000 1<=n<=10000 1<=n<=10000)
第2…N+1行:一个整数 A i A_i Ai表示这头牛喜欢的高度。
输出格式
仅一行即最高的柱子和最矮的柱子之间的高度差。
样例数据
input
3
1
10
3
output
2
【样例说明】 John使用高度为1,3的柱子建围栏,使三头牛中的两头满意,而3-1=2,所以输出2。
数据规模与约定
时间限制:
1
s
1
s
1s1s
1s1s
空间限制:
256
M
B
256MB
256MB
只A了这一个题QAQ
说明这个题确实水。我先开个数组存每个奶牛心仪的高度,sort排序然后因为是要大多数奶牛,所以比较第i头到第 i + ( N / 2 + 1 ) i+(N/2+1) i+(N/2+1)头奶牛喜欢的高度差,for循环里挨个枚举就行了。`
#include <bits/stdc++.h>
using namespace std;
long long ans=9999999,n,a[19000],m;
int main()
{freopen("height.in","r",stdin);freopen("height.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
if(n%2==1) m=n/2+1;
if(n%2==0) m=n/2;
for(int i=1;i<=m;i++)
{
if(a[n/2+i]-a[i]<ans) ans=a[n/2+i]-a[i];
}
cout<<ans;
return 0;
}
希望csp都是这种题。
T2
题目描述
贝茜这头奶牛设计了她认为将是下一个热门的视频游戏“愤怒的奶牛”。她认为这是她完全原创的:玩家将一个弹弓射到一个一维的场景中,该场景由位于数字线上各个点的一组干草包组成。每只奶牛都有足够的力量引爆其落地地点附近的干草包。爆炸后的奶牛会引爆R范围内的干草包。我们的目的是使用一系列奶牛引爆所有的干草包。
有N捆干草包位于这一行的不同整数位置 x 1 , x 2 , . . . , x N x_1,x_2,...,x_N x1,x2,...,xN,如果一头奶牛以能量R着陆在了位置x,那么会引起半径为 R ( x − R . . R + x ) R(x-R..R+x) R(x−R..R+x)的爆炸,并摧毁范围内的所有干草包。
一共有K头奶牛允许被用来作为炮弹,每头奶牛的能量R都相同。请帮忙决定这个最小的能量,使得用这K头奶牛可以摧毁所有的干草包。
输入格式
第一行包含两个整数 N , K ( 1 < = N < = 50 , 000 , 1 < = K < = 10 ) N,K(1<=N<=50,000,1<=K<=10) N,K(1<=N<=50,000,1<=K<=10)。
接下来N行,每行包含一个整数xi,表示每捆干草包的位置 ( 0 < = x i < = 1 , 000 , 000 , 000 ) (0<=xi<=1,000,000,000) (0<=xi<=1,000,000,000)。
输出格式
一行一个整数,最少所需要的每头奶牛的能量值R。
样例数据
input
7 2
20
25
18
8
10
3
1
output
5
数据规模与约定
时间限制:
1
s
1
s
1s1s
1s1s
空间限制:
256
M
B
256MB
256MB
万恶的奶牛
看错题了QAQ
一开始以为干草包会连锁爆炸,就想当然打成了这样的代码
#include <bits/stdc++.h>
using namespace std;
long long x[55000],n,k,r,y[50001];
int main()
{freopen("angry.in","r",stdin);freopen("angry.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&x[i]);
sort(x+1,x+1+n);
for(int i=1;i<n;i++)
{
y[i]=x[i+1]-x[i];
}
sort(y+1,y+n);
for(int i=1;i<=k;i++)
{
if(y[n-1]%2==0) y[n-1]=y[n-1]/2;
else if(y[n-1]%2==1) y[n-1]=y[n-1]/2+1;
sort(y+1,y+n);
}
r=y[n-1];
printf("%d",r);
return 0;
}
也不考虑会不会超时,最最恶心的是两组样例都过了
好家伙,直接把水稻往我胃里插
出来成绩整个人都傻了(但是不知道为啥还是得了十分)
然后就只能好好用二分写了。
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int pp=1e7;
int a[pp];
bool check(int x)
{
int first=1,now=1,num=1;
while(now<=n)
{
while(a[now]-a[first]<=x&&now<=n) now++;
if(now<=n)
{
first=now;
num++;
}
}
if(num<=m) return 1;
else return 0;
}
int er()
{
int lert=0,right=2*pp,mid;
while(lert+1<right)
{
mid=(lert+right)/2;
if(check(mid)) right=mid;
else lert=mid;
}
if(check(lert)) return lert;
else return right;
}
int main()
{
freopen("angry.in","r",stdin);freopen("angry.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+n+1);
int ans=(er()+1)/2;
printf("%d",ans);
return 0;
}
标准的二分答案
T3
著名的龙虎斗!!!(普及组)
题目描述
轩轩和凯凯正在玩一款叫《龙虎斗》的游戏,游戏的棋盘是一条线段,线段上有 n个兵营(自左至右编号 1 ∼n),相邻编号的兵营之间相隔 1 厘米,即棋盘为长度为 n-1 厘米的线段。i 号兵营里有 cici 位工兵。
下面图 1 为 n = 6 n=6 n=6的示例:
轩轩在左侧,代表“龙”;凯凯在右侧,代表“虎”。 他们以 m 号兵营作为分界, 靠左的工兵属于龙势力,靠右的工兵属于虎势力,而第 m号兵营中的工兵很纠结,他们不属于任何一方。
一个兵营的气势为:该兵营中的工兵数 × 该兵营到 m 号兵营的距离;参与游戏 一方的势力定义为:属于这一方所有兵营的气势之和。
下面图 2 为 n = 6,m = 4 的示例,其中红色为龙方,黄色为虎方:
游戏过程中,某一刻天降神兵,共有 s 1 s_1 s1位工兵突然出现在了 p 1 p_1 p1号兵营。作为轩轩和凯凯的朋友,你知道如果龙虎双方气势差距太悬殊,轩轩和凯凯就不愿意继续玩下去了。为了让游戏继续,你需要选择一个兵营 p 2 p_2 p2,并将你手里的 s 2 s_2 s2位工兵全部派往 兵营 p 2 p_2 p2,使得双方气势差距尽可能小。
注意:你手中的工兵落在哪个兵营,就和该兵营中其他工兵有相同的势力归属(如果落在 m 号兵营,则不属于任何势力)。
输入格式
输入文件的第一行包含一个正整数n,代表兵营的数量。
接下来的一行包含 n 个正整数,相邻两数之间以一个空格分隔,第 i个正整数代 表编号为 i 的兵营中起始时的工兵数量 c i c_i ci。
接下来的一行包含四个正整数,相邻两数间以一个空格分隔,分别代表 m , p 1 , s 1 , s 2 m , p 1 , s 1 , s 2 m,p_1,s_1,s_2m,p_1,s_1,s_2 m,p1,s1,s2m,p1,s1,s2。
输出格式
输出文件有一行,包含一个正整数,即 p 2 p_2 p2,表示你选择的兵营编号。如果存在多个编号同时满足最优,取最小的编号。
样例数据
input1
6
2 3 2 3 2 3
4 6 5 2
output1
2
input2
6
1 1 1 1 1 16
5 4 1 1
output2
1
样例说明
样例1:见问题描述中的图 2。
双方以 m=4号兵营分界,有 s 1 s_1 s1=5 s 1 s_1 s1=5位工兵突然出现在 p 1 p_1 p1=6 p 1 p_1 p1=6号兵营。 龙方的气势为:
2×(4−1)+3×(4−2)+2×(4−3)=14
虎方的气势为:
2×(5−4)+(3+5)×(6−4)=18
当你将手中的 s2=2s2=2位工兵派往 p2=2p2=2号兵营时,龙方的气势变为:
14+2×(4−2)=18
此时双方气势相等。
样例2:
双方以 m = 5号兵营分界,有 s 1 s_1 s1=1位工兵突然出现在 p 1 p_1 p1=4号兵营。
龙方的气势为:
1×(5−1)+1×(5−2)+1×(5−3)+(1+1)×(5−4)=11
虎方的气势为:
16×(6−5)=16
当你将手中的 s2=1s2=1位工兵派往 p2=1p2=1号兵营时,龙方的气势变为:
11+1×(5−1)=15
此时可以使双方气势的差距最小。
数据规模与约定
1
<
m
<
n
,
1
≤
p
1
≤
n
1
<
m
<
n
,
1
≤
p
1
≤
n
1<m<n,1≤p1≤n1<m<n,1≤p1≤n
1<m<n,1≤p1≤n1<m<n,1≤p1≤n。
对于%20 的数据,n=3,m=2,ci=1,s1,s2≤100n=3,m=2,ci=1,s1,s2≤100。
另有%20 的数据,n≤10,p1=m,ci=1,s1,s2≤100n≤10,p1=m,ci=1,s1,s2≤100。
对于%60 的数据,n≤100,ci=1,s1,s2≤100n≤100,ci=1,s1,s2≤100。
对于%80 的数据,n≤100,ci,s1,s2≤100n≤100,ci,s1,s2≤100。
对于%100 的数据,n≤105,ci,s1,s2≤109n≤105,ci,s1,s2≤109。
时间限制:1s1s
空间限制:256MB
普及组的题我都A不了,菜死我了QAQ
考试的时候就直接先把龙和虎的气势分别算出来然后比较下大小,分别试下把“天降神兵”放到弱势方的每个阵营。
然后就52了……
后来改错注意到没有算把兵加到m阵营,即不叫增员时两边气势最接近,改上去之后加了几分,然后又把所有数据都long long,又加了几分,聪明的我又在return 0前加了个特判,于是愉快地ac了!!!
#include <bits/stdc++.h>
using namespace std;
long long n,c[123456],p1,s1,p2,s2,m;
unsigned long long lo,hu,lo2,hu2; //按照题目输入
long long hh=99999999; //hh记录给哪个组
int main()
{freopen("fight.in","r",stdin);freopen("fight.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
scanf("%d%d%d%d",&m,&p1,&s1,&s2);
for(int i=1;i<m;i++) lo+=(m-i)*c[i]; //lo是龙的气势
for(int i=m+1;i<=n;i++) hu+=(i-m)*c[i]; //hu是虎的气势
if(p1>m) hu+=(p1-m)*s1; //加人
if(p1<m) lo+=(m-p1)*s1; //加人
hh=labs(hu-lo);
if(hu>lo) //如果虎的气势多
{
for(int i=1;i<=m;i++) //枚举把人加到龙的每个组里或者不加
{
lo2=lo;
lo2+=(m-i)*s2; //加到龙的某个营
if(lo2==hu) //特判下可能加到某个营后两边气势就可以一样
{
cout<<i;
return 0;
}
else if(lo2>hu&&lo2-hu<hh)
{
hh=lo2-hu;
p2=i;
}
else if(lo2<hu&&hu-lo2<hh)
{
hh=hu-lo2;
p2=i;
}
}
}
else if(lo>hu)
{
for(int i=m;i<=n;i++)
{
hu2=hu;
hu2+=(i-m)*s2;
if(lo==hu2)
{
cout<<i;
return 0;
}
else if(lo>hu2&&lo-hu2<hh)
{
hh=lo-hu2;
p2=i;
}
else if(lo<hu2&&hu2-lo<hh)
{
hh=hu2-lo;
p2=i;
}
}
}
else if(lo==hu) //如果两边气势一样,直接把人加到中立兵营
{
cout<<m;
return 0;
}
if(p2==0)
{
cout<<m;
return 0;
}
cout<<p2;
return 0;
}
因为这道题修改的时候找了几个大佬帮我看看,所以就特别加了注释。
T4
题目描述
这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!
输入格式
一行包含两个整数N,M,之间由一个空格隔开。
输出格式
总共的方案数, 答案不超过int能容纳的最大值。
样例数据
input1
1 3
output1
7
input2
3 2
output2
49
样例说明
除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有222-1=7种方案。
数据规模与约定
30% N=1;
100% N,M<=6。
时间限制:1s1s
空间限制:256MB256MB
2009年安徽省选中国象棋(小数据版)
30分 N=1,递推也彳亍,递归也彳亍。
显然是搜索,和 彳亍皇后类似,规则彳亍皇后简单;
象棋中的炮要隔一个子才能打,所以,可以放炮的方案是每行,每列不能超过两个炮。
dfs枚举,每行放两个炮的位置,两重循环枚举,类似于八皇后,当前列也要判断当前答案是否可行。
本题得到解决。