1003 真实的谎言

1003 真实的谎言

这是一个非常有趣的题目,题目描述很简练,但却卡住了很多人。其实,这个题并不难,也没有什么需要注意的地方,只要有了思路,基本就正确了。但是,切忌一一枚举,这样的结果只有一个——TLE。不过只要有了枚举这个想法,在适当思考,加以优化,基本就能AC了。首先,我们来说下暴力枚举的思路:定义一个结构体保存输入,输入完成后,执行

bool flag=0;
for(int i=n-1;i>=0;i--)
{
int ans=0;
for(int j=0;j<n;j++)
if(a[j].min<=i && a[j].max>=i) count++;
if(count==i) {flag=1;cout<<i<<endl;break;}
}
if(flag==0) cout<<"-1"<<endl;

当然,这样做的效率是很低的,是会TLE的,但是在这却能让我们从中得到启示:外层循环:我们假设有 i 个人说真话,我们就需要利用内层循环遍历数组,检查是否是有 i 个人说真话,如果 i 在区间内,就计数加1,这样,通过n次遍历,我们就可以找出包含了 i 的区间个数,如果包含 i 的区间个数等于 i ,那么就有 i 个人说了真话。又我们是 i :  n-1一>0 ,所以一旦成立,那么就是我们的最优解,如果所有均不成立,那么flag=0,输出-1。既然如此,我们完全可以在输入过程中完成遍历处理:设一个数组count[100001],在输入过程中加以处理,

int count[100001]={0},a,b;
for(int i=0;i<n;i++)
{ cin
>>a>>b;
for(int j=a;j<=b;j++)
count[j]
+=1;
}

这个过程中,我们统计了包含 i 的区间个数 count[i],最后我们只需要从大到小同上检索一遍,就能得到正确解了

下面是我的AC代码,大家可以参考一下,但不要直接拷贝提交,也不要太过依赖于它!

View Code
1 #include<iostream>
2 #include<cstdio>
3  using namespace std;
4  int main()
5 { int T,n;
6 cin>>T;
7 while(T--)
8 { bool flag=0;
9 int a[100001]={0},b,c,m,i,j,k;
10 cin>>n;m=n;
11 for(i=0;i<n;i++)
12 { scanf("%d %d",&b,&c);
13 for(j=b;j<=c&&j<=n;j++) a[j]+=1;
14 }
15 for(i=n;i>0;i--)
16 if(a[i]==i) {flag=1,cout<<i<<endl; break;}
17 if(flag==0) cout<<"-1"<<endl;
18 }
19 }
20
posted @ 2011-04-16 21:13  nightstaker  阅读(407)  评论(0编辑  收藏  举报