ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ARC 115 题解

2022-05-20 22:32:20  阅读:198  来源: 互联网

标签:rs int 题解 ll mid long 115 ARC mod


A

显然如果 \(x\) 和 \(y\) 有偶数个位置不同,那么一定是可以有相同数量的。

那么只要考虑有奇数个位置不同的情况,那么方案数就是通过有奇数个 \(1\) 的和有偶数个 \(1\) 的配对来贡献的。

于是扫一遍统计一下就好了。

#include <bits/stdc++.h>
typedef long long ll;
const int N=1e5+10;
int n,m,c[2];
char s[100];
int main(){
	scanf("%d%d",&n,&m);
	int cnt=0;
	for(int i=1;i<=n;++i){
		scanf("%s",s+1),cnt=0;
		for(int j=1;j<=m;++j)if(s[j]=='1')++cnt;
		++c[cnt%2];
	}
	// printf("%d %d\n",c[0],c[1]);
	printf("%lld\n",1ll*c[0]*c[1]);
	return 0;
}

B

观察发现若相邻两行或者两列的差值不同,那么是不存在符合的序列。

我们求出第一列的最小值,然后让 \(B\) 是第一列中的数字减去最小值,然后 \(A\) 通过左上角就可以计算出来。

#include <bits/stdc++.h>
typedef long long ll;
const int N=510;
int n,c[N][N],a[N],b[N];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)scanf("%d",&c[i][j]);
    for(int i=2;i<=n;++i){
        int t=c[i][1]-c[i-1][1];
        for(int j=2;j<=n;++j)if(c[i][j]-c[i-1][j]!=t){
            puts("No");
            return 0;
        }
    }
    for(int j=2;j<=n;++j){
        int t=c[1][j]-c[1][j-1];
        for(int i=2;i<=n;++i)if(c[i][j]-c[i][j-1]!=t){
            puts("No");
            return 0;
        }
    }
    int mn=(1<<30);
    for(int i=1;i<=n;++i)mn=std::min(mn,c[1][i]);
    for(int i=1;i<=n;++i){
        b[i]=c[1][i]-mn;
        a[i]=c[i][1]-c[1][1]+mn;
    }
    for(int i=1;i<=n;++i)if(a[i]<0||b[i]<0){
        puts("No");
        return 0;
    }
    puts("Yes");
    for(int i=1;i<=n;++i)printf("%d ",a[i]);
    puts("");
    for(int i=1;i<=n;++i)printf("%d ",b[i]);
    puts("");
    return 0;
}

C

注意到我们可以通过质因数个数 \(+1\) 来构造答案,这样一定是最大值最小的。

为什么呢?我们设 \(2^k\) 是 \(n\) 中最大的 \(2\) 的次幂,那么 \(a_1 , a_2 , \cdots , a_{2^k}\) 都要不一样,那么最大值至少要 \(k+1\),与我们所构造的相同。

#include <bits/stdc++.h>
typedef long long ll;
const int N=1e5+10;
int n,pr[N],tot,cnt[N];
bool vis[N];
void init(){
    cnt[1]=1;
    for(int i=2;i<=N-10;++i){
        if(!vis[i])pr[++tot]=i,cnt[i]=1;
        for(int j=1;j<=tot&&i*pr[j]<=N-10;++j){
            vis[i*pr[j]]=1,cnt[i*pr[j]]=cnt[i]+1;
            if(i%pr[j]==0)break;
        }
    }
}
int main(){
    init(),scanf("%d",&n);
    for(int i=1;i<=n;++i)(i==1)?printf("1 "):printf("%d ",cnt[i]+1);
    puts("");
    return 0;
}

D

注意到一个事实:一个图里奇度数的点的数量不会是偶数。

分三种情况考虑:

  • 两个非奇度数点连边,奇度数点加 \(2\),为偶数。
  • 两个奇度数点连边,奇度数点数减 \(2\),为偶数。
  • 一个奇度数点,一个非奇度数点连边,奇度数点数不变,为偶数。

所以只要考虑 \(k\) 为奇数的情况。

先考虑图为一棵树的情况,我们可以通过选出 \(k\) 个点,然后删掉这些点的叶子,删成奇度数,删法是唯一的,所以方案数是 \(\binom{\mid V \mid}{k}\)。

当为连通图时,我们考虑一棵生成树,生成树的方案同上,剩下的 \(\mid E \mid - \mid V \mid + 1\) 条边每条都可以选或者不选,方案数为 \(2^{\mid E \mid - \mid V \mid + 1}\)。

还要注意到一个细节,题目并没有保证给出的图是连通的,所以我们要对每个连通块分别计算。

记 \(f(i,j)\) 表示前 \(i\) 个连通块,最后一个选了 \(j\) 的点的方案数。

那么 \(f(i,j)=\displaystyle \sum_{k=0}^{\min(j,\mid V \mid)} f(i-1,j-k) \times 2^{\mid E \mid - \mid V \mid + 1} \times \binom{\mid V \mid}{k}\)。

时间复杂度 \(\mathcal{O}(n^2)\),可以通过 NTT 做到 \(\mathcal{O}(n \log^2 n)\)。

#include <bits/stdc++.h>
typedef long long ll;
const int N=5010;
const int mod=998244353;
int n,m,fa[N],cnte[N],sz[N];
ll f[N][N],fac[N],ifac[N];
void init(){
	fac[0]=fac[1]=ifac[0]=ifac[1]=1;
	for(int i=2;i<=N-10;++i){
		fac[i]=1ll*i*fac[i-1]%mod;
		ifac[i]=1ll*(mod-mod/i)*ifac[mod%i]%mod;
	}
	for(int i=2;i<=N-10;++i)ifac[i]=ifac[i]*ifac[i-1]%mod;
}
ll binom(int n,int m){
	return fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
ll fastpow(ll a,int b){
	ll ret=1;
	for(;b;b>>=1,a=a*a%mod)if(b&1)ret=ret*a%mod;
	return ret;
}
int main(){
	scanf("%d%d",&n,&m);
	init();
	for(int i=1;i<=n;++i)fa[i]=i,cnte[i]=0,sz[i]=1;
	for(int i=1;i<=m;++i){
		int u,v;scanf("%d%d",&u,&v);
		u=find(u),v=find(v);
		if(u==v)++cnte[u];
		else{
			fa[u]=v;
			sz[v]+=sz[u],cnte[v]+=cnte[u]+1;
		}
	}
	f[0][0]=1;
	int cnt=0;
	for(int i=1;i<=n;++i)if(fa[i]==i){
		++cnt;
		for(int j=0;j<=n;++j)for(int k=0;k<=std::min(j,sz[i]);k+=2)
			f[cnt][j]=(f[cnt][j]+f[cnt-1][j-k]*binom(sz[i],k)%mod*fastpow(2ll,cnte[i]-sz[i]+1)%mod)%mod;
			// printf("%d %d %d %d %lld\n",j,k,cnte[i],sz[i],binom(sz[i],k));
	}
	for(int i=0;i<=n;++i)printf("%lld\n",f[cnt][i]);
	return 0;
}

E

考虑容斥原理。

记 \(f(i)\) 表示做到 \(i\) 的答案,那么 \(f(i)=\displaystyle \sum_{j=1}^{i-1} f(j) \times \min_{k=j+1}^i a_k \times (-1)^{i-j-1}\)。

那么我们通过单调栈求出 \(a_k\) 作为最小值的区间,然后维护一下 \(f\) 的和,区间乘法,单点加法,用线段树维护一下。

#include <bits/stdc++.h>
typedef long long ll;
#define gc() (_S==_T&&(_T=(_S=_B)+fread(_B,1,1<<20,stdin),_S==_T)?EOF:*_S++)
char _B[1<<20],*_S=_B,*_T=_B;
int rd(){
	int x=0,f=0;char ch=gc();
	while(ch<'0'||ch>'9')(ch=='-')&&(f=1),ch=gc();
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=gc();
	return f?-x:x;
}
const int N=5e5+10;
const int mod=998244353;
int n,a[N],stk[N],cnt=0,tp=0;
ll f[N];
struct node{
	int l,r;
	ll tag,v,f;
	node *ls,*rs;
}tr[N<<2],*rt;
void pushup(node *o){
	o->v=(o->ls->v+o->rs->v)%mod;
	o->f=(o->ls->f+o->rs->f)%mod;
}
void pushdown(node *o){
	if(o->tag!=1){
		o->ls->f=o->ls->v*o->tag%mod;
		o->rs->f=o->rs->v*o->tag%mod;
		o->ls->tag=o->ls->tag*o->tag%mod;
		o->rs->tag=o->tag*o->rs->tag%mod;
		o->tag=1;
	}
}
void build(node *o,int l,int r){
	o->l=l,o->r=r,o->tag=1;
	if(l==r)return;
	int mid=(l+r)>>1;
	o->ls=&tr[++cnt],o->rs=&tr[++cnt];
	build(o->ls,l,mid),build(o->rs,mid+1,r);
}
void A(node *o,int p,ll v){
	if(o->l==o->r){
		o->v=v,o->f=v*o->tag%mod;
		return;
	}
	int mid=(o->l+o->r)>>1;
	pushdown(o);
	if(p<=mid)A(o->ls,p,v);
	else A(o->rs,p,v);
	pushup(o);
}
void M(node *o,int ql,int qr,ll v){
	if(ql<=o->l&&o->r<=qr){
		o->tag=v,o->f=o->v*v%mod;
		return;
	}
	int mid=(o->l+o->r)>>1;
	pushdown(o);
	if(ql<=mid)M(o->ls,ql,qr,v);
	if(qr>mid)M(o->rs,ql,qr,v);
	pushup(o);
}
int main(){
	n=rd(),rt=&tr[0],build(rt,1,n);
	for(int i=1;i<=n;++i)a[i]=rd();
	A(rt,1,mod-1),stk[++tp]=0;
	for(int i=1;i<=n;++i){
		while(tp&&a[stk[tp]]>=a[i])--tp;
		M(rt,stk[tp]+1,i,a[i]);
		stk[++tp]=i;
		f[i]=(i&1)?(mod-rt->f):rt->f;
		A(rt,i+1,(i&1)?f[i]:(mod-f[i]));
	}
	printf("%lld\n",f[n]);
	return 0;
}

F

不会,咕了。

标签:rs,int,题解,ll,mid,long,115,ARC,mod
来源: https://www.cnblogs.com/Lonely-233/p/16293872.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有