【CSP-S 2019题解】

CSPSCSP-S之后可以说半条腿退役了
如果没那一个失误的话rk14rk14还有救

感觉现在对OIOI的感情也挺复杂的
有些东西自己也还没想明白


Day1

T1T1

模拟即可

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
cs int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
inline ull readu(){
	char ch=gc();
	ull res=0;
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return res;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
ull k;
int n,ans[100];
void solve(int pos,ull ret){
	if(pos==1){
		ans[pos]=ret;
		return;
	}
	ull mid=1;
	mid=mid<<(pos-1);
	mid-=1;
	if(ret<=mid){
		ans[pos]=0;solve(pos-1,ret);return;
	}
	else{
		ans[pos]=1;
		solve(pos-1,mid-ret+mid+1);
		return;
	}
}
int main(){
	freopen("code.in","r",stdin);
	freopen("code.out","w",stdout);
	n=read(),k=readu();
	solve(n,k);
	for(int i=n;i;i--)cout<<ans[i];
	return 0;
}

T2T2

考场debuffdebuff太严重了
不知道为什么这傻逼题就是没想明白

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
inline void readstring(char *s){
	int top=0;
	char ch=gc();
	while(isspace(ch))ch=gc();
	while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
}
cs int N=500005;
char s[N];
int fa[N],pf[N];
int n;
ll anc[N];
vector<int> e[N];
void dfs(int u){
	pf[u]=pf[fa[u]];
	if(s[u]=='(')pf[u]=u;
	else if(pf[u]>0){
		anc[u]=anc[fa[pf[u]]]+1;
		pf[u]=pf[fa[pf[u]]];
	}
	for(int &v:e[u])dfs(v);
}
void dfs2(int u){
	for(int &v:e[u]){
		anc[v]+=anc[u];
		dfs2(v);
	}
}
int main(){
	#ifdef Stargazer
	freopen("lx.cpp","r",stdin);
	#endif
	n=read();
	readstring(s);
	for(int i=2;i<=n;i++)fa[i]=read(),e[fa[i]].pb(i);
	dfs(1),dfs2(1);
	ll ret=0;
	for(int i=1;i<=n;i++)ret^=1ll*i*anc[i];
	cout<<ret;
}

T3T3

不会

Day2Day2

T1T1

先无视n2lceilfrac n 2 ceil的条件,dpdp出总方案
然后容斥用背包dpdp算方案
只需要记使用这个食材和没使用的差即可

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
cs int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int mod=998244353;
inline int add(int a,int b){return (a+=b)>=mod?(a-mod):a;}
inline int dec(int a,int b){return (a-=b)<0?(a+mod):a;}
inline int mul(int a,int b){static ll r;r=1ll*a*b;return (r>=mod)?(r%mod):r;}
inline void Add(int &a,int b){(a+=b)>=mod?(a-=mod):0;}
inline void Dec(int &a,int b){(a-=b)<0?(a+=mod):0;}
inline void Mul(int &a,int b){static ll r;r=1ll*a*b;a=(r>=mod)?(r%mod):r;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
cs int N=105,M=2005,L=103;
char xxx;
int g[N][N],s[N],a[N][M],f[N][2*N];
int n,m;
char yyy;
inline int calc(int p){
	f[0][L]=1;
	for(int i=1;i<=n;i++){
		for(int j=L-i;j<=L+i;j++){
			f[i][j]=f[i-1][j];
			if(j)Add(f[i][j],mul(f[i-1][j-1],a[i][p]));
			Add(f[i][j],mul(f[i-1][j+1],dec(s[i],a[i][p])));
		}
	}
	int res=0;
	for(int k=L+1;k<=L+n;k++)
	Add(res,f[n][k]);
	return res;
}
int main(){
	freopen("meal.in","r",stdin);
	freopen("meal.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			a[i][j]=read();
			Add(s[i],a[i][j]);
		}
	}
	g[0][0]=1;
	for(int i=1;i<=n;i++)
	for(int j=0;j<=i;j++){
		Add(g[i][j],g[i-1][j]);
		if(j)Add(g[i][j],mul(g[i-1][j-1],s[i]));
	}
	int res=0;
	for(int i=1;i<=n;i++)Add(res,g[n][i]);
	for(int i=1;i<=m;i++){
		memset(f,0,sizeof(f));
		Dec(res,calc(i));
	}
	cout<<res<<'
';
	return 0;
} 

T3T3

如果有结论的话回来看证明也挺显然的
但就是没想到

可以直接看毛爷爷的题解

感性伪 证明其实可以考虑把一个序列a1...ana_1...a_n分成递增的2段
那么一定是在位置jj满足a1+...+aj<=aj+1+...+ana_1+...+a_j<=a_{j+1}+...+a_n
a1+...+aj+1>aj+2+....+ana_1+...+a_{j+1}>a_{j+2}+....+a_n切开
那么也就是说分界点一定要尽量靠后

然后单调队列找分解点即可

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll unsigned long long
cs int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=40000005,M=100005;
char xxx;
int n,type,l[M],r[M],p[M],b[N],q[N],pre[N],hd,tl;
ll a[N];
char yyy;
void write(__int128 x){
	if(x>9)write(x/10);
	putchar((x%10)+'0');
}
inline void getans(){
	__int128 ret=0;
	for(int i=n;i;i=pre[i]){
		ret+=(__int128)(a[i]-a[pre[i]])*(a[i]-a[pre[i]]);
	}
	write(ret);
}
int main(){
	n=read(),type=read();
	if(type==0){
		for(int i=1;i<=n;i++)a[i]=read()+a[i-1];
	}
	else{
		ll x=read(),y=read(),z=read();int m;cs ll bas=(1<<30)-1;
		b[1]=read(),b[2]=read(),m=read();
		for(int i=1;i<=m;i++)p[i]=read(),l[i]=read(),r[i]=read();
		for(int i=3;i<=n;i++)b[i]=(x*b[i-1]+y*b[i-2]+z)&bas;
		for(int i=1,j=1;i<=n;i++){
			if(i>p[j])j++;
			a[i]=(b[i]%(r[j]-l[j]+1))+l[j];
		}
		for(int i=1;i<=n;i++)a[i]+=a[i-1];
	}
	for(int i=1;i<=n;i++){
		while(hd<tl&&(a[q[hd+1]]*2-a[pre[q[hd+1]]])<=a[i])hd++;
		pre[i]=q[hd];
		while(hd<=tl&&(a[q[tl]]*2-a[pre[q[tl]]])>=(a[i]*2-a[pre[i]]))tl--;
		q[++tl]=i;
	}
	getans();
	return 0;
}

T3T3

考场已经想出做法了但觉得时间不够为了保险就没去写

直接考虑一个点会有多少边对其有贡献
分成三个部分考虑:
到根的链上的,到根链上点的其他子树的,子树内的

记子树内最大的sizsizcc,一条边断开后子树内的sizsizss
到根链上的需要满足2(ssiz)s,2cs2(s-siz)le s,2cle s
2cs2siz2cle sle 2siz

其他子树的即
2(nssiz)ns,2cns2(n-s-siz)le n-s,2cle n-s
n2sizsn2cn-2sizle sle n-2c

对于子树内需要考虑是哪颗子树
也可以做但比较麻烦
一个方法是以重心做根
那么对于重心以外的点就都不需要考虑子树
对于重心只需要考虑最大的子树和其他子树两种情况即可

然后就完了
为什么我考场不去写啊,傻逼透了

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
cs int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=300005;
int n;
int rt,siz[N],mc[N];
ll ans;
vector<int> e[N];
struct bit{
	int tr[N];
	#define lb(x) (x&(-x))
	inline void clear(){
		memset(tr,0,sizeof(tr));
	}
	inline void update(int p,int k){
		for(;p<=n;p+=lb(p))tr[p]+=k;
	}
	inline int ask(int p,int res=0){
		for(;p>0;p-=lb(p))res+=tr[p];
		return res;
	}
	inline int query(int l,int r){
		return ask(r)-ask(l-1);
	}
}s1,s2;
void dfs1(int u,int fa){
	siz[u]=1;
	bool fg=1;
	for(int &v:e[u]){
		if(v==fa)continue;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(siz[v]>(n>>1))fg=0;
	}
	if(n-siz[u]>(n>>1))fg=0;
	if(fg)rt=u;
}
void dfs2(int u,int fa){
	siz[u]=1,mc[u]=0;
	for(int &v:e[u]){
		if(v==fa)continue;
		dfs2(v,u);
		siz[u]+=siz[v];
		
		chemx(mc[u],siz[v]);
	}
}
void colc(int u,int fa,int k){
	s1.update(siz[u],k);
	for(int &v:e[u]){
		if(v==fa)continue;
		colc(v,u,k);
	}
}
int cnt;
void dfs3(int u,int fa,int lim){
	s2.update(siz[u],1);
	ans+=1ll*u*(s1.query(n-2*siz[u],n-2*mc[u])+s2.query(2*mc[u],2*siz[u]));
	if(siz[u]<=lim)ans+=rt,cnt++;
	for(int &v:e[u]){
		if(v==fa)continue;
		dfs3(v,u,lim);
	}
	s2.update(siz[u],-1);
}
inline void solve(){
	s1.clear(),s2.clear();
	ans=rt=cnt=0,n=read();
	for(int u,v,i=1;i<n;i++){
		u=read(),v=read();
		e[u].pb(v),e[v].pb(u);
	}
	dfs1(1,0);
	dfs2(rt,0);
	int mx=0,semx=0;
	for(int &v:e[rt]){
		if(siz[v]>siz[mx])semx=mx,mx=v;
		else if(siz[v]>siz[semx])semx=v;
		colc(v,rt,1);
	}
	for(int &v:e[rt]){
		colc(v,rt,-1);
		if(v==mx)dfs3(v,rt,n-2*siz[semx]);
		else dfs3(v,rt,n-2*siz[mx]);
		colc(v,rt,1);
	}
	cout<<ans<<'
';
	for(int i=1;i<=n;i++)e[i].clear();
}
int main(){
	int T=read();
	while(T--)solve();
}
原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328355.html