洛谷 P1496 火烧赤壁
这个题用的模拟+贪心,没用离散化,因为实在没懂离散化的意义。。。我太费了。。。
我是智障。。。
题意是说覆盖的线段的长度,不是点的数量!
这就是我用差分没有过的原因。。。
代码:
#include<iostream> #include<cstdio> #include<algorithm> #define NUM 20010 using namespace std; int n,ans; int a[NUM],b[NUM]; int main(){ ios::sync_with_stdio(0); //关同步 cin >> n; for( int i = 1;i <= n;i++ ) cin >> a[i] >> b[i]; sort( a+1,a+n+1 ); //给起点排序① sort( b+1,b+n+1 ); //给终点排序① for( int i = 1;i <= n;i++ ){ ans += b[i] - a[i]; if( i != n && b[i] > a[i+1] ) ans -= b[i] - a[i+1]; //ans减去(当前终点——下一个起点)的距离② } cout << ans; return 0; }
然后就水过去了。。。
先解释两个①,其中a数组存起点,b数组存终点,从小到大排个序。
确实,分别排序后a数组和b数组就没有关系了,但这不重要,原因见图
这是原数组,a[1] = 2,a[2] = 5;
b[1] = 11,b[2] = 9;
________ | __ | | | | | ----------------> 2 5 9 11
__________________________________________________________
这是排序后的a、b数组对应关系:
a[1] = 2,b[1] = 9;
a[2] = 5,b[2] = 11;
_____
| __|__
| | | |
---------------->
2 5 9 11
所以,对a、b数组排序是没有影响的。
再来解释一下②,很显然,重复部分的距离应当去掉不要,即图中的(5-9)
所以,这个减去重复是很有必要的。
想了想,还是把离散化的代码放上吧。。。虽然没看懂。。。(加注释) ( 2021.8.26 )
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<cstring> #define ll int using namespace std; ll n,m=1,ans=0;//m记录坐标数 ll c[40100]= {0}; //因为c要把起点与终点存下来,所以开40100 int a[20100],b[20100];//a存起点,b存终点 bool flag[40100];//判断是否有效 inline long find(long key){ //找在c里的位置_ int p = lower_bound( c+1,c+m+1,key ) - c; if( c[p] != key ) p--; return p; } int main(){ cin >> n; for(ll i=1; i<=n; ++i){ cin >> a[i] >> b[i]; c[m]=a[i]; m++; c[m]=b[i]; m++; }//把a,b存入c数组里去 //c里面好像是存下了所有的点 sort(c+1,c+m+1);//排序坐标 for(ll i=1; i<=n; ++i){ a[i]=find(a[i]); b[i]=find(b[i])-1;//找在c数组里位置 for(int j=a[i]; j<=b[i]; ++j) flag[j]=true;//这一段有效 } for(ll i=1; i<=m; ++i){ if(flag[i]) ans+=c[i+1]-c[i];//有效,加入ans } cout << ans; return 0; }