题目传送门
寒假牛客最后一场终于突破了7题,开心的一批 >_<!!!
题意比较清晰,就是问你木板最少可以分为几组,并输出每块木板被分到哪一组.
话说我的思路还是没有被列为正解 (我的思路很奇葩吗?感觉复杂度什么的也很好啊?是因为非主流吗?)
初见就锁定了这是个逆序数,二话不说写了个树状数组,但其实并不是逆序数,尽管说和逆序数很像…
首先对x进行排序,树状数组维护y就行了
x和y都没有重复的,所以对x排完序之后就不用管x了,然后只用考虑y就行了,y也很好考虑:
- 如果在已经插入的木板里不存在比当前要插入的木板的y还小的y,那就放在第一组啦.
- 如果已经插入的木板里只有一个比当前要插入的木板的y还小的y,那就第二组呗.
- 但是如果已经插入的木板里有x个比当前要插入的木板的y还小的y,那它应该放在第x+1组吗?答案是否定的.
举例:
4
4 3
3 2
2 1
1 4
对于这组样例最后要插入的是4,在它之前已经插入了三个比它小的数了,但是它应该被分到第二组而不是第4组…这就是逆序数不对的原因…(WA了三发才意识到…)
所以树状数组tree[k]维护的是1-k中最大被分到第几组了
当我们插入一个新的y值时 我们看一下1-y中最大的被分到第几组了然后tree[y]=max+1再向上更新就行啦!
AC代码:
#include <iostream>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <algorithm>
#define MAX 100010
#define mod 1000000007
#define ll long long
using namespace std;
struct node{
int x,y;
int id;
int ans;
}p[MAX];
int tree[MAX]={0};
int lowbit(int x)
{
return (x&(-x));
}
int find(int x)
{
int ans=0;
while(x)
{
ans=max(tree[x],ans);
x-=lowbit(x);
}
return ans;
}
void insert(int x)
{
int num=find(x)+1;
tree[x]=num;
while(x<MAX)
{
tree[x]=max(tree[x],num);
x+=lowbit(x);
}
}
int cmp1(node a,node b)
{
return a.x>b.x;
}
int cmp2(node a,node b)
{
return a.id<b.id;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>p[i].x>>p[i].y;
p[i].id=i;
}
sort(p,p+n,cmp1);
int m=-1;
int now=1;
for(int i=0;i<n;i++)
{
insert(p[i].y);
p[i].ans=tree[p[i].y];
if(m<p[i].ans)
m=p[i].ans;
}
sort(p,p+n,cmp2);
cout<<m<<endl;
for(int i=0;i<n;i++)
cout<<p[i].ans<<" ";
return 0;
}
/*
5
2 2
3 1
2 1
5 5
5 4
*/
贴一个官方题解:
这个Dilworth定理是啥… (太菜了,还要多学习…)