HGOI 20200730

水题大作战

T1 bread

一眼线段树

出题人没有把线段树卡掉,那么为什么不用呢

裸的,倒着做

#include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second

const int N = 1000010 ;

int n, m, p, q ;
int f[4 * N], ans[N] ;


void update(int u, int l, int r, int ql, int qr, int v) {
	if (f[u] != 0) return ;
	if (ql <= l && r <= qr) f[u] = v ;
	if (l == r) return ;
	int mid = (l + r) >> 1 ;
	if (ql <= mid) update(2 * u, l, mid, ql, qr, v) ;
	if (mid < qr) update(2 * u + 1, mid + 1, r, ql, qr, v) ;
}

void query(int u, int l, int r) {
	if (l == r) {
		ans[l] = f[u] ;
		return ;
	} 
	int mid = (l + r) >> 1 ;
	query(u * 2, l, mid) ;
	query(u * 2 + 1, mid + 1, r) ;
} 

void print(int x) {
    if (x > 9) print(x / 10) ;
    putchar(x % 10 + '0') ;
}

signed main() {
	freopen("bread.in", "r", stdin) ;
	freopen("bread.out", "w", stdout) ;
	scanf("%d%d%d%d", &n, &m, &p, &q) ;
	memset(f, 0, sizeof(f)) ;
	per(i, m, 1) {
		int ql = (i * p + q) % n + 1, qr = (i * q + p) % n + 1, v = i ;
		if (ql > qr) swap(ql, qr) ;
		update(1, 1, n, ql, qr, v) ;
	}
	query(1, 1, n) ;
	rep(i, 1, n) print(ans[i]), putchar('\n') ;
	return 0 ;
}

T2 divide

稍微有点意思

暴力背包80

稍微优化可得100

换种思路

Dp[i]表示和为i时j物品剩余的个数,如果不合法为-1

#include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second

const int N = 20010 ;

int sum ;
int a[N] ;
int f[N] ;

signed main() {
	freopen("divide.in", "r", stdin) ;
	freopen("divide.out", "w", stdout) ; 
	int t ; scanf("%d", &t) ;
	while (t--) {
		rep(i, 1, 6) scanf("%d", &a[i]) ;
		sum = 0 ;
		rep(i, 1, 6) sum += a[i] * i ;
		if (sum % 2) {
			puts("Can't be divided.") ;
			continue ;
		}
		sum /= 2 ;
		f[0] = 0 ;
        rep(i, 1, sum) f[i] = -1 ;
        rep(i, 1, 6) 
		rep(j, 0, sum) {
			if (f[j] >= 0) f[j] = a[i] ;
	        else if (i <= j) f[j] = f[j - i] - 1 ;
	        else f[j] = -1 ;
	    }
        if (f[sum] >= 0) puts("Can be divided.");
        else puts("Can't be divided.");
	}
	return 0 ;
}
/*
3
1 0 1 2 0 0
1 0 1 1 0 0
1 1 3 1 1 1
*/

T3 cmi

很明显答案为n-最长上升子序列元素个数

用树状数组优化O(nlogn)

#include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second

const int N = 200030 ;

int n ;
int bit[N], a[N], dp[N] ;

void mdf(int p, int v) {
	for (; p <= n + 5; p += p & -p) bit[p] = max(bit[p], v) ;
}

int ask(int p) {
	int ans = 0 ;
	for (; p; p -= p & -p) ans = max(ans, bit[p]) ;
	return ans ;
}

signed main() {
	freopen("cmi.in", "r", stdin) ;
	freopen("cmi.out", "w", stdout) ;
	scanf("%d", &n) ;
	rep(i, 1, n) scanf("%d", &a[i]), a[i]++ ;
	memset(bit, -0x3f, sizeof(bit)) ;
	rep(i, 1, n) {
		dp[i] = 1 ;
		dp[i] = max(dp[i], ask(a[i] - 1) + 1) ;
		mdf(a[i], dp[i]) ;
	}
	int ans = 0 ;
	rep(i, 1, n) ans = max(ans, dp[i]) ;
	printf("%d\n", n - ans) ;
	return 0 ;
}

posted @ 2020-07-30 16:34  harryhqg  阅读(103)  评论(0编辑  收藏  举报