[Ybt 금메달 탐색 1-2-3] 파선 통계

파선 통계

주제 링크 : ybt 금메달 내비게이션 1-2-3

이야기

그래프에 몇 개의 점이 있으므로 두 점의 수평 및 수직 좌표가 동일하지 않습니다.
일부 세트를 선택하고 x 좌표 순서로 연결하면 일부 연속 상승 및 하강 폴리 라인이 형성되고 폴리 라인 수가 k 인 경우 충족되는 세트 수를 묻는 메시지가 표시됩니다.
수량은 모듈로 100007입니다.

아이디어

이 질문에 대해서는 일반 dp로하는 방법을 고려해 보겠습니다.

xx를 누르기 때문에x 좌표가 나란히 연결된 다음 먼저xx를누릅니다.x 좌표는 가장 작은 것부터 가장 큰 것까지 정렬됩니다. 여기에서 세트를 선택하면 여기에 연결된 세트가 연결되어야합니다.

그런 다음 fi, j, k f_ {i, j, k}를 설정합니다.에프I , J , K为前iii 포인트를 선택해야합니다.iijj를 형성하기 위해 점 i 에서 선택됨j 세그먼트이고 마지막 세그먼트의 상태는kk입니다.k。 (kkk0 0상승0 상하11 두 가지 값)
전달 방정식은 먼저 상승과 하강으로 나눈 다음 원래의 마지막 단계와 같거나 다르다고 생각하기 쉽습니다.

먼저 오름차순이됩니다. 즉, 전송 후 k = 0 k = 0입니다.케이=0 상황.
변경되지 않으면 세그먼트 수가 변경되지 않으며 첫 번째 차원은1 1을열거해야합니다.1 도래i - 1 i-1나는1 ,kkk 또는000 .
변경되면 세그먼트 수가 증가하고 원본은− 1 -1이됩니다.1 , 첫 번째 차원은 여전히 ​​열거 형1 ∼ i − 1 1 \ sim i-11~나는1 , 원래kkk1이됩니다.1

그것은 쇠퇴가되며 이는 같은 이유입니다.
그러나 첫 번째 차원은 열거 형이 아닙니다. 1 ∼ i − 1 1 \ sim i-11~나는1 ,하지만i + 1 ∼ 100000 i + 1 \ sim 100000나는+1~1 0 0 0 0 0 높은 값에서 낮은 값으로 변경하기 때문입니다.

초기화는 fi, 0, 0 = fi, 0, 1 = 1 f_ {i, 0,0} = f_ {i, 0,1} = 1에프I , 0 , 0=에프I , 0 , 1=1

그러나 열거 시간이 초과됩니다.
그런 다음 일부 데이터 구조로 최적화하는 것을 고려합니다.
이를 위해서는 간격 합계와 단일 포인트 업데이트 값이 필요하며 트리 배열 사용을 생각하기 쉽습니다.
그런 다음 1 ∼ i − 1 1 \ sim i-1을 열거합니다.1~나는1i − 1 i-1을 직접 쿼리하는 것입니다.나는1 ,i + 1 ∼ 100000 i + 1 \ sim 100000의 위치나는+1~1 0 0 0 0 0 , 쿼리100000 100000 사용1 0 0 0 0 0 마이너스 쿼리iii 의 결과 값. (접두사 합의 아이디어)

그런 다음 기본적으로 괜찮습니다. 모듈로를 사용하는 것을 잊지 마십시오.

암호

#include<cstdio>
#include<algorithm>
#define mo 100007
#define ll long long

using namespace std;

struct node {
    
    
	int x, y;
}zb[100001];
int n, k;
ll f[50001][11][2], tree[100001][11][2], re, ans;

bool cmp(node X, node Y) {
    
    
	return X.x < Y.x;
}

void add(int now, int j, int k, ll add_num) {
    
    //树状数组操作
	for (int i = now; i <= 100000; i += i & (-i))
		tree[i][j][k] = (tree[i][j][k] + add_num) % mo;
}

ll get(int now, int j, int k) {
    
    
	re = 0;
	for (int i = now; i; i -= i & (-i))
		re = (re + tree[i][j][k]) % mo;
	return re;
}

int main() {
    
    
	scanf("%d %d", &n, &k);
	
	for (int i = 1; i <= n; i++) {
    
    
		scanf("%d %d", &zb[i].x, &zb[i].y);
	}
	
	sort(zb + 1, zb + n + 1, cmp);//按 x 坐标排序
	
	f[0][0][0] = 1;
	f[0][0][1] = 1;
	for (int i = 1; i <= n; i++) {
    
    
		f[i][0][0] = 1;
		f[i][0][1] = 1;
		
		add(zb[i].y, 0, 0, 1);
		add(zb[i].y, 0, 1, 1);//初始化
		
		for (int j = 1; j <= k; j++) {
    
    
			f[i][j][0] = (get(zb[i].y - 1, j, 0) + get(zb[i].y - 1, j - 1, 1)) % mo;
			//可以是跟前面一样上升,也可以变换,成为新的一段
			f[i][j][1] = ((get(100000, j, 1) - get(zb[i].y, j, 1) + get(100000, j - 1, 0) - get(zb[i].y, j - 1, 0)) % mo + mo) % mo;
			//同理,可以跟前面一样下降,也可以变换,由原来的上升变成下降
			//不过因为你是要下降,那你就要用全部减去上升的,才可以得到下降的
			//树状数组搞的是上升的,那如果你找 100000,就是最大值的话,就所有都找了一遍,就是全部的了
			//或者说这就是前缀和的思想
			
			add(zb[i].y, j, 0, f[i][j][0]);
			add(zb[i].y, j, 1, f[i][j][1]);
			//放进树状数组里面
		}
		
		ans = (ans + f[i][k][0]) % mo;//统计答案
		ans = (ans + f[i][k][1]) % mo;
	}
	
	printf("%lld", ans);
	
	return 0;
}

추천

출처blog.csdn.net/weixin_43346722/article/details/113107512