CodeCraft-19 and Codeforces Round #537 (Div. 2) Editorial

本文详细解析了CodeCraft-19及Codeforces Round #537(Div.2)的五道题目(A-E),涵盖字符串匹配、动态规划、树形DP、组合数学及虚树构建等算法技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CodeCraft-19 and Codeforces Round #537 (Div. 2) Editorial


 

 

 A

不说了

  • 代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
char s1[N],s2[N];
int main()
{
	scanf("%s",s1+1);
	scanf("%s",s2+1);
	int len=strlen(s1+1);
	int len2=strlen(s2+1);
	if(len!=len2){printf("No\n");return 0;}
	for(int i=1;i<=min(len,len2);i++){
		int tmp1=0,tmp0=0;
		if(s1[i]=='a'||s1[i]=='e'||s1[i]=='i'||s1[i]=='u'||s1[i]=='o'){
			tmp1=1;
		}
		if(s2[i]=='a'||s2[i]=='e'||s2[i]=='i'||s2[i]=='u'||s2[i]=='o'){
			tmp0=1;
		}
		if(tmp0!=tmp1){
			printf("No\n");
			return 0;
		}
	}
	printf("Yes\n");
}

B

考场爆int爽了。不说了。

  • 代码
#include<bits/stdc++.h>
using namespace std;
typedef long double db;
typedef long long ll;
db ans;
const int N=1e6+5;
int n,m,k;
ll c[N];
int main()
{
	cin>>n>>k>>m;
	for(int i=1;i<=n;i++){
		cin>>c[i];
	}sort(c+1,c+n+1);
	for(int i=n-1;i;i--){
		c[i]+=c[i+1];
	}
	for(int i=1;i<=n;i++){
		//cout<<c[i]<<endl;
		db tot=n-i+1;
		if(i-1>m)break;
		db rst=1.00/tot*(db)(min((ll)k*(n-i+1),(ll)(m-i+1)));
		ans=max(ans,(db)c[i]/tot+rst);
		//cout<<ans<<endl;
	}
	printf("%.10Lf\n",ans);
}

C

动态开点之后树形dp。没了

  • 代码
#include<bits/stdc++.h>
using namespace std;
int n,k;
typedef long long ll;
const int N=32*100000+5;
ll A,B;
ll t[N];int lch[N],rch[N];
int rt,cnt;
inline void add(int &x,ll l,ll r,ll pos){
	if(!x)x=++cnt;
	t[x]++;
	if(l==r)return;
	int mid=(l+r)>>1;
	if(pos>mid)add(rch[x],mid+1,r,pos);
	else add(lch[x],l,mid,pos);
}
ll f[N];
void dfs(int x,int l,int r){
	if(x==0)return;
	if(l==r){
		if(t[x]==0)f[x]=A;
		if(t[x]>0)f[x]=(ll)t[x]*(r-l+1)*B;return;
	}
	int mid=(l+r)>>1;
	dfs(lch[x],l,mid);dfs(rch[x],mid+1,r);
	f[x]=f[lch[x]]+f[rch[x]];
	if(t[x]>0)f[x]=min(f[x],B*(ll)(r-l+1)*t[x]);
	else if(t[x]==0)f[x]=min(f[x],A);
}

int main()
{
	cin>>n>>k>>A>>B;
	f[0]=A;
	for(int i=1;i<=k;i++){
		int p;cin>>p;
		add(rt,1,1<<n,p);
	}
	dfs(rt,1,1<<n);
	cout<<f[rt]<<endl;
}

D

考场读错题导致自闭。

确定了哪个在哪边之后计数随便搞,然后你直接枚举字符然后背包除回来就行了

  • 代码(粘的)
#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define ll long long
using namespace std;
const int N=1e5+100,mod=1e9+7;
int n,q,cnt[55],dp[N],f[N],fac[N],inv[N],res[55][55]; char s[N];
int id(char c){
	return 'A'<=c&&c<='Z'?c-'A':c-'a'+26;
}
int ksm(int x,int y){
	int s=1;
	for (;y;y>>=1,x=(ll)x*x%mod) if (y&1) s=(ll)s*x%mod;
	return s;
}
void init(int n){
	fac[0]=1;
	rep (i,1,n) fac[i]=(ll)fac[i-1]*i%mod;
	inv[n]=ksm(fac[n],mod-2);
	for (int i=n-1;~i;i--) inv[i]=(ll)inv[i+1]*(i+1)%mod;
}
int main(){
	scanf("%s%d",s+1,&q); n=strlen(s+1); init(n);
	rep (i,1,n) cnt[id(s[i])]++;
	dp[0]=1;
	rep (i,0,51) if (cnt[i])
		for (int j=n/2;j>=cnt[i];j--) dp[j]=(dp[j]+dp[j-cnt[i]])%mod;
	int v=(ll)fac[n/2]*fac[n/2]%mod;
	rep (i,0,51) v=(ll)v*inv[cnt[i]]%mod;
	rep (x,0,51) rep (y,0,51){
		rep (i,0,n/2) f[i]=dp[i];
		rep (i,cnt[x],n/2) f[i]=(f[i]+mod-f[i-cnt[x]])%mod;
		if (x!=y)
			rep (i,cnt[y],n/2) f[i]=(f[i]+mod-f[i-cnt[y]])%mod;
		res[x][y]=(ll)f[n/2]*v%mod*2%mod;
	}
	while (q--){
		int x,y; scanf("%d%d",&x,&y);
		printf("%d\n",res[id(s[x])][id(s[y])]);
	}
	return 0;
}

E

一眼虚树是什么鬼?

dp的话是按照到rt的关键点个个数(记为H)排序来更新,复杂度k*m

然后你可以直接跑一个lca然后跑一个dep求出H或者你可以直接建虚树(比较懒就粘的建虚树的板子)

  • 代码(因为直接粘的某道题的所以可能有些地方比较鬼畜)
/* based on bzoj 2286 */
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
typedef long long ll;
int anc[N][22];
ll mn[N];
const ll INF=1000000000000000000;
int n,m,num,dfn[N],dep[N],point[N];
bool cmp(const int a,const int b) {return dfn[a]<dfn[b];}
namespace Tr_all {
	int hed[N],to[N];ll val[N];int cnt,nxt[N];
	inline void adde(int u,int v,ll w) {
		++cnt;
		val[cnt]=w,to[cnt]=v,nxt[cnt]=hed[u];
		hed[u]=cnt;
	}
	inline void dfs(int x,int pre) {
		dfn[x]=++num;
		dep[x]=dep[pre]+1;
		if(x==1)mn[x]=INF;
		anc[x][0]=pre;
		for(int i=1; 1<<i<=n; i++) {
			anc[x][i]=anc[anc[x][i-1]][i-1];
		}
		for(int i=hed[x]; i; i=nxt[i]) {
			int v=to[i];
			if(v==pre)continue;
			mn[v]=min(mn[x],(ll)val[i]);
			dfs(v,x);
		}
	}
	int LCA(int x,int y) {
		if(dep[x]<dep[y])swap(x,y);
		for(int i=19; ~i; i--)if(dep[anc[x][i]]>=dep[y])x=anc[x][i];
		if(x==y)return x;
		for(int i=19; ~i; i--)if(anc[x][i]!=anc[y][i])x=anc[x][i],y=anc[y][i];
		return anc[x][0];
	}
}
using Tr_all::LCA;
int MX,rt;
bool ch[N];int nowid;
ll dp[N];bool flg=0;
namespace Tr_cur {
	int hed[N],to[N],nxt[N],cnt;
	int H[N];
	inline void adde(int u,int v) {
		//cout<<u<<" "<<v<<endl;
		if(u==v)return;
		++cnt;to[cnt]=v,nxt[cnt]=hed[u];hed[u]=cnt;
		++cnt;to[cnt]=u,nxt[cnt]=hed[v];hed[v]=cnt;
	}
	inline void clear() {cnt=0;}
	inline void DP(int x,int pre) {
		H[x]=H[pre];
		if(ch[x]){
			ch[x]=0;if(H[x]>MX){flg=1;}
			for(int i=MX;i;i--){
				dp[i]=dp[i]*max(0ll,(ll)(i-H[x]))%1000000007ll+dp[i-1];
				dp[i]%=1000000007ll;
			}
			dp[0]=0;
			H[x]++;
		}
		for(int i=hed[x]; i; i=nxt[i]) {
			int v=to[i];if(v==pre||v==x)continue;
			DP(v,x);
		}
		hed[x]=0;ch[x]=0;
		/* Myclear */
	}
}
using Tr_cur::DP;
int stk[N],top;
 
int main()
{
	scanf("%d",&n);
	scanf("%d",&m);
	for(int i=1; i<n; i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		Tr_all::adde(u,v,1);Tr_all::adde(v,u,1);
	}
	Tr_all::dfs(1,0);
	while(m--) {
		int tot;
		scanf("%d",&tot);scanf("%d%d",&MX,&rt);
		for(int i=1; i<=tot; i++){ scanf("%d",&point[i]); ch[point[i]]=1;}
		point[++tot]=rt;
		sort(point+1,point+tot+1,cmp);
		stk[(top=1)]=1;
		/*insert*/
		for(int i=1; i<=tot; i++) {
			int u=point[i];
			int lca=LCA(u,stk[top]);
			if(top==1) {stk[++top]=u;continue;}
			if(lca==stk[top]){stk[++top]=u;continue;}
			while(top>1&&dep[stk[top-1]]>dep[lca]) {
				Tr_cur::adde(stk[top-1],stk[top]);
				--top;
			}
			if(dep[stk[top]]>dep[lca]) {
				Tr_cur::adde(lca,stk[top]);
				top--;
			}
			if(dep[stk[top]]<dep[lca]) stk[++top]=lca;
			stk[++top]=u;
		}
		while(--top) Tr_cur::adde(stk[top],stk[top+1]);
		/**/
		Tr_cur::H[rt]=0;flg=0;
		for(int i=0;i<=MX;i++){dp[i]=0;}
		dp[0]=1;
		DP(rt,0);
		ll ans=0;
		for(int i=1;i<=MX;i++){ans+=dp[i];ans%=1000000007;}
		printf("%lld\n",ans);
		Tr_cur::clear();
	}
}

没了

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值