西电第一周 b,d,j,m题题解
西电第一周 b,d,j,m题题解
先碎碎念
不得不说已经很久很久没有写题解了,现在想想也的确欠了好多该写的题解没写,并不是说自己不想写还是怎样,这样说实际上对我不公正,因为我个人是很喜欢写题解的,或者说我个人实际上是很喜欢写点什么的。若要较为准确地把握其原因的话,我想,可以做这样的表述:自己太过于投入,而忘记了从更加系统化的层面把握事情。
那么,开始吧。
对于b题来说
先对牌排序,发现这样的单调规律:最小的牌和其余n-1个牌搭配的时候答案是最小的牌,倒数第二小的牌和其余n-2个牌搭配的时候答案是倒数第二小的牌...以此类推。可以发现是一个等差数列,答案为i的时候对应n-i,我们想知道第k大分值,也就是第(n*(n-1)/2+1-k)小分值,设ans[i]为拿到第i小的牌时总共是多少种情况(显然,ans[i]等于1-i的等差数列之和)。
当(n*(n-1)/2+1-k)第一次小于等于ans[i]时 输出i即可。
对于d题来说
发现是个等比数列,第i个位置对应的桃子为2^(i-1),同样求和,当猴子妈妈准备的桃子数第一次大于第i个位置时的和时,说明猴子妈妈的桃子不够了,后面的小猴子没桃子吃了=。=,那么最终答案一定是第i-1个位置的和第i个位置的之间的最大值。
j题的话
我是用二分答案最短时间,假设说时间x内能完成,也就意味着对于每道题来说,一定已经被完成了x分钟,并且每分钟可以选择一道题完成k分钟嘛,我们就从头开始枚举,哪一道题完成x分钟不够,我们就一定要在他上面花费更多的时间去完成,当然未必是1天,可能是很多天,具体计算方法是
(((a[i]-temx)%k==0)?((a[i]-temx)/k):((a[i]-temx)/k+1));
temx即为x,a[i]即为第i道题一共所需时间。
m题呢
m题真是很好的一道题=。=
先是写二分答案和线段树,狂tle(线段树求和的复杂度无论如何都是相当不容忽视的啊=。=)
不过其实把线段树换成前缀数组就好了,反正无论如何也用不到线段树的其他功能,仅仅是区间求和的话前缀数组就能很好的完成。
当然,尺取法也可以,不过我目前只是通过这一道题稍微知道有尺取法这个算法,具体还不太理解,也用不好,还需要多做几道题理解一下。
完整代码
B
#include<bits/stdc++.h>
using namespace std;
int t,n,k;
int a[2505];
int ans[2505];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++)
{
ans[i]=ans[i-1]+n-i;
// printf("A %d\n",ans[i]);
}
int sum=(n*(n-1))/2;
for(int i=1;i<=n-1;i++)
{
if(sum+1-k<=ans[i])
{
printf("%d\n",a[i]);
break;
}
}
}
}
D题就不贴了。=。=
J
#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
int t,n;
long long tem,k;
long long a[MAXN];
int check(long long x)
{
long long temx=x;
for(int i=1;i<=n;i++)
{
if(x<0)
{
return 0;
}
if((a[i]-temx<=0)&&(x>=0))
{
// printf("%lld %lld\n",a[i],x);
return 1;
}
x-=(((a[i]-temx)%k==0)?((a[i]-temx)/k):((a[i]-temx)/k+1));
}
if(x>=0)
{
return 1;
}
else
{
return 0;
}
}
//
bool cmp(long long l1,long long l2)
{
return l1>l2;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
scanf("%lld",&k);
sort(a+1,a+1+n,cmp);
long long r=1000000000,l=1;
while(l<=r)
{
//printf("%lld %lld\n",l,r);
long long mid=(l+r)>>1;
if(check(mid)){
r=mid-1;
}
else
l=mid+1;
}
printf("%lld\n",l);
}
}
M
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
int t,n;
long long m;
long long pre[MAXN];
int a[MAXN];
int check(int x)
{
for(int i=1;i<=n-x;i++)
{
if(pre[i+x]-pre[i-1]>=m)
{
return 1;
}
}
return 0;
}
int main()
{
scanf("%lld",&t);
while(t--)
{
scanf("%d %lld",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
pre[i]=pre[i-1]+a[i];
}
int r=n,l=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)){
r=mid-1;
}
else
l=mid+1;
}
if(r+1>n)
{
printf("0\n");
continue;
}
printf("%d\n",l+1);
}
}