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 ;
}
加油ヾ(◍°∇°◍)ノ゙