首页 > 其他分享 >The 2024 CCPC Online Contest

The 2024 CCPC Online Contest

时间:2024-09-12 20:16:44浏览次数:11  
标签:CI return Contest int CCPC 2024 const include mod

Preface

最唐氏的一集,这场现场打的时候中间出现了“消失的 150min”

很难相信在 93min 过了 D 之后下一次过题要等到 241min 过 E,虽然后面全力追赶最后也是出了 9 题,但罚时也是突破天际,险些拿下同题数罚时倒一

后面分析了下最大的原因就是我比赛的时候想不出 E 导致心态崩了没法正常想题,祁神 J 的实现相比于正解又有些繁琐了导致花费了大量机时调试以及写对拍

但好在有徐神中流砥柱,一眼秒了 E 后又单切了 I,把节奏拉了回来,只能说这就是我们的绝对核心啊

后面补题的时候发现 A 和赛时想的大差不差,但需要繁琐的讨论就没补了;F 算是个经典多合一,赛后补了一下发现也不难写

抛开开场的幽默网络问题,这场题目本身还是挺友好的,比去年的 CCPC 网络赛的罚坐大赛舒服了不少


A. 军训 I

正如官方题解所说,本题很容易发现答案的上界为 \(13\)

赛时和队友讨论了一些情况后发现有些 Case 的解构造不出来(比如 \(8,12\) 这些),由于不确定是真的无解还是单纯的没找到方法因此就没敢冲

后面想到其实完全可以爆搜一下的,\(5\times 5\) 的范围如果都找不出解那么其它情况大概率也是无解的,只可惜机时不够了

看了题解后代码实现不难,不过 \(k=5\) 的情况赛时还是考虑欠缺了,看来这题的超高 dirt 率也是合情合理


B. 军训 II

签到,不难发现最优方案一定是有序的,计算方案数时只要求出每个数的数量,然后阶乘相乘即可

注意特判只有一种数的情况,此时方案数不乘 \(2\)

#include<cstdio>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=1e6+5,mod=998244353,INF=1e9;
int n,a[N],c[N],fact[N];
inline void init(CI n)
{
    fact[0]=1; for (RI i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod;
}
int main()
{
    scanf("%d",&n); init(n);
    for (RI i=1;i<=n;++i) scanf("%d",&a[i]),++c[a[i]];
    sort(a+1,a+n+1); long long ans=0;
    for (RI i=1;i<=n;++i)
    {
        int mn=INF,mx=-INF;
        for (RI j=i;j<=n;++j)
        {
            mn=min(mn,a[j]); mx=max(mx,a[j]);
            ans+=mx-mn;
        }
    }
    int cnt=1,tp=0;
    for (RI i=1;i<=1000000;++i)
    if (c[i]!=0) cnt=1LL*cnt*fact[c[i]]%mod,++tp;
    if (tp!=1) cnt=2LL*cnt%mod;
    return printf("%lld %d",ans,cnt),0;
}

C. 种树

感觉想到了就很简单的一个题,赛时可能榜有点歪

考虑选大小为 \(3\) 的连通块,且里面必须要有关键点,换句话说一次操作最多将 \(2\) 个非关键点变为关键点

不难发现我们只要安排一种非关键点间的配对关系,总存在一个合法的构造方案能将其全部变为关键点,因此不需要考虑顺序问题

限制是匹配的点对间距离不能超过 \(2\),因此其实只有三种情况:兄弟间配对、父子间配对、祖父和孙子节点配对

考虑如下贪心策略,任选一个关键点为根,从叶子往上贪心;优先两两合并某个点的所有非关键点儿子,若有多余的儿子节点则尝试和该点合并,仍有多余则尝试和该点的父节点合并

实现非常简单,复杂度 \(O(n)\)

#include <bits/stdc++.h>

constexpr int $n = 100005;

int n, m, ans, a, qu[$n], fa[$n];
std::vector<int> out[$n], ch[$n];
bool hkr[$n];

void work() {
    std::cin >> n >> m;
    for(int i = 1; i <= n; ++i) out[i].clear(), ch[i].clear(), hkr[i] = false;
    for(int i = 1; i <= m; ++i) std::cin >> a, hkr[a] = true;
    ans = 0;
    for(int i = 1, u, v; i < n; ++i) {
        std::cin >> u >> v;
        out[u].push_back(v);
        out[v].push_back(u);
    }
    int l = 1, r = 1; qu[l] = a; fa[a] = 0;
    while(l <= r) {
        int hd = qu[l++];
        for(auto out: out[hd]) if(out != fa[hd]) {
            fa[out] = hd; ch[hd].push_back(out);
            qu[++r] = out;
        }
    }

    for(int _i = n; _i > 0; --_i) {
        int i = qu[_i];
        while(ch[i].size()) {
            int a = -1, b = -1;
            while(ch[i].size() && hkr[ch[i].back()]) ch[i].pop_back();
            if(ch[i].size()) a = ch[i].back(), ch[i].pop_back();
            while(ch[i].size() && hkr[ch[i].back()]) ch[i].pop_back();
            if(ch[i].size()) b = ch[i].back(), ch[i].pop_back();
            // std::cout << a << " " << b << char(10);
            if(a < 0) break;
            if(b < 0 && !hkr[i]) b = i;
            if(b < 0 && !hkr[fa[i]]) b = fa[i];
            hkr[a] = true;
            if(b >= 0) hkr[b] = true;
            ans += 1;
        }
    }
    // for(int i = 1; i <= n; ++i) std::cout << std::boolalpha << hkr[i] << char(i == n ? 10 : 32);

    std::cout << ans << char(10);
}

int main() {
    std::ios::sync_with_stdio(false);
    int T; std::cin >> T; while(T--) work();
    return 0;
}


D. 编码器-解码器

小清新 DP 题

不难想到设状态 \(f_{k,l,r}\) 表示 \(T[l,r]\) 在 \(S'_k\) 中出现的次数

转移类似于区间 DP,枚举某个 \(T[i]=S[k]\),分成两边两个子状态即可;注意不匹配的情况也要统计

总复杂度 \(O(|S|\times |T|^3)\)

#include <bits/stdc++.h>

constexpr int mod = 998244353;

int n, m, f[105][105][105];
std::string s, t;

inline void add(int &a, const int &b) {
    if((a += b) >= mod) a -= mod;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin >> s >> t;
    n = s.size(); m = t.size();
    for(int l = 0; l < m; ++l) f[0][l][l] = (s[0] == t[l]);
    for(int i = 1; i < n; ++i) for(int l = 0; l < m; ++l) for(int r = l; r < m; ++r) {
        if(l == r) f[i][l][r] = (s[i] == t[l]);
        else for(int y = l; y <= r; ++y) if(s[i] == t[y]) {
            if(y == l) add(f[i][l][r], f[i - 1][y + 1][r]); else
            if(y == r) add(f[i][l][r], f[i - 1][l][y - 1]); else
            add(f[i][l][r], int64_t(f[i - 1][l][y - 1]) * f[i - 1][y + 1][r] % mod);
        }
        add(f[i][l][r], f[i - 1][l][r]); add(f[i][l][r], f[i - 1][l][r]);
        for(int y = l; y < r; ++y) add(f[i][l][r], int64_t(f[i - 1][l][y]) * f[i - 1][y + 1][r] % mod);
        // std::cout << "f[" << i << "][" << l << "][" << r << "] = " << f[i][l][r] << char(10);
    }
    std::cout << f[n - 1][0][m - 1] << char(10);
    return 0;
}


E. 随机过程

想到了就究极弱智的一个题,但有人被腐乳了我不说是谁

首先最大值很好统计,每层的节点数最多为 \(26^i\),因此最优情况下答案为 \(\sum_{i=0}^m \min(n,26^i)\)

考虑计算期望,还是分层考虑,对于第 \(i\) 层共 \(26^i\) 个点,显然它们出现的概率都是相同的

计算一个点出现的概率,正难则反,逆过来考虑会发现这个概率就是 \(1-(1-\frac{1}{26^i})^n\)

因此最后的总期望就是 \(\sum_{i=0}^m [1-(1-\frac{1}{26^i})^n]\times 26^i\)

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005,mod=998244353;
int n,m,f[N][26],fact[N],ifac[N];
inline void inc(int& x,CI y)
{
    if ((x+=y)>=mod) x-=mod;
}
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
    for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void init(CI n)
{
    fact[0]=1; for (RI i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod;
    ifac[n]=quick_pow(fact[n]); for (RI i=n-1;i>=0;--i) ifac[i]=1LL*ifac[i+1]*(i+1)%mod;
}
inline int C(CI n,CI m)
{
    if (n<0||m<0||n<m) return 0;
    return 1LL*fact[n]*ifac[m]%mod*ifac[n-m]%mod;
}
int main()
{
    scanf("%d%d",&n,&m);
    int mx=1,sum=0;
    if (m>=1) inc(mx,min(26,n));
    if (m>=2) inc(mx,min(26*26,n));
    if (m>=3) inc(mx,min(26*26*26,n));
    if (m>=4) inc(mx,1LL*n*(m-3)%mod);
    for (RI i=0;i<=m;++i)
    {
        int c=quick_pow(26,i);
        inc(sum,1LL*c*(1-quick_pow((1-quick_pow(c)+mod)%mod,n)+mod)%mod);
    }
    return printf("%d %d",mx,sum),0;
}

F. 包子鸡蛋 III

超级多合一,每一部分单拿出来感觉都不难,但合在一起就感觉特别麻烦

首先字符只有 e,g 比较有用,记其概率分别为 \(P_e,P_g\),剩下的字符出现概率统一记为 \(P_o\)

如果我们钦定字符只能填 e,g,且强制开头一定为 e,结尾一定为 g,则好的字符串方案可以 DP 出来

正着大力 DP 需要记录长度、egg 的数量、eg 的数量、e 的数量,复杂度是 \(O(m^4)\) 的,无法通过

因此不妨考虑倒着填,令 \(f_{i,j,k}\) 表示填了长为 \(i\) 的串,此时 egg 的数量为 \(j\),且 g 出现了 \(k\) 次的方案数

转移枚举下一个数填什么即可,这个 DP 乍一看是 \(O(m^3)\) 的,但由于 egg 的数量随 g 的数量平方增长,因此其实是 \(O(m^{2.5})\) 的,有了这个我们可以求出长为 \(i\) 的合法串出现的概率 \(g_i\)

接下来考虑往这个串中填入其它字符,设插之前的字符串长度为 \(x\),插入的字符数量为 \(y\),由经典插板法得到此时的贡献为:

\[F(x+y)=\sum C_{x+y-2}^{x-2}\times g_x\times P_o^y \]

不难发现上面式子展开来就是个卷积的形式,大力 NTT 即可;最后为了不重不漏的统计还要加上一段前后缀的情况

设原来串长为 \(p\),前缀(不包含 e)长为 \(q\),后缀(不包含 g)长为 \(l\),则最后的贡献为:

\[G(p+q+l)=\sum F(p)\times (1-P_e)^q\times (1-P_g)^l \]

这个式子还是个卷积,继续大力 NTT 即可;最后得到了每种长度为 \(i\) 的好串的贡献 \(G(i)\),则最后的答案就是 \(\sum G(i)\times (n-i+1)\)

总复杂度 \(O(m^{2.5}+n\log n)\),需要注意一下常数

#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=1<<21,M=1600,mod=998244353;
int n,m,fact[N],ifac[N],Pe,Pg,Po,pwe[N],pwg[N],f[2][M][65],g[N],A[N],B[N],C[N];
inline void inc(int& x,CI y)
{
	if ((x+=y)>=mod) x-=mod;
}
inline int sum(CI x,CI y)
{
	return x+y>=mod?x+y-mod:x+y;
}
inline int sub(CI x,CI y)
{
	return x-y<0?x-y+mod:x-y;
}
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void init(CI n)
{
	fact[0]=1; for (RI i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod;
	ifac[n]=quick_pow(fact[n]); for (RI i=n-1;i>=0;--i) ifac[i]=1LL*ifac[i+1]*(i+1)%mod;
}
namespace Poly
{
	int rev[N],lim,p;
	inline void init(int n)
	{
		for (lim=1,p=0;lim<=n;lim<<=1,++p);
		for (RI i=0;i<lim;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<p-1);
	}
	inline void NTT(int *f,CI opt)
	{
		RI i; for (i=0;i<lim;++i) if (i<rev[i]) swap(f[i],f[rev[i]]);
		for (i=1;i<lim;i<<=1)
		{
			int m=i<<1,D=quick_pow(3,opt==1?(mod-1)/m:mod-1-(mod-1)/m);
			for (RI j=0;j<lim;j+=m)
			{
				int W=1; for (RI k=0;k<i;++k,W=1LL*W*D%mod)
				{
					int x=f[j+k],y=1LL*f[i+j+k]*W%mod;
					f[j+k]=sum(x,y); f[i+j+k]=sub(x,y);
				}
			}
		}
		if (!~opt)
		{
			int Inv=quick_pow(lim); for (i=0;i<lim;++i) f[i]=1LL*f[i]*Inv%mod;
		}
	}
};
int main()
{
	scanf("%d%d",&n,&m); init(n);
	for (RI i=0;i<26;++i)
	{
		int p; scanf("%d",&p);
		if (i==4) Pe=p; else
		if (i==6) Pg=p; else inc(Po,p);
	}
	pwe[0]=pwg[0]=1;
	for (RI i=1;i<=n;++i) pwe[i]=1LL*pwe[i-1]*Pe%mod;
	for (RI i=1;i<=n;++i) pwg[i]=1LL*pwg[i-1]*Pg%mod;
	f[1][0][1]=1;
	for (RI i=1;i<=min(n,m+60);++i)
	{
		memset(f[(i&1)^1],0,sizeof(f[(i&1)^1]));
		for (RI j=0;j<=m;++j) for (RI k=0;k<60;++k)
		{
			if (!f[i&1][j][k]) continue;
			auto C2=[&](CI x)
			{
				return x*(x-1)/2;
			};
			if (j+C2(k)<=m) inc(f[(i&1)^1][j+C2(k)][k],f[i&1][j][k]);
			if (j+C2(k)==m) inc(g[i+1],1LL*f[i&1][j][k]*pwe[i+1-k]%mod*pwg[k]%mod);
			inc(f[(i&1)^1][j][k+1],f[i&1][j][k]);
		}
	}
	for (RI i=min(n,m+60)+1;i<=n;++i) g[i]=1LL*g[i-1]*Pe%mod;
	//for (RI i=1;i<=n;++i) printf("g[%d] = %d\n",i,g[i]);
	for (RI i=3;i<=n;++i) A[i]=1LL*g[i]*ifac[i-2]%mod;
	B[0]=1; for (RI i=1;i<=n;++i) B[i]=1LL*B[i-1]*Po%mod;
	for (RI i=1;i<=n;++i) B[i]=1LL*B[i]*ifac[i]%mod;
	Poly::init(n*2); Poly::NTT(A,1); Poly::NTT(B,1);
	for (RI i=0;i<Poly::lim;++i) A[i]=1LL*A[i]*B[i]%mod;
	Poly::NTT(A,-1); memset(B,0,sizeof(B));
	for (RI i=2;i<=n;++i) A[i]=1LL*A[i]*fact[i-2]%mod;
	for (RI i=n+1;i<Poly::lim;++i) A[i]=0;
	B[0]=C[0]=1;
	for (RI i=1;i<=n;++i) B[i]=1LL*B[i-1]*(1-Pe+mod)%mod;
	for (RI i=1;i<=n;++i) C[i]=1LL*C[i-1]*(1-Pg+mod)%mod;
	Poly::init(n*3); Poly::NTT(A,1); Poly::NTT(B,1); Poly::NTT(C,1);
	for (RI i=0;i<Poly::lim;++i) A[i]=1LL*A[i]*B[i]%mod*C[i]%mod;
	Poly::NTT(A,-1); int ans=0;
	for (RI i=1;i<=n;++i) inc(ans,1LL*A[i]*(n-i+1)%mod);
	return printf("%d",ans),0;
}

G. 疯狂星期六

很经典的一个题,如果没有第一个人花钱超过其它人的限制就是个很典的网络流模型

现在加上这一要求后其实也很简单,首先要尽可能多的让第一个人花钱,因此可以先以该点为源点跑一个最大流,求出第一个人的最大开销 \(lim\)

不难发现对于其它的人 \(i\in[2,n]\),其开销的上界为 \(\min(a_i,lim-1)\),以此将边的容量定下后在参量网络上跑最大流,最后看每个物品对应的边是否流满即可

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define RI register int
#define CI const int&
using namespace std;
const int N=1005,INF=1e9;
int n,m,a[N],v[N],x,y,w;
namespace Network_Flow
{
    const int NN=2005,MM=5e6;
    struct edge
    {
        int to,nxt,v;
    }e[MM<<1]; int cnt=1,head[NN],cur[NN],dep[NN],s,t;
    inline void addedge(CI x,CI y,CI z)
    {
        //printf("%d -> %d  (%d)\n",x,y,z);
        e[++cnt]=(edge){y,head[x],z}; head[x]=cnt;
        e[++cnt]=(edge){x,head[y],0}; head[y]=cnt;
    }
    #define to e[i].to
    inline bool BFS(void)
    {
        memset(dep,0,(s+1)*sizeof(int));
        dep[s]=1; queue <int> q; q.push(s);
        while (!q.empty())
        {
            int now=q.front(); q.pop();
            for (RI i=head[now];i;i=e[i].nxt)
            if (e[i].v&&!dep[to]) dep[to]=dep[now]+1,q.push(to);
        }
        return dep[t];
    }
    inline int DFS(CI now,CI tar,int dis)
    {
        if (now==tar) return dis; int ret=0;
        for (RI& i=cur[now];i&&dis;i=e[i].nxt)
        if (e[i].v&&dep[to]==dep[now]+1)
        {
            int dist=DFS(to,tar,min(dis,e[i].v));
            if (!dist) dep[to]=INF;
            dis-=dist; ret+=dist;
            e[i].v-=dist; e[i^1].v+=dist;
            if (!dis) return ret;
        }
        if (!ret) dep[now]=INF; return ret;
    }
    #undef to
    inline int Dinic(int ret=0)
    {
        while (BFS()) memcpy(cur,head,(s+1)*sizeof(int)),ret+=DFS(s,t,INF); return ret;
    }
};
using namespace Network_Flow;
int main()
{
    scanf("%d%d",&n,&m); t=n+m+1;
    for (RI i=1;i<=n;++i) scanf("%d%d",&a[i],&v[i]);
    for (RI i=1;i<=m;++i)
    {
        scanf("%d%d%d",&x,&y,&w);
        if (x==y) v[x]+=w; else
        {
            addedge(n+i,t,w);
            addedge(x,n+i,INF);
            addedge(y,n+i,INF);
        }
    }
    for (RI i=1;i<=n;++i) if (v[i]>a[i]) return puts("NO"),0;
    s=n+m+2; addedge(s,1,a[1]-v[1]);
    Dinic(); int lim;
    for (RI i=head[s];i;i=e[i].nxt) lim=v[1]+e[i^1].v;
    s=n+m+3;
    for (RI i=2;i<=n;++i)
    {
        int bd=min(a[i],lim-1);
        if (v[i]>bd) return puts("NO"),0;
        addedge(s,i,bd-v[i]);
    }
    Dinic();
    for (RI i=n+1;i<=n+m;++i)
    {
        for (RI j=head[i];j;j=e[j].nxt)
        if (e[j].to==t)
        {
            if (e[j].v!=0) return puts("NO"),0;
        }
    }
    return puts("YES"),0;
}

H. 另一个游戏

防 AK 数据结构题,鉴定为弃疗


I. 找行李

被徐神 solo 了,ORZ

这类问题一眼考虑容斥,令 \(g_x\) 表示答案至少为 \(x\) 的方案数,最后相邻的项作差即可得到答案恰好为 \(x\) 的方案数

计算 \(g_x\) 也很简单,首先将人和行李排序,那么一个人 \(i\) 能选的行李一定是一段前缀;且第 \(i+1\) 个人能选的行李一定包含了第 \(i\) 个人的,因此很好计算方案数

单次 DP 的复杂度为 \(O(n^2)\),总复杂度 \(O(n^3)\)

#include <bits/stdc++.h>

using llsi = long long signed int;
constexpr int mod = 998244353;

int ksm(int a, int b) {
    int c = 1;
    while(b) {
        if(b & 1) c = llsi(c) * a % mod;
        a = llsi(a) * a % mod;
        b >>= 1;
    }
    return c;
}

int fac[502], facinv[502];

void init(int n) {
    fac[0] = 1;
    for(int i = 1; i <= n; ++i) fac[i] = fac[i - 1] * llsi(i) % mod;
    facinv[n] = ksm(fac[n], mod - 2);
    for(int i = n; i >= 1; --i) facinv[i - 1] = facinv[i] * llsi(i) % mod;
    return;
}

int C(int a, int b) {
    return llsi(fac[a]) * facinv[b] % mod * facinv[a - b] % mod;
}

int w[502];
int dp[502][502];

inline void add(int &a, const int &b) {
    if((a += b) >= mod) a -= mod;
}

int get_dp(int n) {
    // for(int i = 1; i <= n; ++i) std::cerr << w[i] << char(i == n ? 10 : 32);
    dp[0][0] = 1; w[0] = 0;
    for(int i = 0; i < n; ++i) {
        memset(dp[i + 1], 0, sizeof(dp[i + 1]));
        for(int j = 0; j <= w[i]; ++j) {
            add(dp[i + 1][j], dp[i][j]);
            if(j + 1 <= w[i + 1])
                add(dp[i + 1][j + 1], llsi(dp[i][j]) * llsi(w[i + 1] - j) % mod);
        }
    }
    int ans = mod - 1;
    for(int i = 0; i <= w[n]; ++i) add(ans, dp[n][i]);
    return ans;
}

int n, m, a[502], b[502], hkr[502];
int main() {
    std::ios::sync_with_stdio(false);
    int n, m; std::cin >> n >> m;
    for(int i = 1; i <= n; ++i) std::cin >> a[i];
    for(int j = 1; j <= m; ++j) std::cin >> b[j];
    std::sort(a + 1, a + n + 1);
    std::sort(b + 1, b + m + 1);
    for(int x = 1; x <= 500; ++x) {
        for(int i = 1; i <= m; ++i) {
            w[i] = 0;
            while(w[i] < n && b[i] - x >= a[w[i] + 1]) w[i]++;
        }
        hkr[x] = get_dp(m);
        // if(x <= 5) std::cout << hkr[x] << char(10);
    }
    int ans = 0;
    for(int x = 1; x <= 500; ++x) add(ans, llsi(mod + hkr[x] - hkr[x + 1]) * x % mod);
    std::cout << ans << char(10);
    return 0;
}


J. 找最小

唉沟槽的线性基还在追杀我,但无所谓我有队友

考虑先求出两个序列的异或和 \(A,B\),同时令 \(c_i=a_i\oplus b_i\),则修改位置 \(i\) 相当于让 \(A,B\) 同时异或上 \(c_i\)

考虑将所有 \(c_i\) 加入线性基中,然后进行一个按位贪心即可;题解的实现较为简单,以下代码是祁神赛时实现的,由于写了对拍可读性较差

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

const int R = 35;
struct Linebase{
    int p[R];
    void init() {
        for (int i=R-1; i>=0; --i) p[i]=0;
    }
    inline void insert(int x) {
        for (int i=R-1; i>=0; --i) if ((x>>i)&1){
            if (!p[i]) return (void)(p[i]=x); x^=p[i];
        }
    }
    bool check(int x, int pos){
        for (int i=R-1; i>=pos; --i) if ((x>>i)&1){
            if (0==p[i] && ((x>>i)&1)) return false;
            x^=p[i];
        }
        return true;
    }
}base;

const int INF = (int)1e18+5;
const int N = 1e6+5;
int n, A[N], B[N], C[N], xorA, xorB;

int bf(){
    int ans=INF;
    for (int i=0; i<(1LL<<n); ++i){
        int resA=0, resB=0;
        for (int j=0; j<n; ++j){
            if ((i>>j)&1) resA^=A[j+1], resB^=B[j+1];
            else resA^=B[j+1], resB^=A[j+1];
        }
        ans = min(ans, max(resA, resB));
    }
    return ans;
}

void makedata(int n_){
    n = n_;
    const int AA = 4;
    for (int i=1; i<=n; ++i) A[i] = rand()%AA, B[i] = rand()%AA;
}

void readd(){
    cin >> n;
    for (int i=1; i<=n; ++i) cin >> A[i];
    for (int i=1; i<=n; ++i) cin >> B[i];
}

bool solve(){
    readd();
    // makedata(4);
    int bfans = bf();

    base.init();
    xorA = xorB = 0;
    for (int i=1; i<=n; ++i) xorA^=A[i], xorB^=B[i];
    for (int i=1; i<=n; ++i) C[i] = (A[i]^B[i]), base.insert(C[i]);

    // printf("xorA=%lld xorB=%lld\n", xorA, xorB);

    // printf("base:\n");
    // for (int i=0; i<4; ++i) {
    //     printf("i=%lld : %lld\n", i, base.p[i]);
    // }

    int cur=0, pos=-1;
    int xxx = xorA^xorB;
    for (int i=R-1; i>=0; --i){
        if ((xxx>>i)&1) {pos=i; break;}

        bool ok0 = base.check(cur, i);
        bool ok1 = base.check(cur|(1LL<<i), i);
        if (ok0 && ok1){
            if ((xorA>>i)&1) cur |= (1LL<<i);
        }else if (ok1) cur |= (1LL<<i);
    }

    // printf("cur=%lld pos=%lld\n", cur, pos);
    int resA = xorA^cur, resB = xorB^cur;
    int ans = INF;
    // printf("cur=%lld resA=%lld resB=%lld\n", cur, resA, resB);

    if (pos<0) ans = max(xorA^cur, xorB^cur);
    else {
        for (int h=0; h<2; ++h){
            cur &= (1LL<<R) - (1LL<<pos);
            cur ^= (1LL<<pos);
            resA = xorA^cur, resB = xorB^cur;
            // printf("cur=%lld resA=%lld resB=%lld\n", cur, resA, resB);

            // printf("base.check(%lld, %lld)=%lld\n", cur, pos, base.check(cur, pos));
            if (!base.check(cur, pos)) continue;

            for (int i=pos-1; i>=0; --i){
                bool ok0 = base.check(cur, i); 
                bool ok1 = base.check(cur|(1LL<<i), i);

                // printf("i=%lld ok0=%d ok1=%d\n", i, ok0, ok1);

                if (ok0 && ok1){
                    // printf("(%lld %lld)(%lld %lld)\n", resA, resB, resA^(1LL<<i), resB^(1LL<<i) );
                    if (max(resA, resB) > max(resA^(1LL<<i), resB^(1LL<<i))) cur |= (1LL<<i);
                }else if (ok1) cur |= (1LL<<i);
                resA = xorA^cur, resB = xorB^cur;
                // printf("cur=%lld resA=%lld resB=%lld\n", cur, resA, resB);
            }
            // printf("resA=%lld %lld\n", resA, resB);
            ans = min(ans, max(resA, resB));
        }
    }
    cout << ans << '\n';

    // if (ans!=bfans){
    //     // printf("n=%lld\n", n);
    //     for (int i=1; i<=n; ++i) printf("%lld ", A[i]);
    //     for (int i=1; i<=n; ++i) printf("%lld ", B[i]);
    //     // printf("ans=%lld bfans=%lld\n", ans, bfans);
    //     return false;
    // }else printf("ans=%lld bfans=%lld\n", ans, bfans);
    return true;
}

signed main(){
    ios::sync_with_stdio(0); cin.tie(0);
    int t; cin >> t;
    while (t--) solve();
    // while (solve()) {break;}
    return 0;
}

K. 取沙子游戏

祁神开场一眼秒了,我题意都不知道

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

int n, k;
int lb(int x){return x&(-x);}

void solve(){
    cin >> n >> k;
    if (lb(n) <= k) cout << "Alice\n";
    else cout << "Bob\n";
}

signed main(){
    ios::sync_with_stdio(0); cin.tie(0);
    int t; cin >> t; while (t--) solve();
    return 0;
}

L. 网络预选赛

签到,枚举即可

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=505;
int n,m; char s[N][N];
int main()
{
    scanf("%d%d",&n,&m); int ans=0;
    for (RI i=1;i<=n;++i) scanf("%s",s[i]+1);
    for (RI i=1;i+1<=n;++i) for (RI j=1;j+1<=m;++j)
    if (s[i][j]=='c'&&s[i][j+1]=='c'&&s[i+1][j]=='p'&&s[i+1][j+1]=='c') ++ans;
    return printf("%d",ans),0;
}

Postscript

这场打的实在是有点唐,被同届的一堆队伍吊着打,还差点被 Div2 的队暴打了,还好最后小赢一手罚时保住颜面

这周的 ICPC 网络赛还要打名额,只能说希望别再犯病了的说

标签:CI,return,Contest,int,CCPC,2024,const,include,mod
From: https://www.cnblogs.com/cjjsb/p/18410962

相关文章

  • [NOIP 2024 模拟2]矩阵学说
    [NOIP2024模拟2]矩阵学说题意给出\(n\)行\(m\)列的矩阵,第\(i\)行第\(j\)列的元素为\(a_{i,j}\),找出满足以下条件的三元组\((i,j,x)\)的数量:\(1≤i≤n\),\(1≤j\lem\),\(1≤x≤\min(n−i+1,m−j+1)\)矩阵的左上角\((i,j)\)到右下角......
  • [NOIP 2024 模拟2]数组操作
    [NOIP2024模拟2]数组操作题意有\(n+2\)个整数\(a_0,a_1,...,a_n,a_{n+1}\),\(a_0=a_{n+1}=0\)。你需要做确切地\(n\)次操作,每次数组操作为以下形式:选择一个整数\(x\)满足\(a_x\ne0\),使得\(a_x=0\),令\(l=\max_{i<x,a_i=0}i,r=\min_{i>x,a_i=0}i\)......
  • 2024825XCPC2024模拟赛
    背景QY可爱。榜三。正文记得上次打ICPC赛制还是在上一次。而且这次是IOI赛制,所以没有罚时哈哈哈哈哈哈哈。T1概率期望,但是只用了定义。\(\mathcal{O}(1)\)小式子一推,\(6\min\)过掉。T2直接上难度。发现两个字符串按照前缀和后缀分别删除元素以后得到的两个端点之间......
  • 明天见!2024WAIC产业数据要素流通与应用论坛诚邀莅临
    7月6日下午,2024WAIC产业数据要素流通与应用论坛将于在上海世博中心430会议室举办。诚邀您莅临,聚焦数字科技最新成果,强化高水平数字化支撑,见证多项重磅成果发布,共同推动数据要素市场发展!  重磅嘉宾亮相  ......
  • 从产业区块链到产业数据空间,构建数据价值释放关键引擎 | 林乐博士在2024WAIC产业数据
    7月6日,2024WAIC零数科技产业数据要素流通与应用论坛将于在上海世博中心430会议室成功举办。零数科技创始人兼CEO林乐博士代表主办方致辞,并表示,数据市场已全面启航,数据流通基础设施是构建数据价值释放关键引擎;从产业区块链,到产业数据空间,再到金融数据空间,零数科技正式推出零数可信数......
  • 2024.09.08小红书
    1.机器人走网格小红书的冒险家们!今天,我们要进入一个充满挑战的高科技迷言。这是一张由小红书科技部最新研发的网格地图,每个格子都营着秘密一它们内置了自动滑行带!这些滑行带会让所有进入它们的机器人自动翻一个特定方向滑行。网格地图每个格子都藏着秘密一它们内置了自动滑行......
  • [2024-9-12]如何在Z-Library中免费下载书籍讲解流程
    无不良引导,共享知识,书籍乃进步阶梯。一、登录官网https://z-lib.io/按要求进行注册。二、下载Discordhttps://discord.com/经过我的测试网页版应该是没有注册功能的,先下载再注册。三、免费下载书籍搜索图书,点击索取此书。 然后接受邀请,转到help,帮助内容如下:1)H......
  • 数据要素市场如何发展?2024WAIC零数科技这场论坛干货满满!
    7月6日,2024WAIC零数科技产业数据要素流通与应用论坛于上海世博中心430会议室成功举办。本次论坛由中国发展战略学研究会数字经济战略专委会主办,中国发展战略学研究会数字经济战略专委会、上海零数科技有限公司联合承办。作为2024WAIC重要分论坛之一,论坛以“激活数据要素×,筑基新质......
  • 2024 上海CCPC
    The2024ShanghaiCollegiateProgrammingContest补题连接:https://codeforces.com/gym/105229M.不共戴天观察样例2,注意到6个荷叶两两分成一组,共分为3组(1,2)(3,4)(5,6)其中对于青蛙的策略是组内全部连接,即:m=3:1->2,3->4,5->6鸟的策略是,相邻组相连,即:m=4:1->3,2->4,3->5,4->6猜......
  • 2024年9月11日(k8s环境配置)
    编号主机名称ip1k8s-master192.168.8.2022k8s-node1192.168.8.2033k8s-node2192.168.8.204 1、做免密[root@k8s-master~]#ssh-keygen[root@k8s-master~]#[email protected][root@k8s-master~]#[email protected]、yum源(三台主......