[题解]Viva la vida!

校长者,真神人也,左马桶,右永神,会执利笔破邪炁,何人当之?The principal is really a godwith a closestool on the left and Yongshen on the rightholding a sharp pen to pierce the truthWho can resist him? 校長は本当に神であり、左側にトイレ、右側にヨンシェンがあり鋭いペンを持って真実を突き刺している。誰が彼に抵抗できるだろうか? Le principal est vraiment un dieuavec des toilettes à gauche et Yongshen à droitetenant un stylo pointu pour percer la véritéQui peut lui résister ? Der Direktor ist wirklich ein Gottmit einer Toilette links und Yongshen rechtsder einen spitzen Stift hältum die Wahrheit zu durchdringen.Wer kann ihm widerstehen? Principalis deus est, Yongshen a dextris cum latrinaacuto stylo ad perforandum veritatem: quis resistet ei? 对曰:“无人,狗欲当之,还请赐教!”




  BackToTheMenu.

2022-03-11 Viva la vida!

  T1 拿来搞笑的吧?T2 知道 O(n2) 还转不到正解上面去......T3 就没怎么想了。

王 / King

I used to roll the dice

过去我常常孤注一掷


Feel the fear in my enemy's eyes

尽情品味惊恐在死敌瞳孔绽开


Listen as the crowd would sing:

欣然倾听百姓高歌喝彩


"Now the old king is dead! Long live the king!"

“先王亡矣!新王万代!”

  从 0 开始倒着考虑,那么原题就相当于分别用长度为 1,2,3, 的全 1 串去异或当前的串,也可以不异或。

  做一遍 dijkstra 就行了,同时不难发现一定有解且小于等于 16,因为当长度为 16 时线性基满秩。

/** @author __Elaina__ */

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

// #define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define curse(...) fprintf(stderr, __VA_ARGS__)

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {;
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int Maxn = 16;
const int n = 16;
const int Maxs = 1 << Maxn;

int dis[Maxs + 5];
priority_queue<pii, vector<pii>, greater<pii>> Q;
inline void dijkstra() {
    memset(dis, 0x3f, sizeof dis);
    Q.push({dis[0] = 0, 0});
    while (!Q.empty()) {
        int s = Q.top().se, d = Q.top().fi; Q.pop();
        if (d > dis[s]) continue;
        repf (i, 0, n) {
            rep (len, 0, i) {
                if (len < i && dis[s] > len) continue;
                int to = ((2 << len) - 1) << (i - len), w = max(dis[s], len) + 1;
                to ^= s;
                if (dis[to] > w) Q.push({dis[to] = w, to});
            }
        }
    }
}

signed main() {
    freopen("roll.in", "r", stdin);
    freopen("roll.out", "w", stdout);
    cin.tie(NULL)->sync_with_stdio(false);
    dijkstra();
    int s, t; char reci[Maxn + 5];
    cin >> t; while (t--) {
        cin >> reci;
        repf (i, s = 0, strlen(reci)) s = s << 1 | (reci[i] ^ 48);
        writln(dis[s]);
    }
    return 0;
}

落幕 / Fading

One minute I held the key

曾经我手握权位经脉


Next the walls were closed on me

如今才知宫墙深似海


And I discovered that my castles stand

恍然发现我的城池


Upon pillars of salt, pillars of sand

基底散如盐沙乱似尘埃

  可以发现一些性质,比如说有解的充要条件是 kai,比如说如果 [a,b] 有解,[b+1,c] 有解,那么 [l1,r2] 一定有解,并且若设 g(l,r) 表示区间 [l,r] 的答案,那么 g(a,c)=g(a,b)+g(b+1,c),这告诉我们,对于一个右端点,我们实际上只需要计算与它最近的那个 l 且保证 [l,r] 有解的 l,而这样的区间是线性的,如果每一对我们可以快速地计算,那么最后的处理就非常容易了。

  分析到这里就有一个 O(n2) 的算法,每次枚举一个左端点,然后计算所有右端点的花费。

  不难发现上面的暴力的瓶颈在于,我们知道 [l,r] 有解,但是计算 g(l,r) 花费了我们大量的时间,考虑快速地计算它:显然我们应当给每个需要的数定向,是向上还是向下凑成 k 的倍数,然后每个数就有 冗余售罄 两种情况,花费就是将 冗余 部分转移到 售罄 地方的总花费。

  十分容易可以证明,用 冗余 去补充 售罄,最小花费一定是先贪心地将最近的两个进行补充,然后再次近的......但是这样做显然不是特别好,问题有两个:一,如何将每个点定成 冗余 还是 售罄,二,即使可以确定,计算花费也不是特别方便。

  考虑从另外的方面进行计算,如果我们将前缀和看成条状,那么每一次修改就是将某个条拔高或者降低,并且其他的条不受到影响,而目标状态是让每个条的高度变成 k 的倍数,那么这个花费就很好计算了,记这个数列的前缀和对 k 取模之后为 prei,那么总花费就是

i=1lenmin{prei,kprei}

  记原序列的前缀和对 k 取模为 si,那么,对于每一个右端点,找到最近的 l 使得 sl1=sr,计算 [l,r] 的贡献,和上面相似,就是

i=lrmin{sisl1,k(sisl1)}(mod9998244353)

  注意 min 里面的运算都要对 k 取模。这个式子的计算,实际上可以分成两个部分,记 xi=sisl1,那么我们找到 [l,r] 中有多少 xi[0,k2],这些直接取值,另外的就用 k 乘以个数减去和即可。实现可以使用主席树。

  代码细节有亿点多,但是应该是我写丑了。

/** @author __Elaina__ */

#pragma GCC optimize("Ofast")

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

#define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define masdf(...) fprintf(stderr, __VA_ARGS__)

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {;
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int Maxn = 1e6;
const int Maxk = 1e8;
const int logk = 30;
const int mod = 998244353;
inline void chkadd(int& x, int y) { if ((x += y) >= mod) x -= mod; }

int n, k;
int a[Maxn + 5];

inline void input() {
    readin(n, k);
    rep (i, 1, n) readin(a[i]);
}

namespace saya {
    
const int Maxn = ::Maxn * logk;

int ncnt;
int cnt[Maxn + 5], sum[Maxn + 5];
int ls[Maxn + 5], rs[Maxn + 5];

#define mid ((l + r) >> 1)
#define _lhs ls[i], l, mid
#define _rhs rs[i], mid + 1, r

inline int copy(int x) {
    int i = ++ncnt;
    tie(cnt[i], sum[i], ls[i], rs[i]) = tie(cnt[x], sum[x], ls[x], rs[x]);
    return i;
}

void modify(int p, int& i, int l = 0, int r = Maxk - 1) {
    i = copy(i), ++cnt[i], chkadd(sum[i], p);
    if (l == r) return ;
    if (p <= mid) modify(p, _lhs);
    else modify(p, _rhs);
}

inline void add(pii& x, pii y) { x.fi += y.fi, chkadd(x.se, y.se); }
pii query(int ql, int qr, int x, int y, int l = 0, int r = Maxk - 1) {
    if (ql > qr) return {0, 0};
    if (ql <= l && r <= qr) return {cnt[y] - cnt[x], (sum[y] + mod - sum[x]) % mod};
    pii ret = {0, 0};
    if (ql <= mid) ret = query(ql, qr, ls[x], ls[y], l, mid);
    if (mid < qr) add(ret, query(ql, qr, rs[x], rs[y], mid + 1, r));
    return ret;
}

#undef mid
#undef _lhs 
#undef _rhs 

};

int rt[Maxn + 5], s[Maxn + 5];
int reals[Maxn + 5];
inline void buildTree() {
    rep (i, 1, n) {
        s[i] = (s[i - 1] + a[i]) % k;
        reals[i] = (reals[i - 1] + s[i]) % mod;
        saya::modify(s[i], rt[i] = rt[i - 1]);
    }
}

int val[Maxn + 5];

inline int solve(int l, int r) {
    int mov = s[l - 1], les_cnt, gre_cnt, les_sum, gre_sum;
    if (mov + (k >> 1) < k) {
        int ql = mov, qr = mov + (k >> 1);
        auto ret = saya::query(ql, qr, rt[l - 1], rt[r]);
        tie(les_cnt, les_sum) = ret;
        gre_cnt = (r - l + 1) - les_cnt;
        gre_sum = ((0ll + reals[r] - reals[l - 1] - les_sum) % mod + mod) % mod;
        int number = saya::query(0, ql - 1, rt[l - 1], rt[r]).fi;
        les_sum = ((0ll + les_sum - 1ll * les_cnt * mov) % mod + mod) % mod;
        gre_sum = ((0ll + gre_sum + 1ll * k * number - 1ll * gre_cnt * mov) % mod + mod) % mod;
    }
    else {
        int ql = ((k >> 1) + 1 + mov) % k, qr = (k - 1 + mov) % k;
        auto ret = saya::query(ql, qr, rt[l - 1], rt[r]);
        tie(gre_cnt, gre_sum) = ret;
        les_cnt = (r - l + 1) - gre_cnt;
        les_sum = ((0ll + reals[r] - reals[l - 1] - gre_sum) % mod + mod) % mod;
        int number = saya::query(0, ql - 1, rt[l - 1], rt[r]).fi;
        les_sum = ((0ll + les_sum + 1ll * k * number - 1ll * les_cnt * mov) % mod + mod) % mod;
        gre_sum = ((0ll + gre_sum + 1ll * k * gre_cnt - 1ll * gre_cnt * mov) % mod + mod) % mod;
    }
    chkadd(les_sum, ((1ll * k * gre_cnt - gre_sum) % mod + mod) % mod);
    return les_sum;
}
map<int, int> pre;
int tol[Maxn + 5];
inline void prelude() {
    pre[0] = 0;
    rep (i, 1, n) {
        if (pre.count(s[i])) val[i] = solve(pre[s[i]] + 1, i), tol[i] = pre[s[i]];
        else val[i] = tol[i] = -1;
        pre[s[i]] = i;
    }
}

int ans = 0;
int f[Maxn + 5];
inline void getAns() {
    pre.clear(), pre[0] = 1;
    rep (i, 1, n) {
        chkadd(ans, 1ll * (mod - 1) * (i - pre[s[i]]) % mod);
        if (~tol[i]) {
            f[i] = 1ll * val[i] * pre[s[i]] % mod;
            chkadd(f[i], f[tol[i]]);
        }
        ++pre[s[i]];
        chkadd(ans, f[i]);
    }
    writln(ans);
}

signed main() {
    freopen("win.in", "r", stdin);
    freopen("win.out", "w", stdout);
    input();
    buildTree();
    prelude();
    getAns();
    return 0;
}

终焉 / Ending

Shattered windows and the sound of drums

断壁残垣礼崩乐坏


People couldn't believe what I'd become

世人不敢相信我已当年不再


Revolutionaries Wait

起义大军翘首期待


For my head on a silver plate

有朝一日我站上断头台

  转化之后将会变成一个很简单的问题,可是我并没有想到去转化......概率期望题还是多想想能不能转化再说。

  判断最优策略:在当前的手牌可以弑君再出牌。

  然后将赢的局数的期望转变一下:1+++

  注意到

1+i=1+i=1+

  于是我们可以只关注抽排序列有哪些牌。

  1. 只有毒药:在 n 张牌以内都无法获胜,P1=i=1n13i=113n2
  2. 只有火球,在 m=n12 张牌以内无法获胜,P2=i=1m13i=113m2
  3. 只有复读,无法获胜,P3=i=1+13i=12
  4. 毒药加火球,比较复杂,定义 f(0/1,0/1,s) 表示当前是否使用毒药,是否使用火球,造成 s 伤害的概率,最后的概率就是 P4=i=1n1f(1,1,i)
  5. 毒药加复读,相当于毒药伤害为 1,复读伤害为 2,与上面的 DP 类似;
  6. 复读加上火球,其实和全是火球一样,但是要注意排除全是火球或者复读的情况,因此这一部分的概率为 P6=i=1m2i23i=2(1(23)m)(113m)
  7. 毒药加火球加复读,类似地,毒药为 1,火球为 3,复读为 4 就行了;

  注意到 4,5,7 的前缀和都是线性递推的形式,因此可以使用矩阵加速进行优化,可以把他们仨放到一个大矩阵中进行递推,这样比较方便,矩阵大小不超过 20 吧,因此复杂度大概就是 O(T×203logn).

  但是无码。

posted @   Arextre  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2020-03-14 「模板」替罪羊树
点击右上角即可分享
微信分享提示