【BZOJ2298】【luoguP2519】problem a

description

一次考試共有n個人參加,第i個人說:“有ai個人分數比我高,bi個人分數比我低。”問最少有幾個人沒有說真話(可能有相同的分數)


analysis

  • 這題轉化模型很妙,容易知道最少沒有說真話的數量=n=n-說真話最多的數量

  • 對於aia_i個比ii大、bib_i個比ii小,可以看成ii分數排名第ai+1a_i+1

  • 又由於有重分,那麼轉化成[ai+1,nbi][a_i+1,n-b_i]這段排名內的分數全部相等

  • 判斷某個區間單獨不可行就判斷ai+1a_i+1是否大於nbin-b_i

  • 如果兩個區間有交(且不完全重合),這肯定不合法,至少一個是假話

  • 這是因爲給出的分數區間唯一確定,不可能出現同分數不同區間

  • 現在問題相當於有很多條線段,求[1,n][1,n]區間內,最大線段個數覆蓋是多少

  • 先把線段按右端點排序,然後統計同一區間出現的次數,次數大於區間長度則取minmin

  • f[i]f[i]表示到第11位到第ii位最大線段覆蓋,由於排序好了,維護一個左端點轉移

  • b[left].y==ib[left].y==i,則可以轉移到f[i]f[i]++left++left繼續轉移即可

  • 我調了很久因爲nn前後不一樣,實際應該取最初讀入的nn來算答案


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 100005
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)

using namespace std;

ll f[MAXN],val[MAXN];
ll n,m,tot,cnt;

struct node
{
	ll x,y;
}a[MAXN],b[MAXN];

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
inline bool cmp(node a,node b){return a.y<b.y || (a.y==b.y && a.x<b.x);}
int main()
{
	//freopen("P2519.in","r",stdin);
	n=m=read();
	fo(i,1,n)
	{
		ll x=read(),y=read();
		if (x+y>=n)continue;
		a[++tot].x=x+1,a[tot].y=n-y;
	}
	n=tot,tot=0,sort(a+1,a+n+1,cmp);
	fo(i,1,n)
	{
		if (i>1 && a[i].x==a[i-1].x && a[i].y==a[i-1].y){++val[tot];continue;}
		b[++tot]=a[i],val[tot]=1;
	}
	fo(i,1,tot)val[i]=min(val[i],b[i].y-b[i].x+1);
	ll left=0;memset(f,128,sizeof(f)),f[0]=0;
	fo(i,1,m)
	{
		f[i]=f[i-1];
		while (left<tot && b[left+1].y==i)++left,f[i]=max(f[i],f[b[left].x-1]+val[left]);
	}
	printf("%lld\n",m-f[m]);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章