省选测试1
我好菜啊
A 翻转硬币
题目大意 : 给定每次可以翻的长度,有m种,问最后把这些硬币翻到指定状态的最少次数
-
原题。翻转一段区间复杂度太大,如果用差分的话就只需要改变 l 和 r+1 处的值
-
先把需要的状态转换为差分数组,翻转一段区间就会把两端的值(l和r+1)改掉,如果两端都是0的话没必要改,只有有1的时候才需要改
-
把差分数组中为1的提出来,可以BFS预处理出来将两个点改掉需要的最小步数,进行DP
-
把这些点的状态压为 s, 1表示还没消除,f[s]表示从全集到当前状态所需的最小步数,每次转移挑一个点和其它点匹配进行消除,最后f[0]即为答案
Code
Show Code
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N = 1e4 + 5;
int read(int x = 0, int f = 1, char c = getchar()) {
for (; c < '0' || c > '9'; c = getchar())
if (c == '-') f = -1;
for (; c >='0' && c <='9'; c = getchar())
x = x * 10 + c - '0';
return x * f;
}
int n, k, m, a[105], p[25], tot, d[N], c[25][25], q[N], l, r, f[1<<20|5];
bool b[N];
int main() {
n = read() + 1; k = read(); m = read();
for (int i = 1; i <= k; ++i) {
int x = read();
b[x] ^= 1; b[x+1] ^= 1;
}
for (int i = 1; i <= m; ++i)
a[i] = read();
for (int i = 1; i <= n; ++i)
if (b[i]) p[++tot] = i;
for (int i = 1; i <= tot; ++i) {
memset(d, 0x3f, n * 4 + 4);
d[p[i]] = 0; q[l=r=1] = p[i];
while (l <= r) {
int x = q[l++];
for (int j = 1, y; j <= m; ++j) {
if ((y = x + a[j]) <= n && d[y] > 1e9)
d[y] = d[x] + 1, q[++r] = y;
if ((y = x - a[j]) >= 1 && d[y] > 1e9)
d[y] = d[x] + 1, q[++r] = y;
}
}
for (int j = 1; j <= tot; ++j)
c[i][j] = d[p[j]];
}
int s = (1 << tot) - 1;
memset(f, 0x3f, s * 4);
for (; s >= 1; --s) {
int j;
for (j = 1; !((s >> j - 1) & 1); ++j);
for (int i = j + 1; i <= tot; ++i) {
if (!((s >> i - 1) & 1)) continue;
int t = s ^ ((1 << i - 1) + (1 << j - 1));
f[t] = std::min(f[t], f[s] + c[i][j]);
}
}
printf("%d\n", f[0] > 1e9 ? -1 : f[0]);
return 0;
}
B 一起自习的日子 (Unaccepted)
题目大意 :
- 咕咕咕
Code
Show Code
C Sanrd
题目大意 : 求一个排列的一个LIS 和 LDS,满足找出的两个子序列没有交集
-
首先要知道一个排列的任意一个 LIS 和 LDS 最多只会有一个地方重合
-
求出s[i]表示经过位置 i 的 lds 的数量,注意这个方案数会非常大,所以要对一个大质数取模
-
然后找Lis,要满足经过的点的 s 的和不能等于 LDS 的总数 sum
-
用树状数组维护
Code
Show Code
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N = 5e5 + 5, M = 1e9 + 7;
int read(int x = 0, int f = 1, char c = getchar()) {
for (; c < '0' || c > '9'; c = getchar())
if (c == '-') f = -1;
for (; c >='0' && c <='9'; c = getchar())
x = x * 10 + c - '0';
return x * f;
}
int n, a[N], lis, lds, len1[N], len2[N], stk[N], tp, g[N];
int num1[N], num2[N], sum, s[N];
bool v[N];
struct Node1 {
int m, num;
Node1() { m = num = 0; }
}t1[N];
void Add1(int x, int w, int num) {
for (; x <= n; x += x & -x) {
if (w > t1[x].m) t1[x].m = w, t1[x].num= num;
else if (w == t1[x].m && (t1[x].num += num) >= M) t1[x].num -= M;
}
}
Node1 Ask1(int x) {
Node1 ans; ans.num = 1;
for (; x; x -= x & -x) {
if (t1[x].m > ans.m) ans = t1[x];
else if (t1[x].m == ans.m && (ans.num += t1[x].num) >= M) ans.num -= M;
}
return ans;
}
struct Node2 {
int m, p1, p2, n1, n2;
Node2() {m = p1 = p2 = 0; n1 = n2 = -1;}
}t2[N], f[N];
void operator += (Node2 &a, const Node2 &b) {
if (b.m > a.m) a = b;
if (b.m == a.m && a.n2 == -1) {
if (b.n1 != a.n1) a.n2 = b.n1, a.p2 = b.p1;
else if (b.n2 != -1 && b.n2 != a.n1) a.n2 = b.n2, a.p2 = b.p2;
}
}
void Add2(int x, int k, Node2 w) {
w.p1 = w.p2 = k;
for (; x <= n; x += x & -x) t2[x] += w;
}
Node2 Ask2(int x) {
Node2 ans;
for (; x; x -= x & -x) ans += t2[x];
return ans;
}
void Add3(int x, int w, int k) {
for (; x <= n; x += x & -x)
if (w > t1[x].m) t1[x].m = w, t1[x].num = k;
}
Node1 Ask3(int x) {
Node1 ans;
for (; x; x -= x & -x)
if (t1[x].m > ans.m) ans = t1[x];
return ans;
}
int main() {
n = read();
for (int i = 1; i <= n; ++i)
a[i] = read();
for (int i = 1; i <= n; ++i) {//LIS
int x = Ask1(a[i]).m + 1; Add1(a[i], x, 0);
lis = std::max(lis, x);
}
memset(t1 + 1, 0, sizeof(Node1) * n);
for (int i = 1; i <= n; ++i) {//LDS ending with i
Node1 x = Ask1(n - a[i] + 1); x.m++;
Add1(n - a[i] + 1, len1[i] = x.m, num1[i] = x.num);
lds = std::max(lds, len1[i]);
}
memset(t1 + 1, 0, sizeof(Node1) * n);
for (int i = n; i >= 1; --i) {//LDS starting with i
Node1 x = Ask1(a[i]); x.m++;
Add1(a[i], len2[i] = x.m, num2[i] = x.num);
}
for (int i = 1; i <= n; ++i) {
if (len1[i] + len2[i] == lds + 1) s[i] = 1ll * num1[i] * num2[i] % M;
if (len1[i] == lds && (sum += num1[i]) >= M) sum -= M;
}
for (int i = 1; i <= n; ++i) {//find the lis that meets the condition
Node2 &x = f[i] = Ask2(a[i]); x.m++;
if (x.n1 == -1) x.n1 = s[i];
else if ((x.n1 += s[i]) >= M) x.n1 -= M;
if (x.n2 != -1 && (x.n2 += s[i]) >= M) x.n2 -= M;
Add2(a[i], i, x);
if (x.m == lis && (x.n1 != sum || (x.n2 != -1 && x.n2 != sum))) {
int p = i;
while (p) {
int last = stk[++tp] = p; v[p] = 1;
p = sum != f[p].n1 ? f[p].p1 : f[p].p2;
if ((sum -= s[last]) < 0) sum += M;
}
printf("%d\n", lis);
while (tp) printf("%d ", stk[tp--]);
memset(t1 + 1, 0, sizeof(Node1) * n);
for (i = n; i >= 1; --i) {
if (v[i]) continue;
Node1 y = Ask3(a[i]); y.m++;
g[i] = y.num;
Add3(a[i], y.m, i);
if (y.m == lds) {
printf("\n%d\n", lds);
for (int q = i; q; q = g[q])
printf("%d ", q);
return 0;
}
}
}
}
puts("-1");
return 0;
}