首页 > 其他分享 >ARC168

ARC168

时间:2024-01-18 20:37:56浏览次数:28  
标签:ARC168 cnt int rint ++ rightarrow mod

ARC168

前言

输输输,只有 A、B、D 只有独立做出来了。C 想到了的 idea,但是指数是 6 次方级别的,没敢写。E 看出来了是 wqs 二分,但是找不到凸,F 根本不可做。麻了。

[ARC168A]

传送门 link

这种题放在 A 就别瞎想,简单问题简单解决,双指针扫一遍即可。

int n;
string s;
int ans;

signed main()
{
    cin >> n >> s;
    
    for (rint i = 0, j = 0; i < n - 1; i++)
	{
    	if (s[i] != '>') continue;
		j = max(i, j);
		bool flag = 0;
		while (s[j] == '>') j++, flag = 1;
		j -= flag;
		ans += j - i + 1;
	}
	
	cout << ans << endl;
	
	return 0;
}

[ARC168B] Arbitrary Nim

传送门 link

比较板子的一个 nim 博弈

先判一手有没有必胜策略,如果有,考虑如何维护答案。镜子影像思想,先将出现两次的数给消掉,通过模仿对方的行为消除这两堆。保证最大的一堆用两步消掉。对最大的一堆异或记录即可。


multiset<int> s;
int n, t;

signed main()
{
	cin >> n;
	
	for (rint i = 1; i <= n; i++)
	{
		int x;
		cin >> x;
		t ^= x;//判断是否有必胜策略
		if (s.find(x) != s.end()) s.erase(x);
		else s.insert(x);
	}
	
	if (t) cout << "-1" << endl;
	else 
	{
	    if(s.empty())
		{
			cout << "0" << endl;
			exit(0);
		} 	
		cout << *--s.end() - 1 << endl; 
	}
    
    return 0;
} 

[ARC168C] Swap Characters

传送门link

根本没想到换个角度解决问题。以为肯定可以 dp 或者能推出一个比较快的公式,打死也想不到正解。

正面解决根本不会,那么正难则反,已知一个目标字符串 \(T\),求从原来的字符串 \(s\) 变换至 \(T\) 的最小操作数是多少

考虑枚举 \(a\rightarrow b,b\rightarrow a,a\rightarrow c,c\rightarrow a,b\rightarrow c,c\rightarrow b\) 的位置数,判断最小交换次数是否小于等于 \(k\)。但是这种复杂度是非常高的,显然过不去。

考虑另一种枚举方法,我们先枚举 \(a,b\) 之间,\(b,c\) 之间以及 \(a,c\) 之间的交换次数,每次交换对最小步数的贡献为 \(1\),设它们为 \(A,B,C\)。则 \(a\rightarrow b,b\rightarrow a\) 的次数均为 \(A\),\(a\rightarrow c,c\rightarrow a\) 的次数均为 \(C\),\(b\rightarrow c,c\rightarrow b\) 的次数均为 \(B\),再枚举全排列交换次数(显然每次交换对最小步数的贡献为 \(2\)),设为 \(D\)

那么 \(D\) 只可能被加到 \(a\rightarrow b,b\rightarrow c,c\rightarrow a\) 或者 \(a\rightarrow c,c \rightarrow b,b\rightarrow a\) 的次数里。剩下的情况都是这两种情况的其中一种的全排列。

所以直接枚举 \(A,B,C,D\),再枚举 \(D\) 被加到前者的情况里还是后者的情况里,每次加进答案的贡献数就是组合数。复杂度 \(O(k^4)\)

const int N = 2.5e5 + 5;
const int mod = 998244353;

int n, k, cnt[3], ans;
int fac[N], inv[N], ifac[N];
int ab, ac, bc, ba, ca, cb;

int read() 
{
    int x = 0;
    char c = getchar(), f = 0;

    while (c < '0' || c > '9')
        f |= (c == '-'), c = getchar();

    while (c >= '0' && c <= '9')
        x = (x << 3) + (x << 1) + (c & 15), c = getchar();

    return f ? -x : x;
}

int qpow(int a, int b)
{
	int res = 1;
	while (b)
	{
		if (b & 1) res = res * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return res;
}

void init()
{
    fac[0] = ifac[0] = 1;
    for (rint i = 1; i < N; i ++)
    {
        fac[i] = fac[i - 1] * i % mod;
        ifac[i] = ifac[i - 1] * qpow(i, mod - 2) % mod; 
    }	
}

int C(int a, int b)
{
	if (b < 0 || a < b) return 0;
	return fac[a] * ifac[a - b] % mod * ifac[b] % mod;
}

void update()
{
    ans = (ans + C(cnt[0], ab) * C(cnt[0] - ab, ac) % mod * C(cnt[1], ba) % mod * C(cnt[1] - ba, bc) % mod * C(cnt[2], ca) % mod * C(cnt[2] - ca, cb) % mod) % mod;
}

signed main() 
{
    ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	n = read();
	k = read();
    init();

    while (n--) cnt[getchar() - 'A']++;

    for (rint d = 0; d <= (k >> 1); d++)
      for (rint a = 0; a <= k - (d << 1); a++)
        for (rint b = 0; b <= k - (d << 1) - a; b++)
          for (rint c = 0; c <= k - (d << 1) - a - b; c++) 
			{
                ab = a;
				ac = b + d; 
				bc = c;
				ba = a + d;
				ca = b;
				cb = c + d;
				update();

                if (d)
                {
                    ab = a + d;
					ac = b; 
					bc = c + d;
					ba = a;
					ca = b + d; 
					cb = c; 
					update();						
				}
            }

    cout << ans << endl;
    
    return 0;
}

[ARC168D] Maximize Update

传送门link

要么是计数 dp,要么是区间 dp。第一眼想到的是 区间 dp

设 \(f_{i,j}\) 为把 \([i,j]\) 全部涂黑,其他为白的最多操作次数

\(f_{i,j}=\max\limits_{k=i}^{r-1}f_{i,k}+f_{k+1,r}\)

\(f_{i,j}=\max\limits_{k=i}^rf_{i,k-1}+f_{k+1,r}+ cost(l,r)\)

\(cost\) 表示区间内是否有覆盖该格子

然后前缀和处理一下就可以,剩下的板子。

复杂度 \(O(n^3)\)

bool cost(int l, int r, int k)
{
	return bool(s[k][r] - s[k][k - 1] - s[l - 1][r] + s[l - 1][k - 1]);
}

signed main()
{
	cin >> n >> m;
	
	for (rint i = 1; i <= m; i++)
	{
		int a, b;
		cin >> a >> b;
		s[a][b]++; 
	} 
	
	for (rint i = 1; i <= n; i++)
		for (rint j = 1; j <= n; j++)
			s[i][j] += s[i - 1][j];
			
	for (rint i = 1; i <= n; i++)
		for (rint j = 1; j <= n; j++)
			s[i][j] += s[i][j - 1];
	
	for (rint len = 1; len <= n; len++)
	{
		for (rint l = 1; l <= n; l++)
		{
			int r = l + len - 1;
			for (rint k = l; k < r; k++)
			{
				f[l][r] = max(f[l][r], f[l][k] + f[k + 1][r]);
			}
			for (rint k = l; k <= r; k++)
			{
				f[l][r] = max(f[l][r], f[l][k - 1] + f[k + 1][r] + cost(l, r, k));
			}
		}		
	}

	cout << f[1][n] << endl;
	
	return 0;
}

[ARC168E] Subsegments

传送门link

先二分答案转为判定性问题。这时候问题就被转化为,在令答案为 \(x\) 的前提下,是否能够划分出 \(k\) 个连续段。

设 \(f_i\) 表示选出 \(i\) 段的最小代价,每一段的代价使用 \(r-l\) 来刻画

\(f_i\) 是求出恰好答案为 \(i\) 的方案数,这个函数是凸的。到了这一步就简单了。对 \(f\) 进行 wqs 二分。转移不选当前点,或选以当前点为右端点的代价最小的一个区间,从对应位置转移。

复杂度 \(O(n\log^2 n)\)

int n, k, S;
pair<int, int> f[N];
int p[N];
int a[N], s[N];

void F(int x) 
{
    for (rint i = 1; i <= n; i++) 
	{
        f[i] = f[i - 1];
        if (p[i])
        {
            f[i] = min(f[i], {f[p[i] - 1].x + (i - p[i]) - x, f[p[i] - 1].y + 1});			
		}
    }
}

bool check(int x) 
{
    int l = 1, r = n;
	int ans = 0;

    while (l <= r) 
	{
        int mid = (l + r) >> 1;
        F(mid);
        if (f[n].y <= x) l = mid + 1, ans = mid;
        else r = mid - 1;
    }
    F(ans);
    return f[n].x + ans * x <= n - k;
}

signed main() 
{
    cin >> n >> k >> S;

    for (rint i = 1; i <= n; i++)
    {
        cin >> a[i];
		s[i] = s[i - 1] + a[i];		
	}

    for (rint i = 1, j = 0; i <= n; i++) 
	{
        while (s[i] - s[j] >= S) j++;
        p[i] = j;
    }

    int l = 1, r = k;
    int ans = 0;

    while (l <= r) 
	{
        int mid = (l + r) >> 1;
        if (check(mid)) ans = mid, l = mid + 1;
        else r = mid - 1;
    }

    cout << ans << endl;
    
	return 0;
}

[ARC168F] Up-Down Queries

传送门 link

不可做,根本不可做。看了题解代码也打不出来,写了一个小时直接弃了。

这道题的前置知识是省选联考2023人员调动。这种题留着,下辈子有机会一定补上。

标签:ARC168,cnt,int,rint,++,rightarrow,mod
From: https://www.cnblogs.com/spaceswalker/p/17973331

相关文章

  • ARC168
    [ARC168A]<Inversion>之前打了,忘了,懒得想了,咕。$\texttt{Code}$#include<bits/stdc++.h>usingnamespacestd;#defineintlonglong#defineilinline#definereregisterconstintN=3e5+113;intn,ans;chara[N];ilintread(){reintx=0,f=1;char......
  • [ARC168B] Arbitrary Nim
    原题链接:ARC168B题意:有\(n\)堆石子,每堆有\(a_{i}\)个。每人每次可以取走其中一堆中的\(x(1\lex\lek)\)个。求出一个最大的\(k\)使得先手必胜。无解输出\(0\),\(k\)可以取无限大输出\(-1\)。一个经典Nim游戏的结论是:\(a_{i}\)的异或和为\(0\),则先手必败。但是......
  • ARC168E
    题面给定长度为\(n\)的数列\(\{a_i\}\)和两个参数\(k,s\),将\(\{a_i\}\)划分成\(k\)段,最大化和\(\geqs\)的段数。\(1\leqk\leqn\leq250000,1\leqA_i\leq10^9,1\leqs\leq10^{15}\)。题解首先注意到如果当前划分的一段\(sum<s\),那么这种段的长度......
  • arc168b
    https://atcoder.jp/contests/arc168/tasks/arc168_b不会博弈,但是会乱搞首先直接判断-1的情况然后我们直接考察最大值能不能取到假设存在一个数ai\(a_1\oplusa_2...\oplus(a_i-x)\oplus...a_n\)=max也就是说要拿掉max,才能再使xor=0移项之后得到\((a_i-x)=a_1\oplusa_2......
  • [ARC168E] Subsegments with Large Sums
    题目链接看到严格选\(k\)个,不难想到WQS二分。定义\(f(x)\)为分成\(x\)段,最多有多少个超过\(S\)的。然后你会发现他不是凸的。因为他有很多平段,比如把两个很小的合并不改变答案。换个方向?考虑定义\(f(x)\)为有\(x\)个超过\(S\)的段,最多有多少个段。然后发现这个......
  • [ARC168E] Subsegments with Large Sums
    有点意思的简单题。答案有可二分性。合并两段,显然仍然合法。考虑如何check。因为答案可以被二分,我们尝试求恰好\(x\)段就行了。恰好,这是wqs二分的内容。如何设计一个与\(x\)有关的凸函数呢?这个函数大概是\(\sum_{i=1}^xw(l_i,r_i)\)的形式,每一个\([l,r]\)都是合......
  • ARC168F
    纪念一下第一次补完ARC的所有题。本题解介绍\(2log\)做法,需要卡常才能过。感谢@Rainbow_qwq大佬的耐心讲解,拜谢拜谢拜谢。首先注意到每次操作是前后缀修改,自然想到维护差分数组。假设当前操作到了\(a_i\),那么差分数组的\(a_i\)这位加\(2\),然后差分数组全局最小的值......
  • ARC168(A-C)题解
    比赛链接:arc168A题意:读入一个由<和>构成的字符串,在最开始,最后,字符之间可以填上任意数字,任意两个相邻数字之间必须满足字符代表的大小关系。求问最后填入的数字组成的数组最少有多少对逆序对。题解:签到。<可以不去考虑,因为不会对答案造成影响。>如果不是在连续段内,也可以不......
  • ARC168E
    简要题意给定一个长度为$n$的序列$a$,将$a$划分为$k$个连续段,最大化满足连续段中元素和$\geqs$的连续段数。题解首先发现是恰好$k$个连续段,这种类型的题套路地考虑wqs二分,然后你会惊喜的发现这玩意不是凸的,我的思考也就卡在这里了。正确的做法是观察到答案具有单......