Preface
这场打的挺好,感觉在题目难度不小的情况下能写出10题还是挺猛的
可惜最后时间差一点不然甚至能再写出来一个E
A. King of String Comparison
签到,本来徐神跟我说写个二分+Hash,然后我库库上去一顿写刚抄完板子就被赶下来了
直接从后往前扫,记录距离当前最近的不同的位置出现在哪里,然后遇到一个合法的开头就直接算贡献即可
#include <bits/stdc++.h>
int main(void) {
std::ios::sync_with_stdio(false);
int n; std::cin >> n;
std::string s1, s2;
std::cin >> s1 >> s2;
s1 += '\0'; s2 += '\0';
int dif = n;
int64_t ans = 0;
for(int i = n - 1; i >= 0; --i) {
if(s1[i] != s2[i]) dif = i;
if(s1[dif] < s2[dif]) ans += n - dif;
}
std::cout << ans << char(10);
return 0;
}
B. New Queries On Segment Deluxe
应该是一个比较复杂的DS,连题目都没看
C. Werewolves
复杂度分析题,做法都能一眼想到然就是敢不敢写的问题了
不难发现由于要求最多的颜色严格超过半数,因此可以枚举出现次数最多的颜色,设其出现次数为\(m\)
将与该颜色相同的赋值为\(1\),否则赋值为\(-1\),然后可以很容易设计一个DP状态
\(f_{i,j}\)表示在\(i\)的子树内,选了权值和为\(j\)的连通块的方案数,转移就是一个树上背包
但注意到我们只关心第二维的绝对值\(\le m\)的状态,在这种前提下单次的复杂度其实是\(O(nm)\)的
因此最后的总复杂度就是\(O(n^2)\)
#include<cstdio>
#include<iostream>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=3005,mod=998244353;
int n,c[N],val[N],bkt[N],x,y,f[N][N<<1],sz[N],ans; vector <int> v[N];
inline void inc(int& x,CI y)
{
if ((x+=y)>=mod) x-=mod;
}
inline void DFS(CI now,CI fa,CI col,CI lim)
{
RI i,j; sz[now]=1; for (i=-1;i<=1;++i) f[now][i+lim]=0;
f[now][(c[now]==col?1:-1)+lim]=1;
for (auto to:v[now]) if (to!=fa)
{
DFS(to,now,col,lim); static int tmp[N<<1];
for (i=-min(sz[now]+sz[to],lim);i<=min(sz[now]+sz[to],lim);++i) tmp[i+lim]=0;
for (i=-min(sz[now],lim);i<=min(sz[now],lim);++i)
for (j=-min(sz[to],lim);j<=min(sz[to],lim);++j) if (-lim<=i+j&&i+j<=lim)
inc(tmp[i+j+lim],1LL*f[now][i+lim]*f[to][j+lim]%mod);
for (sz[now]+=sz[to],i=-min(sz[now],lim);i<=min(sz[now],lim);++i) f[now][i+lim]=tmp[i+lim];
}
inc(f[now][0+lim],1);
for (i=1;i<=min(sz[now],lim);++i) inc(ans,f[now][i+lim]);
}
int main()
{
RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&c[i]),++bkt[c[i]];
for (i=1;i<n;++i) scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
for (i=1;i<=n;++i) if (bkt[i]) DFS(1,0,i,bkt[i]);
return printf("%d",ans),0;
}
D. Many LCS
恭喜徐神又开局开到全场防AK题
E. Replace Sort
祁神最后提出了降状态的DP方法,徐神也找出了优化的关键,最后我补上了一种Corner Case才一起通过了这个题
状态数是\(O(n^2)\)的DP不难想到,难点就是怎么提出一个状态数是\(O(n)\)的DP
考虑以一个\(\{a_i\}\)中的数是否要被替换来划分状态,设\(f_i\)表示钦定\(a_i\)不被替换时,使得前\(i\)个位置单调递增最少需要的替换次数
转移的话考虑枚举上一个没换的位置\(a_j\),不难发现需要满足以下性质:
- \(a_j<a_i\)
- 在集合\(B\)中且\(\in(a_j,a_i)\)的数的个数大于等于\(i-j-1\)
转移的话就是\(f_i=f_j+i-j-1\)
考虑第二个限制如何简化,设\(s_i\)表示集合\(B\)中小于等于\(a_i\)的数的个数,则有\(s_i-s_j\ge i-j-1\),移项后得到\(s_i-i+1\ge s_j-j\)
不难发现后面那个条件在绝大多数的情况下包含了前面那个条件,但当两个位置相邻时(即\(j=i-1\)时)会出现问题
因此我们特判情况后,用树状数组维护前缀最小值即可,每次把\(f_i-i\)存储起来
总复杂度\(O(n\log n)\)
#include<cstdio>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=1e6+5,S=500001,INF=2e9;
int n,m,a[N],b[N],s[N],f[N];
class Tree_Array
{
private:
int bit[N],lim;
public:
inline void init(CI n)
{
lim=n; for (RI i=0;i<=lim;++i) bit[i]=INF;
}
#define lowbit(x) (x&-x)
inline int get(RI x,int mn=INF)
{
for (x+=S;x;x-=lowbit(x)) mn=min(mn,bit[x]); return mn;
}
inline void add(RI x,CI y)
{
for (x+=S;x<=lim;x+=lowbit(x)) bit[x]=min(bit[x],y);
}
#undef lowbit
}BIT;
int main()
{
RI i; for (scanf("%d%d",&n,&m),i=1;i<=n;++i) scanf("%d",&a[i]);
for (i=1;i<=m;++i) scanf("%d",&b[i]); sort(b+1,b+m+1);
for (i=1;i<=n;++i) s[i]=lower_bound(b+1,b+m+1,a[i])-b-1;
for (a[n+1]=INF,s[n+1]=m,BIT.init(2*S),i=1;i<=n+1;++i)
{
f[i]=BIT.get(s[i]-i+1)+i-1;
if (a[i-1]<a[i]) f[i]=min(f[i],f[i-1]);
BIT.add(s[i-1]-(i-1),f[i-1]-(i-1));
}
if (f[n+1]>=INF) puts("-1"); else printf("%d\n",f[n+1]);
return 0;
}
F. to Pay Respects
稍作观察发现,毒药视其用途可以分为两类,一类用于开头拿来增加伤害,一类用于BOSS开治疗后那里减治疗
不难发现这两种用途都是把药尽可能早地用掉,因此可以枚举用于减治疗的药的前缀,剩下多出的药扔到最前面即可
贡献的话拆分一下就很好计算,具体实现看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n, X, R, P, K;
string str;
signed main(){
ios::sync_with_stdio(0); cin.tie(0);
cin >> n >> X >> R >> P >> K;
cin >> str;
int ans=n*X;
int posR=0, posP=0;
for (int i=0; i<K; ++i){
ans+=(n-i)*P;
if (str[i]=='1') posR=i;
}
for (int i=K; i<n; ++i) if (str[i]=='1') ans-=(n-i)*R;
posP=K-1;
int res=ans;
while (posP>=0 && posR<n){
++posR; while (posR<n && str[posR]!='1') ++posR;
if (posR>=n) break;
ans += (n-posR)*R;
ans += (n-posR)*P;
while (posP>=0 && str[posP]=='1') --posP;
if (posP<0) break;
ans -= (n-posP)*P; --posP;
res = max(res, ans);
}
cout << res << '\n';
return 0;
}
G. Max Pair Matching
这种问题上来先发现绝对值可以直接扔了,对于一个pair
\((a,b)\)不妨假设\(a>b\)
考虑如果是用\(i\)减去\(j\)的话则有\(a_i-b_j>a_j-b_i\),即为\(a_i+b_i>a_j+b_j\),因此按\(a_i+b_i\)的值从大到小排序后,前\(n\)个减去后\(n\)个即可
#include <bits/stdc++.h>
struct pair { int a, b; };
int main() {
std::ios::sync_with_stdio(false);
int n; std::cin >> n; int dn = n << 1;
std::vector<pair> p(dn);
for(auto &[a, b]: p) {
std::cin >> a >> b;
if(a < b) std::swap(a, b);
}
std::sort(p.begin(), p.end(), [](const pair &x, const pair &y) {
return x.a + x.b > y.a + y.b;
});
int64_t ans = 0;
for(int i = 0; i < n; ++i) ans += p[i ].a;
for(int i = 0; i < n; ++i) ans -= p[i + n].b;
std::cout << ans << std::endl;
return 0;
}
H. Colourful Permutation Sorting
题目没看,估计不简单
I. Flood Fill
队友直接把饼做好了喂我嘴里,最后小搜一波结论直接淦过了这个题
首先考虑搜出\(A\)中所有同色四联通的连通块,徐神发现每个连通块要么不翻转要么翻转一次
同时若对两个相邻的连通块都进行了翻转,则一定可以等效转化为另一种不对相邻连通块进行翻转的情况
因此我们可以对每个连通块求出如果将其翻转,相比不翻转带来的收益,将其作为这个连通块的点权
结合上面的限制,我们不妨将相邻的连通块视为有一条边相连,由于相连的连通块必然异色,因此得到的是一个二分图
所以这题其实就转化为了求二分图的最大带权独立集问题,根据经典结论这个等于总权值减去最小带权点覆盖
后者的做法就是把二分图中间的边边权看作\(\infty\),源点向左部图连边,右部图向汇点连边,边权为点权
跑出最小割后即可发现该最小割就是原二分图的最小带权点覆盖
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#define RI register int
#define CI const int&
using namespace std;
typedef pair <int,int> pi;
const int N=105,INF=1e9,dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
int n,m,bel[N][N],idx,sum,all; char A[N][N],B[N][N]; vector <pi> pos[N*N]; set <pi> rst;
namespace Network_Flow
{
const int NN=10005,MM=1e7+5;
struct edge
{
int to,nxt,v;
}e[MM<<1]; int cnt=1,head[NN],cur[NN],dep[NN],s,t; queue <int> q;
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,t+1<<2); dep[s]=1; q=queue <int>(); 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]=0; return ret;
}
#undef to
inline int Dinic(int ret=0)
{
while (BFS()) memcpy(cur,head,t+1<<2),ret+=DFS(s,t,INF); return ret;
}
};
using namespace Network_Flow;
inline void travel(CI x,CI y,CI col)
{
bel[x][y]=col; pos[col].push_back(pi(x,y));
for (RI i=0;i<4;++i)
{
int nx=x+dx[i],ny=y+dy[i];
if (nx<1||nx>n||ny<1||ny>m) continue;
if (A[nx][ny]==A[x][y]&&!bel[nx][ny]) travel(nx,ny,col);
}
}
int main()
{
RI i,j,k; for (scanf("%d%d",&n,&m),i=1;i<=n;++i) scanf("%s",A[i]+1);
for (i=1;i<=n;++i) scanf("%s",B[i]+1);
for (i=1;i<=n;++i) for (j=1;j<=m;++j) all+=(A[i][j]!=B[i][j]);
for (i=1;i<=n;++i) for (j=1;j<=m;++j) if (!bel[i][j]) travel(i,j,++idx);
for (s=idx+1,t=s+1,i=1;i<=idx;++i)
{
int cur=0; for (auto [x,y]:pos[i])
if (A[x][y]==B[x][y]) --cur; else ++cur;
if (cur<0) continue; sum+=cur;
if (A[pos[i][0].first][pos[i][0].second]=='0') addedge(s,i,cur); else addedge(i,t,cur);
}
for (i=1;i<=n;++i) for (j=1;j<=m;++j)
{
for (k=0;k<4;++k)
{
int nx=i+dx[k],ny=j+dy[k];
if (nx<1||nx>n||ny<1||ny>m) continue;
if (bel[i][j]!=bel[nx][ny])
{
int u=bel[i][j],v=bel[nx][ny];
if (A[i][j]=='1') swap(u,v);
if (rst.count(pi(u,v))) continue;
addedge(u,v,INF); rst.insert(pi(u,v));
}
}
}
return printf("%d",all-(sum-Dinic())),0;
}
J. ABC Legacy
挺有意思的贪心题
首先我们可以计算出每个对的出现次数,例如\(AB\)的出现次数就是\(c_{AB}=\frac{c_A+c_B-c_C}{2}\)
由于\(B\)既可以向前匹配也可以向后匹配,考虑从最特殊的它开始匹配
手玩一下会发现可以给前\(c_{BC}\)个\(B\)都拿去匹配\(BC\),后\(c_{AB}\)个\(B\)都拿去匹配\(AB\)
每次匹配的时候都贪心地选择离当前最近的来匹配
最后检验剩下的\(A,C\)能否匹配即可,手玩一下会感觉这个很对
#include<cstdio>
#include<iostream>
#include<stack>
#include<utility>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
typedef pair <int,int> pi;
const int N=200005;
int n,c[3],vis[N]; char s[N]; stack <int> stk;
int main()
{
RI i; for (scanf("%d%s",&n,s+1),i=1;i<=n*2;++i) ++c[s[i]-'A'];
int AB=(c[0]+c[1]-c[2])/2,AC=(c[0]+c[2]-c[1])/2,BC=(c[1]+c[2]-c[0])/2;
if (AB<0||AC<0||BC<0) return puts("NO"),0;
vector <int> posB; vector <pi> ans;
for (i=1;i<=n*2;++i) if (s[i]=='B') posB.push_back(i);
if (BC>0)
{
while (!stk.empty()) stk.pop();
for (i=1;i<=n*2;++i)
{
if (s[i]=='C')
{
if (stk.empty()) continue;
vis[stk.top()]=vis[i]=1;
ans.push_back(pi(stk.top(),i));
stk.pop();
} else if (s[i]=='B'&&i<=posB[BC-1]) stk.push(i);
}
if (!stk.empty()) return puts("NO"),0;
}
if (AB>0)
{
while (!stk.empty()) stk.pop();
for (i=1;i<=n*2;++i)
{
if (s[i]=='B'&&i>=posB[BC])
{
if (stk.empty()) return puts("NO"),0;
vis[stk.top()]=vis[i]=1;
ans.push_back(pi(stk.top(),i));
stk.pop();
} else if (s[i]=='A') stk.push(i);
}
}
if (AC>0)
{
while (!stk.empty()) stk.pop();
for (i=1;i<=n*2;++i)
{
if (vis[i]) continue;
if (s[i]=='C')
{
if (stk.empty()) return puts("NO"),0;
vis[stk.top()]=vis[i]=1;
ans.push_back(pi(stk.top(),i));
stk.pop();
} else if (s[i]=='A') stk.push(i);
}
}
puts("YES"); for (auto [x,y]:ans) printf("%d %d\n",x,y);
return 0;
}
K. Amazing Tree
思博题,想到关键就迎刃而解了
首先这题如果确定了根节点就有一个很trivial的做法:先找到权值最小的叶节点,然后将其删去,递归操作其父亲节点即可
但现在问题是我们不知道哪个点是根,但我们可以在从叶子节点往上走的时候来动态考虑这个问题
首先还是找到权值最小的叶节点,不难发现这个点一定不作为根
而对于其父亲节点,我们先维护出其余子树内叶子节点的最小值,然后进行讨论:
- 若该点权值大于所有子树中叶子节点的最小值,则以当前点为根一定能得到最优解
- 若若该点权值小于所有子树中叶子节点的最小值,则根节点一定在所有子树中叶子节点的最小值最大的那个子树内,递归寻找即可
同时其它子树的选择顺序也很显然,按照子树中叶子节点的最小值从大到小排序后依次选即可
总复杂度\(O(n\log n)\)
#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#define RI register int
#define CI const int&
#define fi first
#define se second
using namespace std;
const int N=200005;
typedef pair <int,int> pi;
int t,n,x,y,lf_mn[N]; vector <int> v[N],ans;
inline void DFS1(CI now,CI fa=0)
{
lf_mn[now]=(v[now].size()==1&&fa!=0?now:1e9);
for (auto to:v[now]) if (to!=fa)
DFS1(to,now),lf_mn[now]=min(lf_mn[now],lf_mn[to]);
}
inline void DFS3(CI now,CI fa);
inline void DFS2(CI now,CI fa=0) //unknown root
{
vector <pi> sons;
for (auto to:v[now]) if (to!=fa) sons.push_back(pi(lf_mn[to],to));
if (sons.empty()) return ans.push_back(now);
sort(sons.begin(),sons.end());
for (RI i=0;i<sons.size()-1;++i) DFS3(sons[i].se,now);
if (now>sons.back().fi) DFS3(sons.back().se,now),ans.push_back(now);
else ans.push_back(now),DFS2(sons.back().se,now);
}
inline void DFS3(CI now,CI fa=0) //known root
{
vector <pi> sons;
for (auto to:v[now]) if (to!=fa) sons.push_back(pi(lf_mn[to],to));
if (sons.empty()) return ans.push_back(now);
sort(sons.begin(),sons.end());
for (RI i=0;i<sons.size();++i) DFS3(sons[i].se,now); ans.push_back(now);
}
int main()
{
for (scanf("%d",&t);t;--t)
{
RI i; for (scanf("%d",&n),i=1;i<=n;++i) v[i].clear();
for (i=1;i<n;++i) scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
int pos=-1; for (i=1;i<=n;++i) if (v[i].size()==1) { pos=i; break; }
ans.clear(); DFS1(pos); DFS2(pos);
for (i=0;i<n;++i) printf("%d%c",ans[i]," \n"[i==n-1]);
}
return 0;
}
L. Jason ABC
徐神大力秒了此题
首先很容易发现答案有一个上界\(3\),但后面又玩出来其实还有个显然的上界\(2\)
因为我们只要找出某个前缀,满足其中出现次数最多的字符出现了恰好\(n\)次,这样对于剩下的后缀我们只需要至多两次操作就能得到符合要求的序列了
同时\(0\)的情况也很简单,因此只要求出\(1\)的情况即可快速求解
不妨大力枚举这次操作变成的字符,那么很容易求出选择的区间中应包含其它两种字符各多少个,然后two pointers
求解即可
具体实现看代码
#include <bits/stdc++.h>
int main() {
const std::string ABC = "ABC";
int n; std::cin >> n; int tn = n * 3;
std::string s; std::cin >> s;
std::vector<int> __c[3];
for(auto &c: __c) c.resize(tn);
auto c = [&__c](const char &i) -> std::vector<int>& { return __c[i - 'A']; };
for(char ch: ABC) c(ch)[0] = (s[0] == ch);
for(int i = 1; i < tn; ++i) for(char ch: ABC)
c(ch)[i] = c(ch)[i - 1] + (s[i] == ch);
if(c('A')[tn - 1] == c('B')[tn - 1] && c('A')[tn - 1] == c('C')[tn - 1])
return std::cout << "0" << std::endl, 0;
std::string p = ABC; do {
const char A = p[0], B = p[1], C = p[2];
int Bo = c(B)[tn - 1] - n, Co = c(C)[tn - 1] - n;
if(Bo < 0 || Co < 0) continue;
int l = 0, r = 0;
while(l < tn) {
while(r < tn && (Bo > 0 || Co > 0)) {
Bo -= (s[r] == B);
Co -= (s[r] == C);
r += 1;
}
if(Bo > 0 || Co > 0) break;
while(l < r && (Bo < 0 || Co < 0)) {
Bo += (s[l] == B);
Co += (s[l] == C);
l += 1;
}
if(Bo == 0 && Co == 0) {
std::cout << "1\n";
std::cout << l + 1 << ' ' << r << ' ' << A << std::endl;
return 0;
}
}
} while(std::next_permutation(p.begin(), p.end()));;
p = ABC; do {
static int cnt[128];
memset(cnt, 0, sizeof(cnt));
const char A = p[0], B = p[1], C = p[2];
int p1 = 0;
while(p1 < tn && cnt[A] < n) cnt[s[p1++]] += 1;
// std::cerr << cnt[A] << ' ' << cnt[B] << ' ' << cnt[C] << std::endl;
if(cnt[A] < n || cnt[B] > n || cnt[C] > n) continue;
int p2 = p1 + n - cnt[B];
std::cout << "2\n";
std::cout << p1 + 1 << ' ' << p2 << ' ' << B << char(10);
std::cout << p2 + 1 << ' ' << tn << ' ' << C << char(10);
return 0;
} while(std::next_permutation(p.begin(), p.end()));
std::cerr << "FUCK\n";
return 0;
}
M. Counting Phenomenal Arrays
奇妙大力搜索题
直觉告诉我们这个序列一定是由大量的\(1\)和少量的非\(1\)数构成的
同时非\(1\)的数的个数必须大于\(1\),这就保证了其中最大的数是根号级别的
并且由于非\(1\)的数最小为\(2\),这就保证了非\(1\)的数的个数是\(\log\)级别的
综合上述不难发现非\(1\)数的取法很少,我们再强制给它定个序,规定它单调不升排列
最后在乘上重排的方案数,直接爆搜+剪枝即可通过此题
#include <bits/stdc++.h>
using llsi = long long signed int;
constexpr int $n = 400020;
llsi P, n;
llsi ksm(llsi a, llsi b) {
llsi res = 1;
while(b) {
if(b & 1) res = res * a % P;
a = a * a % P;
b >>= 1;
}
return res;
}
llsi fac[$n], facinv[$n];
void prep(int n) {
fac[0] = 1ll;
for(int i = 1; i <= n; ++i) fac[i] = fac[i - 1] * i % P;
facinv[n] = ksm(fac[n], P - 2);
for(int i = n; i >= 1; --i) facinv[i - 1] = facinv[i] * i % P;
return ;
}
llsi C(llsi a, llsi b) {
return fac[a] * facinv[b] % P * facinv[a - b] % P;
}
llsi f[$n], vis = 0;
void dfs(llsi prod, llsi sum, llsi prep, llsi cc, llsi dd) {
f[cc + prod - sum] += dd * C(cc + prod - sum, cc) % P;
vis += 1;
for(llsi i = 2; i < prep; ++i) {
llsi nprod = prod * i, nsum = sum + i;
if(cc + 1 + nprod - nsum > n) break;
for(llsi j = 1; cc + j + nprod - nsum <= n; ++j) {
dfs(nprod, nsum, i, cc + j, dd * C(cc + j, j) % P);
nprod *= i; nsum += i;
}
}
return ;
}
int main() {
std::cin >> n >> P;
prep(n + 10);
dfs(1, 0, n + 10, 0, 1);
for(int i = 2; i <= n; ++i) std::cout << f[i] % P << char(i == n ? 10 : 32);
// std::cerr << "vis = " << vis << char(10);
return 0;
}
N. A-series
签到,倒着贪心一遍即可
#include<cstdio>
#include<iostream>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int n,a[N],b[N],ans;
signed main()
{
RI i; for (scanf("%lld",&n),++n,i=1;i<=n;++i) scanf("%lld",&a[i]);
for (i=1;i<=n;++i) scanf("%lld",&b[i]);
for (i=n;i>=1;--i)
{
if (a[i]>=b[i]) continue;
int tmp=(b[i]-a[i]+1)/2;
ans+=tmp; a[i-1]-=tmp;
}
if (a[i]<0) return puts("-1"),0;
return printf("%lld",ans),0;
}
Postscript
明天徐神疑似来不了,看我直接原形毕露
标签:Europe,std,CI,include,Contest,int,Regional,llsi,now From: https://www.cnblogs.com/cjjsb/p/17971301