The 2018 ICPC Asia Qingdao Regional Programming Contest (The 1st Universal Cup, Stage 9: Qingdao)

Preface

久违地VP一场,虽然打的挺唐但勉强写出了8题

前中期EFB三开三卡属实有点难受,而且B题这个套路大合集我和徐神两个人写了快200行也占用了一定机时

但好在后面把卡住的题慢慢都写出来了,然后最后40min冲刺L题成功

比较可惜的是I这个开场看的题没有再细想一步,感觉想到在线段树上DP就很容易做了


A. Sequence and Sequence

防AK题,开场看了眼题面一眼不可做直接扔了


B. Kawa Exam

超级经典套路题,徐神1h就开了这道题然后开始写,后面我接力上去写了个DSU on Tree加线段树,这就是我们热血沸腾的组合技啊

首先原问题等价于,每个点有一个颜色,每个连通块的权值定义为其中出现次数最多的颜色的值

图的权值定义为所有连通块的权值和,现在要对于每一条边求出,断掉这条边后图的权值是多少

看到断边和连通性,很容易想到求出桥,显然不是桥的那些边删不删对答案没有影响,可以预先计算出

然后根据经典结论,将一个无向图边双缩点后,得到的一定是个森林,因此只要考虑在树上断一条边求解原问题

树上的断边又等价于选出一个子树,求出它的贡献以及删去整个子树后剩下部分的贡献

直接DSU on Tree扫描子树,同时线段树分别维护子树内和子树外每种颜色出现的次数即可,总复杂度\(O(n\log^2 n)\)

#include <bits/stdc++.h>

constexpr int $n = 200005;

std::vector<std::pair<int, int>> out[$n];

int dfn[$n], low[$n], tarjan_O;

std::vector<std::pair<int, int>> edge;
std::vector<bool> is_bridge;

int fa[$n];

bool vis[$n];

inline int father(int i) {
	if(fa[i] == i) return i;
	return fa[i] = father(fa[i]);
}

void tarjan(int u, int pre) {
	low[u] = dfn[u] = ++tarjan_O;
	vis[u] = true;
	int son = 0;
	int pre_cnt = 0;
	for(auto [v, id]: out[u]) {
		if(v == pre && pre_cnt == 0) { pre_cnt += 1; continue; }
		if(!dfn[v]) {
			son += 1;
			tarjan(v, u);
			if(low[u] > low[v]) low[u] = low[v];
			if(low[v] > dfn[u]) is_bridge[id] = true;
		} else if(low[u] > dfn[v]) {
				low[u] = dfn[v];
		}
	}
}
int n, m,C;
int a[$n], ans[$n], baseline;

std::vector<int> hkr[$n];
int ans_partial[$n];
std::map<int, int> rst[$n];
std::map<int, int> dfs1(int cur, int pre) {
	std::map<int, int> res {};
	vis[cur] = true;
	for(auto hkr: hkr[cur]) res[hkr] += 1;
	for(auto [ch, id]: out[cur]) if(ch != pre) {
		auto s = dfs1(ch, cur);
		if(s.size() > res.size()) std::swap(s, res);
		for(auto [k, v]: s) res[k] += v;
	}
	return res;
}
#define CI const int&

class Segment_Tree
{
	private:
		int mx[$n<<2];
	public:
		#define TN CI now=1,CI l=1,CI r=C
		#define LS now<<1,l,mid
		#define RS now<<1|1,mid+1,r
		inline void updata(CI pos,CI mv,TN)
		{
			if (l==r) return (void)(mx[now]+=mv); int mid=l+r>>1;
			if (pos<=mid) updata(pos,mv,LS); else updata(pos,mv,RS);
			mx[now]=std::max(mx[now<<1],mx[now<<1|1]);
		}
		inline int query(void)
		{
			return mx[1];
		}
		#undef TN
		#undef LS
		#undef RS
}IN,OUT;

int son[$n],sz[$n],bid[$n];
inline void getson(CI now,CI fa=0)
{
	sz[now]=1; son[now]=0; vis[now]=true;
	for (auto [to,_]:out[now]) if (to!=fa)
	{
		getson(to,now); sz[now]+=sz[to];
		if (sz[to]>sz[son[now]]) son[now]=to,bid[now]=_;
	}
}
inline void travel(CI now,CI fa,CI tp)
{
	for (auto x:hkr[now]) IN.updata(x,tp),OUT.updata(x,-tp);
	for (auto [to,_]:out[now]) if (to!=fa) travel(to,now,tp);
}
inline void DSU(CI outer,CI now,CI fa=0,CI id=-1,CI flag=0)
{
	for (auto [to,_]:out[now]) if (to!=fa&&to!=son[now]) DSU(outer,to,now,_,0);
	if (son[now]) DSU(outer,son[now],now,bid[now],1);
	for (auto [to,_]:out[now]) if (to!=fa&&to!=son[now]) travel(to,now,1);
	for (auto x:hkr[now]) IN.updata(x,1),OUT.updata(x,-1);
	if (~id) ans[id]=outer+IN.query()+OUT.query();
	if (!flag) travel(now,fa,-1);
}

void solve(CI outer,CI root) {
	for (auto [x,y]:rst[root]) OUT.updata(x,y);
	getson(root); DSU(outer,root);
	for (auto [x,y]:rst[root]) OUT.updata(x,-y);
}

#undef CI

void work() {
	std::cin >> n >> m; C=0; tarjan_O = 0;
	for(int i = 1; i <= n; ++i) low[i] = dfn[i] = 0;
	for(int i = 1; i <= n; ++i) std::cin >> a[i],C=std::max(C,a[i]);
	for(int i = 1; i <= n; ++i) out[i].clear();
	edge.resize(m), is_bridge.assign(m, false);
	for(int i = 0; i < m; ++i) {
		auto &[f, t] = edge[i];
		std::cin >> f >> t;
		out[f].emplace_back(t, i), out[t].emplace_back(f, i);
	}
	
	for(int i = 1; i <= n; ++i) vis[i] = false;
	
	for(int i = 1; i <= n; ++i) if(!vis[i]) tarjan(i, i);
	
//	for(int i = 0; i < m; ++i) if(is_bridge[i]) std::cerr << edge[i].first << " <-> " << edge[i].second << char(10);
//	std::cerr << "-------\n";
//	return ;
	
	for(int i = 1; i <= n; ++i) fa[i] = i;
	for(int i = 0; i < m; ++i) if(!is_bridge[i]) fa[father(edge[i].first)] = father(edge[i].second);
	for(int i = 1; i <= n; ++i) out[i].clear();
	
	std::set<std::pair<int, int>> edge_fuck;
	for(int i = 0; i < m; ++i) if(is_bridge[i]) {
		auto [_f, _t] = edge[i];
		int f = father(_f), t = father(_t);
		if(f > t) std::swap(f, t);
		if(edge_fuck.find({f, t}) != edge_fuck.end()) continue;
		edge_fuck.insert({f, t});
		out[f].emplace_back(t, i), out[t].emplace_back(f, i);
	}
	
	for(int i = 1; i <= n; ++i) hkr[i].clear();
	for(int i = 1; i <= n; ++i) hkr[father(i)].push_back(a[i]);
	
	baseline = 0;
	for(int i = 1; i <= n; ++i) vis[i] = false;
	for(int i = 1; i <= n; ++i) if(fa[i] == i && !vis[i]) {
		rst[i] = dfs1(i, i);
		ans_partial[i] = 0;
//		std::cerr << "i = " << i << char(10);
//		for(auto [k, v]: rst[i]) std::cerr << "k, v = " << k << ", " << v << char(10);
		for(auto [k, v]: rst[i]) if(v > ans_partial[i]) ans_partial[i] = v;
		baseline += ans_partial[i];
//		std::cerr << "ans_partial[" << i << "] = " << ans_partial[i] << char(10);
	} else rst[i].clear();
	
//	std::cerr << baseline << char(10);
//	std::cerr << "-------\n";
//	return ;
	
	for(int i = 1; i <= n; ++i) vis[i] = false;
	for(int i = 1; i <= n; ++i) if(fa[i] == i && !vis[i]) solve(baseline-ans_partial[i],i);

	for(int i = 0; i < m; ++i) is_bridge[i]
		? std::cout << ans[i] << char(i == m - 1 ? 10 : 32)
		: std::cout << baseline << char(i == m - 1 ? 10 : 32);
	return ;
}

int main() {
	// freopen("B.in","r",stdin);
	std::ios::sync_with_stdio(false);
	int T; std::cin >> T; while(T--) work();
	return 0;
}

C. Flippy Sequence

分类讨论题,找出两个串不同的极长区间的个数,记为\(cnt\),则:

  • \(cnt>2\),显然无解
  • \(cnt=2\),手玩以下会发现一定恰有\(6\)种方法,而且样例给出了这种情况所以很容易理解
  • \(cnt=1\),刚开始被坑了以为和区间长度有关,后面仔细想了下发现就是\(2\times (n-1)\)
  • \(cnt=0\),两次选的区间相同,方案数为\(\frac{n(n+1)}{2}\)
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=1e6+5;
int t,n; char a[N],b[N];
int main()
{
	for (scanf("%d",&t);t;--t)
	{
		RI i; scanf("%d%s%s",&n,a+1,b+1);
		int cnt=0,lst=0;
		for (i=1;i<=n;++i) if (a[i]==b[i])
		{
			if (lst+1<=i-1) ++cnt; lst=i;
		}
		if (lst+1<=n) ++cnt;
		if (cnt>2) { puts("0"); continue; }
		if (cnt==2) { puts("6"); continue; }
		if (cnt==1) printf("%d\n",2*(n-1));
		else printf("%lld\n",1LL*n*(n+1)/2LL);
	}
	return 0;
}

D. Magic Multiplication

神秘模拟题,细节还是挺多的但想清楚还是很简单的

首先由于没有前导零,因此可以从\(1\sim 9\)枚举\(a_1\)的取值,当\(a_1\)确定时我们可以唯一确定出\(b_1\sim b_m\)的值

注意如果某个一位数\(x\)\(a_1\)的倍数,那么对应的\(b_i\)必须是\(\frac{x}{a_1}\),否则如果在后面再加一个数得到的\(b_i\)一定是两位数

否则考虑取出两位来作为\(a_1\)\(b_i\)的乘积,但要注意判掉前导零和得到的\(b_i>9\)的情况

现在我们已经得到了一组\(b_1\sim b_m\),然后就是用这些值来反着确定\(a_2\sim a_n\)的值了

注意当\(b_i=0\)时对应的\(a_i\)可以任意取值,因此有一些细节需要注意,最后如果回代检验成功就直接输出

具体细节可以看代码

#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int t,n,m,a[N],b[N]; char s[N];
int main()
{
	for (scanf("%d",&t);t;--t)
	{
		RI i,j; scanf("%d%d%s",&n,&m,s+1);
		int len=strlen(s+1); bool flag=0;
		for (a[1]=1;a[1]<=9&&!flag;++a[1])
		{
			bool sign=1; int p=1;
			for (i=1;i<=m;++i)
			{
				if (p>len) { sign=0; break; }
				if ((s[p]-'0')%a[1]==0)
				{
					b[i]=(s[p]-'0')/a[1];
					++p; continue;
				}
				if (s[p]=='0') { sign=0; break; }
				if (p+1>len) { sign=0; break; }
				if (((s[p]-'0')*10+(s[p+1]-'0'))%a[1]==0)
				{
					b[i]=((s[p]-'0')*10+(s[p+1]-'0'))/a[1];
					if (b[i]>9) { sign=0; break; }
					p+=2; continue;
				}
				sign=0; break;
			}
			for (i=2;i<=n&&sign;++i)
			{
				a[i]=-1; for (j=1;j<=m;++j)
				{
					if (b[j]!=0)
					{
						if (p>len) { sign=0; break; }
						if ((s[p]-'0')%b[j]==0)
						{
							int tmp=(s[p]-'0')/b[j];
							if (tmp>9) { sign=0; break; }
							if (a[i]==-1) a[i]=tmp;
							else if (a[i]!=tmp) { sign=0; break; }
							++p; continue;
						}
						if (s[p]=='0') { sign=0; break; }
						if (p+1>len) { sign=0; break; }
						if (((s[p]-'0')*10+(s[p+1]-'0'))%b[j]==0)
						{
							int tmp=((s[p]-'0')*10+(s[p+1]-'0'))/b[j];
							if (tmp>9) { sign=0; break; }
							if (a[i]==-1) a[i]=tmp;
							else if (a[i]!=tmp) { sign=0; break; }
							p+=2; continue;
						}
					} else
					{
						if (p>len) { sign=0; break; }
						if (s[p]!='0') { sign=0; break; }
						++p; continue;
					}
				}
				if (a[i]==-1) a[i]=0;
			}
			if (sign&&p==len+1)
			{
				for (i=1;i<=n;++i) putchar(a[i]+'0'); putchar(' ');
				for (i=1;i<=m;++i) putchar(b[i]+'0'); putchar('\n');
				flag=1;
			}
		}
		if (!flag) puts("Impossible");
	}
	return 0;
}

E. Plants vs. Zombies

从开局搞到最后发现原来是爆long long了,真是经经又典典啊

首先最小值最大一眼二分答案,然后我们此时可以轻松确定出每个位置需要被走到的最少次数

考虑从前往后贪心处理,我们钦定处理到位置\(i\)时所有\(<i\)的位置已经满足要求了,那么要刷步数的话就直接在\((i,i+1)\)刷是最优的

总复杂度\(O(n\log Ans)\),注意潜在的爆long long问题

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

const int INF = (int)4e18+5;
const int N = 1e5+5;
int t, n, m, A[N], c[N];
bool check(int val){
//	printf("check(%lld)\n", val);
	for (int i=1; i<=n; ++i){
		c[i]=(val+A[i]-1)/A[i];
	}
	__int128 res=0;
	for (int i=1; i<=n; ++i){
		if (i<n || (n==i && c[i]>0)) ++res, --c[i];
		if (c[i]>0) c[i+1]-=c[i], res+=2*c[i], c[i]=0;
	}
//	printf("res=%lld\n", res);
	return res<=m;
}
signed main(){
	ios::sync_with_stdio(0); cin.tie(0);
	cin >> t;
	while (t--){
		cin >> n >> m;
		for (int i=1; i<=n; ++i) cin >> A[i];
		int L=0, R=INF;
		while (L<R){
			int M = L+(R-L)/2+1;
			if (check(M)) L=M;
			else R=M-1;
		}
		cout << L << '\n';
	}
	return 0;	
}

F. Tournament

神秘题,刚开始想漏了一个关键条件卡了我和徐神好久的时间,后面徐神上去写B我在下面冷静后发现好像是个找规律题

大力手玩会发现,当\(n\)为奇数时显然无解,\(2\mid n\and 4\nmid n\)\(k\)至多为\(1\),这些都是很trivial的

然后画一画会发现\(n=8\)时可以达到\(n-1\)轮的上界,而\(n=12\)时最多就只能做\(3\)

索性大力猜测对于数\(n\)它能做到的最多轮次就是\(\operatorname{lowbit}(n)-1\),然后构造方案就直接异或就行

爬上去5min写了一发发现直接过了,我直接呃呃

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=1005;
int t,n,k;
int main()
{
	for (scanf("%d",&t);t;--t)
	{
		RI i,j; scanf("%d%d",&n,&k);
		auto lowbit=[&](CI x)
		{
			return x&-x;
		};
		if (k>lowbit(n)-1) { puts("Impossible"); continue; }
		for (i=1;i<=k;++i) for (j=0;j<n;++j) printf("%d%c",(j^i)+1," \n"[j==n-1]);
	}
	return 0;
}

G. Repair the Artwork

看过题人数还是挺可做的一个题,但赛时机时不够了只能作罢,之后有空再补吧


H. Mirror

没一个人过的几何,很符合我对几何的想象


I. Soldier Game

开场就看了这个题,然后一直摸到结束也不会,后面看了眼题解发现就是个傻逼题

首先这类极差问题的经典思路就是枚举确定最小值,然后在只考虑大于阈值的区间时能得到的最大值

这题虽然乍一看数据范围挺大,但仔细一想会发现合法的区间最多只有\(2n-1\)个,因此可以先排序然后枚举

现在问题就是怎么快速处理在ban掉部分区间的情况下用剩余区间覆盖\(1\sim n\),且最大权值最小

不妨考虑用线段树优化DP,在线段树\(x\)(对应区间\([l,r]\))的节点上维护\(f_{x,0/1,0/1}\),表示当覆盖区间\([l,r]\),且覆盖\(l\)位置的线段在/不在区间外,覆盖\(r\)位置的线段在/不在区间外的情形下,最小化的最大权值

转移的话也很trivial:

\[f_{x,p,q}=\min_{k\in \{0,1\}} \max(f_{ls(x),p,k},f_{rs(x),k,q}) \]

初始值的设置按照定义推一下也不难,然后每次删除一条线段就直接把线段树上对应的权值改成\(\infty\)即可

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

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<array>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
const int N=100005,INF=1e18;
int t,n,a[N];
class Segment_Tree
{
	private:
		int f[N<<2][2][2];
		inline void pushup(CI now)
		{
			for (RI x=0;x<2;++x) for (RI y=0;y<2;++y)
			{
				f[now][x][y]=INF; for (RI k=0;k<2;++k)
				f[now][x][y]=min(f[now][x][y],max(f[now<<1][x][k],f[now<<1|1][k][y]));
			}
		}
	public:
		#define TN CI now=1,CI l=1,CI r=n
		#define LS now<<1,l,mid
		#define RS now<<1|1,mid+1,r
		inline void build(TN)
		{
			if (l==r)
			{
				f[now][0][0]=a[l]; f[now][0][1]=l<n?a[l]+a[l+1]:INF;
				f[now][1][0]=l>1?-INF:INF; f[now][1][1]=INF; return;
			}
			int mid=l+r>>1; build(LS); build(RS); pushup(now);
		}
		inline void modify(CI pos,CI len,TN)
		{
			if (l==r)
			{
				if (len==1) f[now][0][0]=INF; else f[now][0][1]=INF; return;
			}
			int mid=l+r>>1; if (pos<=mid) modify(pos,len,LS); else modify(pos,len,RS); pushup(now);
		}
		inline int query(void)
		{
			return f[1][0][0];
		}
		#undef TN
		#undef LS
		#undef RS
}SEG;
signed main()
{
	for (scanf("%lld",&t);t;--t)
	{
		RI i; for (scanf("%lld",&n),i=1;i<=n;++i) scanf("%lld",&a[i]);
		vector <array <int,3>> vec; SEG.build();
		for (i=1;i<=n;++i) vec.push_back({a[i],i,1});
		for (i=1;i<n;++i) vec.push_back({a[i]+a[i+1],i,2});
		sort(vec.begin(),vec.end()); int ans=INF;
		for (auto [val,p,len]:vec)
		ans=min(ans,SEG.query()-val),SEG.modify(p,len);
		printf("%lld\n",ans);
	}
	return 0;
}

J. Books

徐神开场写的,我题面都没看

#include <bits/stdc++.h>

using llsi = long long signed int;

void work() {
	int n, m;
	std::cin >> n >> m;
	std::vector<llsi> a(n);
	for(int i = 0; i < n; ++i) std::cin >> a[i];
	llsi ans = 0;
	int c0 = 0;
	for(int i = 0; i < n; ++i) c0 += !a[i];
	if(c0 > m) return void(std::cout << "Impossible\n");
	m -= c0;
	llsi sufmin = 1e17;
	for(int i = 0; i < n; ++i) if(a[i]) {
		if(m > 0) {
			ans += a[i];
			m -= 1;
		} else if(m == 0) {
			sufmin = std::min(sufmin, a[i] - 1);
		}
	}
	ans += sufmin;
	if(ans >= 1e17)
		std::cout << "Richman\n";
	else
		std::cout << ans << char(10);
}

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

K. Airdrop

好像也是个可做题,但经典没时间了直接弃疗


L. Sub-cycle Graph

小清新计数题,稍微想一下就会了

首先先特判各种Corner Case,比如\(m>n\)时无解;\(m=n\)时为\(\frac{(n-1)!}{2}\)(不计方向的圆排列,所以要除以\(2\));\(m=0\)时为\(1\)

然后考虑一般的情况,不妨设度数为\(i\)的点的个数为\(d_i\),显然我们枚举\(d_1\)的值后就可以唯一确定\(d_0,d_2\)的值了

考虑现在图的形态,我们首先把编号划分给三种点,方案数为\(C_n^{d_0}\times C_{n-d_0}^{d_1}\),然后忽略掉所有的\(d_0\)

考虑先把\(d_1\)两两配对作为一条链的两个端点,这个的方案数是个经典问题

式子是\(C_{d_1}^{\frac{d_1}{2}}\times (\frac{d_1}{2})!\times \frac{1}{2^{\frac{d_1}{2}}}\),第一个组合数表示先定下一堆点放左边,然后剩下的点放在右边配对有阶乘种放法,但要注意因为后面加入的度数为\(2\)的点在中间的时候已经消除了顺序的影响,因此两端点顺序无关,每个pair都要除以\(2\)

最后插入度数为\(2\)的点可以这样考虑,先把\(d_2\)的点任意排列,然后再划分成\(\frac{d_1}{2}\)组,每组内元素连续

后者是个经典的插板法例题,因此再乘上\(d_2!\times C_{d_2+\frac{d_1}{2}-1}^{\frac{d_1}{2}}\)即可

#include <bits/stdc++.h>

using llsi = long long signed int;

constexpr llsi mod = 1'000'000'007;

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

constexpr llsi inv2 = ksm(2, mod - 2);

llsi fac[1000006], facinv[1000006] , inv_pw2[1000006];

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

inline llsi C(llsi n, llsi m) {
	if(n < 0 || m < 0 || m > n) return 0;
	return fac[n] * facinv[m] % mod * facinv[n - m] % mod;
}

llsi work() {
	llsi n, m; std::cin >> n >> m;
	if(m > n) return 0;
	if(m == n) {
		if(n <= 2) return 0;
		return fac[n - 1] * inv2 % mod;
	}
	if(m == 0) return 1;
	llsi ans = 0;
	for(llsi d1 = 2; d1 <= n; d1 += 2) {
		const llsi d2 = (2 * m - d1) / 2;
		const llsi d0 = n - d1 - d2;
		if(d2 < 0 || d2 > n || d0 < 0 || d0 > n) continue;
		ans +=
			C(n, d0) * C(n - d0, d1) % mod * (
				C(d1, d1 / 2) * fac[d1 / 2] % mod
				* inv_pw2[d1 / 2] % mod
				* fac[d2] % mod
				* C(d2 + d1 / 2 - 1, d1 / 2 - 1) % mod) % mod;
	}
	
	return ans % mod;
}

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

M. Function and Function

祁神开场写的签,我题都没看

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

int t, x, k;
const int tbl[10] = {1, 0, 0, 0, 1, 0, 1, 0, 2, 1};
int calc(int v){
	int res=0;
	while (v>0){
		res += tbl[v%10];
		v/=10;
	}
	return res;
}
signed main(){
	ios::sync_with_stdio(0); cin.tie(0);
	cin >> t;
	while (t--){
		cin >> x >> k;
		while (k>0 && x>0){
			--k;
			x = calc(x);	
		}
		if (k>0) cout << k%2 << '\n';
		else cout << x << '\n';
	}
	return 0;	
}

Postscript

晚上要上人工智能的实验课,而且明天要补五一的课,晚上有CF都懒得打

唉感觉最近训练量堪忧啊,好久没有打CF/ATC了的说

posted @ 2024-04-27 17:16  空気力学の詩  阅读(37)  评论(0编辑  收藏  举报