首页 > 其他分享 >2021 ICPC Southeastern Europe Regional Contest

2021 ICPC Southeastern Europe Regional Contest

时间:2024-01-17 22:11:30浏览次数:20  
标签:Europe std CI include Contest int Regional llsi now

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

相关文章

  • AtCoder Beginner Contest 336
    题目链接:AtCoderBeginnerContest336A-LongLoong题意:输出Long,其中'o'的数量等于n解题思路:签到(其实没看清楚题目wa了一发)查看代码voidsolve(){ intn; cin>>n; cout<<'L'; while(n--)cout<<'o'; cout<<"ng";}......
  • 2020-2021 ACM-ICPC Latin American Regional Programming Contest J. Job Allocator
    Preface今天因为下午被强行拉回老家了,而且没带电脑回去然后就变成了徐神和祁神两个人写,我拿个手机在后面口胡了3h最后变成了在缺我一个人的前提下还能4h过10题的情况,感觉就算我在的话最多就是快点过H然后把剩下的时间拿去写个J这场因为没啥参与就不写整场的博客了,把赛后写的这......
  • AtCoder Grand Contest 046 F Forbidden Tournament
    洛谷传送门AtCoder传送门太厉害了!!!!!!首先竞赛图有个性质,若存在环则一定存在三元环。先把DAG的情况(一条链)特判了。然后缩点。发现非链底的部分不能存在大小\(>1\)的SCC。所以枚举非链底的部分有多少点,转化为SCC的情况。发现对于任意点(设为\(1\)号点),它的前驱连成一条链......
  • Atcoder Beginner Contest 330 题解
    AtCoderBeginnerContest330题解A-CountingPasses签到voidShowball(){intn,l;cin>>n>>l;intcnt=0;for(inti=0;i<n;i++){intx;cin>>x;cnt+=(x>=l);}cout<<cnt<<endl;}B-Minimize......
  • AtCoder Beginner Contest 336
    B-CTZ难度:⭐题目大意给定一个数n,输出其二进制最后有几个连续的0;解题思路模拟一下就行;神秘代码#include<bits/stdc++.h>#defineintlonglong#defineIOSios::sync_with_stdio(false);cin.tie(0);cout.tie(0);#defineendl'\n'usingnamespacestd;......
  • AtCoder Beginner Contest 336
    AtCoderBeginnerContest336比赛链接A-LongLoong思路:简单的模拟代码:#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongvoidsolve(){intn;//cin>>n;cin>>n;cout<<"L";for(inti=......
  • AtCoder Grand Contest 051 D C4
    洛谷传送门AtCoder传送门下文的点\(1,2,3,4\)对应原题面中的\(S,T,U,V\)。直接对无向图欧拉回路计数不太好做。考虑给边定向。枚举有\(i\)条边是从\(1\)到\(2\)的。那么\(2\to1\)有\(a-i\)条边。由于这个图必须满足每个点的入度等于出度,设\(j\)条\(......
  • AtCoder Beginner Contest 336
    AtCoderBeginnerContest336A-LongLoong#include<bits/stdc++.h>#defineendl'\n'//#defineintlonglongusingnamespacestd;voidsolve(){ intx; cin>>x; cout<<"L"; while(x--)cout<<"o&q......
  • 2021-2022 ACM-ICPC Latin American Regional Programming Contest
    Preface唉最近天天前期犯病,读错题占用大量机时还红温,纯在靠队友兜底H板题但刚开始因为没打印自己的KM板子就写个了MCMF上去,然后直接TLE飞,后面找了个别人的板子抄上去才过,I题一个傻逼题题意读错爆WA两发最后1h把L题扔给队友然后跑去看ECF滚榜直播了,只能说从此清北电的格局打开了......
  • 2021-2022 ICPC Northwestern European Regional Programming Contest (NWERC 2021)
    Preface和昨天刚好相反,前期极度崩盘2h2题而且一堆银铜牌题不会但好在后面稳扎稳打慢慢追回来了一点,最后超高罚时8题收场这场一边打一边看ECF的实况,最后看到同校的Wifi暴打全场,实在是ORZA.AccessDenied签到,首先暴力问出长度然后从前往后一位一位确定即可注意实现的时候不......