洛谷p2678跳石头
终于过了,复杂度(nlogn)看来还是可以接受的。判断是否成立部分也不难。
顺便过了p1316丢瓶盖,两题挺像的。
#include<bits/stdc++.h>
using namespace std;
int a[50010]={0};
int len,n,m,l,r,mid;
bool check(int temp)//判断是否成立
{
int s=0,flag=0;
for(int i=1;i<=n;i++)
{
if(a[i]-a[flag]>=temp)flag=i;
else s++;
}
if(flag!=n)s++;
if(s<=m)return true;else return false;
}
int main()
{
scanf("%d%d%d",&len,&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
a[++n]=len;l=1;r=len;
while(l+1<r)//二分答案
{
mid=(l+r)/2;
if(check(mid))l=mid;else r=mid;
}
if(check(r))printf("%d",r);else printf("%d",l);
return 0;
}
洛谷p1181数列分段
用到前缀和,刚开始没有注意到flag的包含问题,改了后就过了。。。打表大法好,模拟大法好
#include<bits/stdc++.h>
using namespace std;
int a[100010]={0},sum[100010]={0};
int n,m,l,r,mid,ma;
bool check(int temp)
{
int s=0,flag=1;
for(int i=1;i<=n;i++)
if(sum[i]-sum[flag-1]>temp)//[flag-1]!
{
flag=i;
s++;
}
if(s<m)return true;
else return false;
}
int main()
{
scanf("%d%d",&n,&m);
ma=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
if(a[i]>ma)ma=a[i];
}
l=ma;r=sum[n];
while(l+1<r)
{
mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid;
}
if(check(l))printf("%d",l);
else printf("%d",r);
return 0;
}
p1908逆序对
经典模版题(现在才ak真是惭愧。。。)归并排序其实也不难理解(只是以前太害怕?)
明天计划:聪明的质检员,试练场“递推与递归二分”。
#include<bits/stdc++.h>
using namespace std;
int a[40010]={0},c[40010]={0},n;
long long ans=0;
void swap(int l,int r)
{
if(l==r)return;
int mid=(l+r)/2;
swap(l,mid);swap(mid+1,r);//拆分
int i=l,j=mid+1,x=l;
while(i<=mid&&j<=r)//合并
if(a[i]<=a[j])
{
c[x]=a[i];i++;x++;
}
else
{
c[x]=a[j];x++;j++;
ans+=mid-i+1;//计数逆序对
}
while(i<=mid)
{
c[x]=a[i];x++;i++;
}
while(j<=r)
{
c[x]=a[j];x++;j++;
}
for(int i=l;i<=r;i++)a[i]=c[i];//整理
return;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
swap(1,n);
printf("%lld",ans);
return 0;
}