首页 > 其他分享 >ABC380题解(F&G)

ABC380题解(F&G)

时间:2024-11-16 21:57:14浏览次数:1  
标签:int 题解 s1 s3 ABC380 s2 qry ll

ABC380F. Exchange Game

因为 \(n+m+k\leq 12\),考虑状压 dp,设 \(f(x,s1,s2,s3)\) 表示 先手,后手,桌子上的牌分别是哪一些,这有 \(O(3^n)\) 种状态。

然后只要枚举出哪一张即可,有

  • \(f(s1,s2,s3)\to f(s2,s1-i+j,s3+i-j)(i\in s1,j\in s3,a_j<a_i)\)
  • \(f(s1,s2,s3)\to f(s2,s1-i,s3+i)(i\in s1)\)

其中 \(x\to y\) 表示 \(y:=y\operatorname{or}\lnot x\)。

如果直接 map 记录,复杂度 \(O(n^33^n)\),可以过但是不够快。

只要预处理出 \(s=(S)_2\) 在三进制表示的值 \(h_s=(S)_3\) 即可。

那么 \(f(s1,s2,s3)=g(h_{s2}+2h_{s3})\),复杂度 \(O(n^23^n)\)。

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

const int N = 12, M = 6e5;
int a[N], n;

int f[M], pw[N], ss[1 << N];
inline int get(int s1, int s2, int s3) { return ss[s2] + ss[s3] * 2; }

bool dfs(int s1, int s2, int s3)
{
    if(!s1) return 0;
    int S = get(s1, s2, s3);
    if(f[S] != -1) return f[S];
    bool ok = 0;
    for(int i = 0; i < n; i ++)
        if((s1 >> i) & 1)
        {
            for(int j = 0; j < n; j ++)
                if(a[j] < a[i] && ((s3 >> j) & 1))
                    ok |= !dfs(s2, s1 ^ (1 << i) ^ (1 << j), s3 ^ (1 << i) ^ (1 << j));
            ok |= !dfs(s2, s1 ^ (1 << i), s3 ^ (1 << i));
        }
    return f[S] = ok;
}

signed main()
{
    pw[0] = 1; for(int i = 1; i < N; i ++) pw[i] = pw[i - 1] * 3;
    for(int i = 0; i < (1 << N); i ++)
        for(int j = 0; j < N; j ++)
            ss[i] += pw[j] * ((i >> j) & 1);
    ios::sync_with_stdio(0);cin.tie(0);
    int x, y, z; cin >> x >> y >> z;
    n = x + y + z;
    for(int i = 0; i < n; i ++) cin >> a[i];
    int s1 = 0, s2 = 0, s3 = 0;
    s1 = (1 << x) - 1;
    s2 = (1 << y) - 1;
    s3 = (1 << z) - 1;
    s2 <<= x;
    s3 <<= x + y;
    memset(f, -1, sizeof f);
    if(dfs(s1, s2, s3))
        cout << "Takahashi";
    else cout << "Aoki";

    return 0;
}

ABC380G. Another Shuffle Window

考虑怎么快速计算任意 \(i\) 下的逆序对期望。把排列分割成 \([1,i)[i,i+k)[i+k,n]\) 三段。记为 \([1][2][3]\),把整个排列记为 \(p\)。

答案即为 \(E(1,1)+E(1,2)+E(1,3)+E(2,3)+E(3,3)+Ek\)。

其中 \(E(x,y)\) 表示 \(x\) 和 \(y\) 构成的逆序对数,\(Ek\) 表示长为 \(k\) 的排列的期望逆序对数,有 \(Ek=\dfrac{k(k-1)}{4}\)。

考虑稍微容斥一下:

\[\begin{aligned} Ans&=(E(1,1)+E(1,2)+E(1,3))+(E(1,3)+E(2,3)+E(3,3))-E(1,3)+Ek\\ &=E(1,p)+E(p,3)+Ek-E(1,3) \end{aligned} \]

然后预处理 \(2n\) 个 \(E(p,x),E(x,p)\),现在的问题是求 \(E(1,3)\)。

发现在从左到右增加 \(i\) 的过程中,可以通过两个树状数组维护 \([1][3]\) 里的值,然后直接做查询即可。

复杂度 \(O(n\log n)\)。

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

const int N = 2e5 + 5, p = 998244353;
int n, a[N], k, pre[N], suf[N];
ll sp[N], ss[N];

constexpr ll qpow(ll a, ll b)
{
    if(!b) return 1;
    return ((b & 1) ? a : 1ll) * qpow(a * a % p, b >> 1) % p;
}

constexpr ll inv4 = qpow(4, p - 2);

struct BIT {
    int a[N];
    void upd(int q, int v) {for(int i = q; i < N; i += (i & -i)) a[i] += v;}
    int qry(int q) {int ans = 0; for(int i = q; i; i -= (i & -i)) ans += a[i]; return ans; }
    int qry(int ql, int qr) {return qry(qr) - qry(ql - 1);}
} t, t2;

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n >> k;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    for(int i = 1; i <= n; i ++)
    {
        pre[i] = t.qry(a[i] + 1, n);
        t.upd(a[i], 1);
        sp[i] = (sp[i - 1] + pre[i]) % p;
    }
    memset(t.a, 0, sizeof t.a);
    for(int i = n; i >= 1; i --)
    {
        suf[i] = t.qry(1, a[i] - 1);
        t.upd(a[i], 1);
        ss[i] = (ss[i + 1] + suf[i]) % p;
    }
    memset(t.a, 0, sizeof t.a);
    for(int i = k; i <= n; i ++)
        t.upd(a[i], 1);
    ll ans = 0, Erev = 1ll * k * (k - 1) % p * inv4 % p;
    ll now = 0;
    for(int i = 1; i <= n - k + 1; i ++)
    {
        ll res = 0;
        res += ss[1] - ss[i];
        res += sp[n] - sp[i + k - 1];
        
        t.upd(a[i + k - 1], -1);

        now -= t2.qry(a[i + k - 1] + 1, n);
        if(a[i - 1] > 1) now += t.qry(1, a[i - 1] - 1);
        
        if(i > 1) t2.upd(a[i - 1], 1);
        
        res -= now;
        res += Erev;
        ans = (ans + res) % p;
    }
    cout << (ans * qpow(n - k + 1, p - 2) % p + p) % p;

    return 0;
}

标签:int,题解,s1,s3,ABC380,s2,qry,ll
From: https://www.cnblogs.com/adam01/p/18549899

相关文章

  • ABC380
    Clink点击查看代码#include<bits/stdc++.h>usingnamespacestd;intn,k;chars[500005];intqr,dg,dl,dr;signedmain(){ cin>>n>>k>>s+1; intlx=1,rx=0,op=0,gs=0; for(inti=1;i<=n&&op<=k;++......
  • 2024ICPC南京部分题解
    LeftShifting3题面:给定一个长度为\(n\)的字符串\(S=s_0s_1\cdotss_{n-1}\),你可以将\(S\)向左移动最多\(k\)次(包括零次)。计算在操作后字符串中包含的“nanjing”子字符串的最大数量。更正式地说,让\(f(S,d)\)成为将\(S\)向左移动\(d\)次得到的字符串。也就是......
  • NOIP集训 P4137 Rmq Problem / mex 题解
    前置指使:可持久化线段树题解:P4137RmqProblem/mex有一个长度为\(n\)的数组\(\{a_1,a_2,...,a_n\}\)。\(m\)次询问,每次询问一个区间内最小没有出现过的自然数。Input第一行,两个正整数\(n,m\)。第二行,\(n\)个非负整数\(a_1,a_2,...,a_n\)。接下来\(m\)行,每......
  • 蓝桥杯模拟赛(第一期)个人题解&感想
    林专大一牲第一次写blog,更新较慢,写的不好的地方请见谅(好多题目忘记了题号and暂时没有题目要求的内容…后面会补充的!)本次带来的是蓝桥杯模拟赛第一期的个人题解(笨人水平较低,大家可以在评论区指出错误/讨论更优解~)大多题我是用c++写的,但也掺了几道c,为以后全面用c++打比赛作过......
  • AI|经常崩溃的问题解决
    AdobeIllustratorCrashes网络上大部分说法都是重装AI,兼容性问题,管理员权限或者是版本不对,经测试均无效,甚至出现重装系统这种离谱的办法,正确的解决办法是把首选项的性能里的GPU取消勾选,或者再把电脑的虚拟内存扩大即可。 Step1:打开首选项 Step2:取消勾选GPU性能......
  • CF987 Div2 F 题解
    阶段1考虑我们每次随机删除两个然后询问,若中位数为\(\frac{n}{2},\frac{n}{2}+1\)称被删除的两个为基准数,用\(v_1,v_2\)代表。每次询问得到解的概率约为\(\frac{1}{2}\)。发现基准数一定一个\(<\frac{n}{2}\)一个\(>\frac{n}{2}+1\),且对于一次四个数的询问\(x......
  • [AGC018C] Coins 题解
    先全部选\(a_i\),假设\(b_i=b_i-a_i,c_i=c_i-a_i\)。那么题目转化为选\(y\)个\(b\)和\(z\)个\(c\)使得答案最大。会发现若\(i\)位置选的\(b\),\(j\)位置选的\(c\),那么需要满足\(b_i-c_i>b_j-c_j\)。我们按上述条件排序,这样一定是在左边选\(b\),右边选\(c\)。那......
  • 题解:ABC013D 阿弥陀
    先考虑\(D=1\),明显可以\(O(M)\)模拟预处理出在最上面的每个位置往下走会走到什么位置,之后每次就可以\(O(1)\)查询了。当\(D>1\)时,可以依赖预处理的数据每次\(O(D)\)暴力查询。又注意到每次对所有位置进行的变换操作是一样的,可以倍增后用类似快速幂的方法优化到\(O(\log......
  • CF2031D 题解
    原题链接最后悔的一集,感觉D\(<\)everything。考虑由确定的点推出其他点的答案,发现最高点的答案是确定的,设其位置为\(x\)。然后根据题目定义,发现可以分成\([1,x-1],[x,n]\)两个区间,\([x,n]\)答案均为\(h_x\)。对于\([1,x-1]\)区间,我们找到第一个\(>[x,n]\)区间最小......
  • 读数据质量管理:数据可靠性与数据质量问题解决之道05数据标准化
    1. 批处理1.1. 批处理在一段时间内收集数据,然后将大量数据“批处理”在离散的数据包中1.2. 直到20世纪10年代中期,批处理都是处理分析型数据最常用的方法1.3. 批处理比流处理要便宜得多,即使是对时间要求最苛刻的处理需求也足以满足1.4. 批处理是经过时间考验的标准,并且仍......