注意到策略其实是没有用的,所以需要想一种办法加速模拟。
注意到纸币价格只有 106 10 6 ,首先用硬币能买就买,之后的操作中,尽量多用纸币,这样可以将硬币数量控制在 106 10 6 以内,不断模拟下去一定会形成环,加上记忆化就可以了。
#include
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 1000005;
const int base = 1000000;
int b, c, r, tot, mem_b[N];
LL ans, mem_ans[N];
bool mem[N];
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(b), Read(c), Read(r), Read(tot), tot += c;
ans += c / r, c %= r;
int c_small = c % base, c_large = c / base, r_small = r % base, r_large = r / base, b_need = r_large - c_large;
if (c_small < r_small) {
if (b >= b_need + 1 && tot - c_small >= base - r_small) {
b -= b_need + 1, ++ans, c = c_small - r_small + base;
} else {
printf("%lld\n", ans);
return 0;
}
} else {
if (b >= b_need) {
b -= b_need, ++ans, c = c_small - r_small;
} else {
printf("%lld\n", ans);
return 0;
}
}
while (true) {
if (mem[c]) {
break;
}
mem[c] = true, mem_b[c] = b, mem_ans[c] = ans;
if (c < r_small) {
if (b >= r_large + 1 && tot - c >= base - r_small) {
b -= r_large + 1, ++ans, c += base - r_small;
} else {
printf("%lld\n", ans);
return 0;
}
} else {
if (b >= r_large) {
b -= r_large, ++ans, c -= r_small;
} else {
printf("%lld\n", ans);
return 0;
}
}
}
LL t = b / (mem_b[c] - b);
ans += t * (ans - mem_ans[c]), b %= mem_b[c] - b;
while (true) {
if (c < r_small) {
if (b >= r_large + 1 && tot - c >= base - r_small) {
b -= r_large + 1, ++ans, c += base - r_small;
} else {
printf("%lld\n", ans);
return 0;
}
} else {
if (b >= r_large) {
b -= r_large, ++ans, c -= r_small;
} else {
printf("%lld\n", ans);
return 0;
}
}
}
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
一个性质是 LIS 和 LDS 交集的大小至多为 1 1 。
记 fi f i 表示经过 i i 的 LDS 个数, all a l l 为总的 LDS 个数。考虑不合法的 LIS 长什么样,记它为 i1,i2,⋯,ik i 1 , i 2 , ⋯ , i k ,那么所有 LDS 一定与它有交集,又因为交集不超过 1 1 ,所以交集恰好为 1 1 ,即 fi1+fi2+⋯+fik=all f i 1 + f i 2 + ⋯ + f i k = a l l 。考虑如何求这样一个 LIS ,首先可以放到模一个大质数意义下考虑,那么用树状数组求 LIS 的同时,也维护一下当前 f f 之和,维护两个不同的值就可以了,因为一个不合法必然另一个合法。
#include
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 500005;
const int mod = 1004535809;
struct Info {
int val, mod_a, mod_b, pre_a, pre_b;
Info(int val = 0, int mod_a = -1, int mod_b = -1, int pre_a = 0, int pre_b = 0):val(val), mod_a(mod_a), mod_b(mod_b), pre_a(pre_a), pre_b(pre_b) {}
} h[N];
int n, lds, lis, tot, a[N], w[N], seq[N];
pii f[N], g[N];
bool ban[N];
inline Info Merge(Info a, Info b) {
if (a.val > b.val) {
return a;
}
if (a.val < b.val) {
return b;
}
if (!~a.mod_a) {
return b;
}
if (!~a.mod_b) {
if (~b.mod_a && b.mod_a != a.mod_a) {
a.mod_b = b.mod_a, a.pre_b = b.pre_a;
} else {
a.mod_b = b.mod_b, a.pre_b = b.pre_b;
}
}
return a;
}
namespace BITA {
int b[N], c[N];
inline void Clear() {
for (int i = 1; i <= n; ++i) {
b[i] = c[i] = 0;
}
}
inline void Modify(int x, int v, int w) {
for (; x <= n; x += x & -x) {
if (CheckMax(b[x], v)) {
c[x] = 0;
}
if (b[x] == v) {
c[x] = (c[x] + w) % mod;
}
}
}
inline pii Query(int x) {
int v = 0, w = 1;
for (; x; x -= x & -x) {
if (CheckMax(v, b[x])) {
w = 0;
}
if (v == b[x]) {
w = (w + c[x]) % mod;
}
}
return mp(v, w);
}
}
namespace BITB {
Info b[N];
inline void Modify(int x, Info v) {
for (; x <= n; x += x & -x) {
b[x] = Merge(b[x], v);
}
}
inline Info Query(int x) {
Info v = Info(0, 0, -1, 0, 0);
for (; x; x -= x & -x) {
v = Merge(v, b[x]);
}
return v;
}
}
namespace BITC {
pii b[N];
inline void Modify(int x, pii v) {
for (; x <= n; x += x & -x) {
CheckMax(b[x], v);
}
}
inline pii Query(int x) {
pii v = mp(0, 0);
for (; x; x -= x & -x) {
CheckMax(v, b[x]);
}
return v;
}
}
inline void Output(int x, int y) {
while (x) {
seq[++tot] = x;
if (h[x].mod_a == y) {
y = (y - w[x] + mod) % mod;
x = h[x].pre_a;
} else {
y = (y - w[x] + mod) % mod;
x = h[x].pre_b;
}
}
reverse(seq + 1, seq + tot + 1);
printf("%d\n", lis);
for (int i = 1; i <= tot; ++i) {
printf("%d%c", seq[i], i == tot ? '\n' : ' ');
ban[seq[i]] = true;
}
printf("%d\n", lds);
for (int i = 1; i <= n; ++i) {
if (!ban[i]) {
f[i] = BITC::Query(n - a[i]);
BITC::Modify(n - a[i] + 1, mp(++f[i].X, i));
if (f[i].X == lds) {
tot = 0;
for (int x = i; x; seq[++tot] = x, x = f[x].Y);
reverse(seq + 1, seq + tot + 1);
for (int j = 1; j <= tot; ++j) {
printf("%d%c", seq[j], j == tot ? '\n' : ' ');
}
return ;
}
}
}
}
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n);
for (int i = 1; i <= n; ++i) {
Read(a[i]);
}
BITA::Clear();
for (int i = 1; i <= n; ++i) {
f[i] = BITA::Query(n - a[i]);
BITA::Modify(n - a[i] + 1, ++f[i].X, f[i].Y);
CheckMax(lds, f[i].X);
}
BITA::Clear();
for (int i = n; i; --i) {
g[i] = BITA::Query(a[i] - 1);
BITA::Modify(a[i], ++g[i].X, g[i].Y);
}
int sum = 0;
for (int i = 1; i <= n; ++i) {
if (f[i].X + g[i].X - 1 == lds) {
w[i] = 1LL * f[i].Y * g[i].Y % mod;
} else {
w[i] = 0;
}
if (f[i].X == lds) {
sum = (sum + f[i].Y) % mod;
}
}
BITA::Clear();
for (int i = 1; i <= n; ++i) {
f[i] = BITA::Query(a[i] - 1);
BITA::Modify(a[i], ++f[i].X, f[i].Y);
CheckMax(lis, f[i].X);
}
for (int i = 1; i <= n; ++i) {
h[i] = BITB::Query(a[i] - 1);
++h[i].val;
if (~h[i].mod_a) {
h[i].mod_a = (h[i].mod_a + w[i]) % mod;
}
if (~h[i].mod_b) {
h[i].mod_b = (h[i].mod_b + w[i]) % mod;
}
if (h[i].val == lis) {
if (~h[i].mod_a && h[i].mod_a != sum) {
Output(i, h[i].mod_a);
return 0;
}
if (~h[i].mod_b && h[i].mod_b != sum) {
Output(i, h[i].mod_b);
return 0;
}
}
BITB::Modify(a[i], Info(h[i].val, h[i].mod_a, h[i].mod_b, ~h[i].mod_a ? i : 0, ~h[i].mod_b ? i : 0));
}
Debug("%d %d\n", lis, lds);
puts("IMPOSSIBLE");
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
显然最优策略是走到最右端的某个点,在回来的路上吃某些餐馆。
记 fi f i 表示吃了 i i 单位食物时,最少需要消耗的能量。考虑倒着转移,不难发现只考虑 i,i+1,⋯,n i , i + 1 , ⋯ , n 时 f f 的取值至多取 ei e i ,因为每单位食物都会带来至少 i i 的代价,而走到最右端的某个点只需要在处理 f0 f 0 转移出去的时候加上代价就可以了。复杂度是调和级数。
#include
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 10000005;
int n, m, a[N], f[N];
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n), Read(m);
for (int i = 1; i <= m; ++i) {
f[i] = m + 1;
}
for (int i = 1; i <= n; ++i) {
Read(a[i]);
}
for (int i = n; i; --i) {
for (int j = m / i; j >= a[i]; --j) {
if (j == a[i]) {
CheckMin(f[j], (i << 1) + a[i] * i);
} else {
CheckMin(f[j], f[j - a[i]] + a[i] * i);
}
}
}
for (int i = m; ~i; --i) {
if (f[i] <= m) {
printf("%d\n", i);
return 0;
}
}
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
建出后缀自动机,考虑往前加字符就是在 parent p a r e n t 树上不动或者走向某个儿子,而往后加字符就是走转移边。注意到离开当前节点的时候,出现次数不会变多,那么在当前节点待到最后一定是不劣的,然后做个DP就可以了。
#include
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 400005;
int n, lst, tot, deg[N], par[N], siz[N], val[N], nxt[N][26];
vector <int> adj[N];
queue <int> q;
LL ans, f[N];
char s[N];
inline void Extend(int w) {
int p = lst, np = ++tot;
val[np] = val[p] + 1, siz[np] = 1;
for (; p && !nxt[p][w]; nxt[p][w] = np, p = par[p]);
if (!p) {
par[np] = 1;
} else {
int q = nxt[p][w];
if (val[q] == val[p] + 1) {
par[np] = q;
} else {
int nq = ++tot;
val[nq] = val[p] + 1;
memcpy(nxt[nq], nxt[q], sizeof nxt[nq]);
par[nq] = par[q], par[np] = par[q] = nq;
for (; p && nxt[p][w] == q; nxt[p][w] = nq, p = par[p]);
}
}
lst = np;
}
inline void DFS(int x) {
for (auto y : adj[x]) {
DFS(y), siz[x] += siz[y];
}
}
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n), scanf("%s", s + 1), lst = tot = 1;
for (int i = 1; i <= n; ++i) {
Extend(s[i] - 'a');
}
for (int i = 2; i <= tot; ++i) {
adj[par[i]].pb(i), ++deg[i];
}
DFS(1);
for (int i = 1; i <= tot; ++i) {
for (int j = 0; j < 26; ++j) {
if (nxt[i][j]) {
adj[i].pb(nxt[i][j]), ++deg[nxt[i][j]];
}
}
}
for (q.push(1); !q.empty(); q.pop()) {
int x = q.front();
for (auto y : adj[x]) {
CheckMax(f[y], f[x] + 1LL * (val[y] - val[x]) * siz[y]);
if (!--deg[y]) {
q.push(y);
}
}
CheckMax(ans, f[x]);
}
printf("%lld\n", ans);
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
考虑随机一个排列 q q ,然后依次让 pqi p q i 加 1 1 ,不难发现如果当前不同数个数变少了那 qi q i 一定不是 n n 。考虑一个不是 n n 的数 x x 什么情况下会被排除:当且仅当在排列 q q 中它在 x−1 x − 1 和 x+1 x + 1 前面。正确率为 (1−(23)50)1000 ( 1 − ( 2 3 ) 50 ) 1000 ,约为 1−10−6 1 − 10 − 6 ,可以通过。
#include
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 1005;
int n, m, cur, nxt, p[N];
bool v[N];
int main() {
srand(time(0));
Read(n), cur = m = n;
for (int i = 1; i <= n; ++i) {
p[i] = i;
}
while (m > 1) {
random_shuffle(p + 1, p + n + 1);
for (int i = 1; i <= n; ++i) {
printf("0 %d\n", p[i]);
fflush(stdout);
Read(nxt);
if (nxt < cur) {
if (!v[p[i]]) {
v[p[i]] = true, --m;
}
}
cur = nxt;
}
}
for (int i = 1; i <= n; ++i) {
if (!v[i]) {
printf("1 %d\n", i);
fflush(stdout);
return 0;
}
}
return 0;
}
两个数不冲突当且仅当模数不是它们差的约数,做一次 FFT 求出所有可能的差,然后枚举答案即可。
#include
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 4194305;
const int M = 25;
const double pi = acos(-1);
struct E {
double x, y;
E(double x = 0, double y = 0):x(x), y(y) {}
E operator + (const E &b) const {
return E(x + b.x, y + b.y);
}
E operator - (const E &b) const {
return E(x - b.x, y - b.y);
}
E operator * (const E &b) const {
return E(x * b.x - y * b.y, x * b.y + y * b.x);
}
} I[N], W[N], X[N], Y[N];
int D, L, R[N];
inline void Ini(int n) {
for (D = 1, L = 0; D < n; D <<= 1, ++L);
for (int i = 1; i < D; ++i) {
R[i] = (R[i >> 1] >> 1) | ((i & 1) << L - 1);
}
for (int i = 0; i < D; ++i) {
W[i] = I[i] = E(cos(2 * pi * i / D), sin(2 * pi * i / D)), I[i].y = -I[i].y;
}
}
inline void DFT(E *X, E *W) {
for (int i = 0; i < D; ++i) {
if (i < R[i]) {
swap(X[i], X[R[i]]);
}
}
for (int i = 1, l = L - 1; i < D; i <<= 1, --l) {
for (int j = 0; j < D; j += i << 1) {
for (int k = 0; k < i; ++k) {
E u = X[j + k], v = X[j + k + i] * W[k * (1 << l)];
X[j + k] = u + v, X[j + k + i] = u - v;
}
}
}
}
inline vector <int> Mul(vector <int> a, vector <int> b) {
int n = a.size(), m = b.size();
vector <int> c(n + m - 1, 0);
Ini(n + m - 1);
for (int i = 0; i < D; ++i) {
X[i] = i < n ? E(a[i], 0) : E(0, 0);
Y[i] = i < m ? E(b[i], 0) : E(0, 0);
}
DFT(X, W), DFT(Y, W);
for (int i = 0; i < D; ++i) {
X[i] = X[i] * Y[i];
}
DFT(X, I);
for (int i = 0; i < n + m - 1; ++i) {
c[i] = X[i].x / D + 0.5;
}
return c;
}
int n, m, a[N], b[N];
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n);
for (int i = 1, x; i <= n; ++i) {
Read(x), CheckMax(m, x), a[x] = 1;
}
for (int i = 1; i <= m; ++i) {
if (a[i]) {
b[m - i] = 1;
}
}
vector <int> c = Mul(vector <int> (a, a + m + 1), vector <int> (b, b + m + 1));
for (int i = 1; i <= m; ++i) {
if (c[i + m]) {
a[i] = 1;
} else {
a[i] = 0;
}
}
for (int i = 1; i <= m; ++i) {
bool f = false;
for (int j = i; j <= m; j += i) {
f |= a[j];
}
if (!f) {
printf("%d\n", i);
return 0;
}
}
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}