[YDRG#001] 提瓦特环游记 · 云斗杯 · 七月 Golden 组模拟赛 整理分析--zhengjun

link

总体评价:因为 K 了,所以好评,练一下思维蛮好的,质量不错

比赛 2.5h K 的。

#A. 诗人小 G 初进 OI 界

标准送分,输出 s2a2a1

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=1e6+10;
int n,a[N];
void read(ll &x){
	char c;
	for(x=0;!isdigit(c=getchar()););
	for(;x=x*10+c-48,isdigit(c=getchar()););
}
int main(){
	freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	ll x,y;
	read(x),read(y);
	cout<<(y-a[2])/a[1];
	return 0;
}

#B. 派蒙是最好的伙伴!

Ai=j=1iaj,Bi=j=1ibj

左上角为 (a,x),右下角为 (b,y) 的矩阵中 1 的个数即为 (AbAa1)×(ByBx1)=k

然后枚举 k 的因数 AbAa1O(n) 计算答案即可通过。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=3e5+10,mod=998244353;
int n,a[N],b[N],ta[N],tb[N];
ll k,ans;
void calc(int x,int y){
	ll t1=0,t2=0;
	for(int i=0;i+x<=a[n];i++)t1+=1ll*ta[i]*ta[i+x];
	for(int i=0;i+y<=b[n];i++)t2+=1ll*tb[i]*tb[i+y];
	ans+=(t1%mod)*(t2%mod)%mod;
}
int main(){
	freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	scanf("%d%lld",&n,&k);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i]+=a[i-1];
	for(int i=1;i<=n;i++)scanf("%d",&b[i]),b[i]+=b[i-1];
	for(int i=0;i<=n;i++)ta[a[i]]++,tb[b[i]]++;
	for(ll i=1;i*i<=k;i++)if(k%i==0){
		if(max(i,k/i)>n)continue;
		calc(i,k/i);
		if(i*i<k)calc(k/i,i);
	}
	cout<<ans%mod;
	return 0;
}

#C. 层岩巨渊中的最长环

构造+有但不多的思维

首先考虑对于一个质数 p(接下来的 p 都表示质数),若 p×3>n,那么 p 的度数为 1,一定不能成为环上的点。

所以考虑所有满足 p|i,p×3ni

对于所有 p>3,构造 p×2p×kp×kp×3

然后拼接所有的这样的链:

p×2p×kp×kp×3p×3p×kp×kp×2p×2p×kp×kp×3

最后考虑所有的 2k,3k,一共三段,第一段至少有一段可以和 2k3k 链连接,剩下两个连接点用 6,12 连接即可。

要求 n12,所以特判所有 n<12

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=5e5+10;
int T,n;
int cnt,pri[N],vis[N];
void init(int n=5e5){
	for(int i=2;i<=n;i++){
		if(!vis[i])pri[++cnt]=i;
		for(int j=1;j<=cnt&&i*pri[j]<=n;j++){
			vis[i*pri[j]]=1;
			if(i%pri[j]==0)break;
		}
	}
}
int k,ans[N];
void get(){
	scanf("%d",&n),cerr<<n<<':';
	fill(vis,vis+1+n,0);
	if(n<=12){
		if(n<=3)puts("0");
		else if(n<=5)puts("2 2 4");
		else if(n<=7)puts("3 2 4 6");
		else if(n<=9)puts("4 2 4 6 8");
		else if(n<=11)puts("5 2 4 6 8 10");
		else puts("8 2 4 8 10 6 3 9 12");
		return;
	}
	k=0;
	for(int i=3;i<=cnt&&pri[i]*3<=n;i++){
		int tag=ans[k]%2==0;
		if(tag)ans[++k]=pri[i]*2;
		else ans[++k]=pri[i]*3;
		assert(!vis[pri[i]]*2);
		assert(!vis[pri[i]]*3);
		vis[pri[i]*2]=vis[pri[i]*3]=1;
		for(int j=pri[i];j<=n;j+=pri[i]){
			if(!vis[j])ans[++k]=j,vis[j]=1;
		}
		if(tag)ans[++k]=pri[i]*3;
		else ans[++k]=pri[i]*2;
	}
	if(ans[k]%3==0){
		for(int i=3;i<=n;i+=3)if(i!=6&&i!=12){
			if(!vis[i])ans[++k]=i,vis[i]=1;
		}
		ans[++k]=6,vis[6]=1;
		for(int i=2;i<=n;i+=2)if(i^12){
			if(!vis[i])ans[++k]=i,vis[i]=1;
		}
		ans[++k]=12,vis[12]=1;
	}else{
		for(int i=2;i<=n;i+=2)if(i!=6&&i!=12){
			if(!vis[i])ans[++k]=i,vis[i]=1;
		}
		ans[++k]=6,vis[6]=1;
		for(int i=3;i<=n;i+=3)if(i^12){
			if(!vis[i])ans[++k]=i,vis[i]=1;
		}
		ans[++k]=12,vis[12]=1;
	}
	printf("%d",k);
	for(int i=1;i<=k;i++)printf(" %d",ans[i]);
	puts("");
}
int main(){
	freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	for(init(),scanf("%d",&T);T--;)get();
	return 0;
}

#D. 于是他的杠精开始了

数学题+思维,设:

p=gcd(a,b),q=gcd(c,d),A=ap,B=bp,C=cq,D=dq

代入原式,得到:

B2A2p2A2B2=D2C2q2C2D2

不管分子分母是否整除,直接令分子分母各自相等:

{B2A2=D2C2pAB=qCDgcd(p,q)=1

这样令 A,B,C,D[1,2×103]

每个 B2A2 开个 vector,枚举 B2A2

然后枚举一对 (A,B)(C,D),可以直接计算 p,q 验证一下 B×pC×q 即可。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=2e3+10,V=4e6+10;
int n=2e3,m=4e6,cnt;
struct zj{
	int A,B;
};
vector<zj>p[V];
int main(){
	freopen(".in","r",stdin);
	freopen(".out","w",stdout);
	cin>>cnt;
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)if(__gcd(i,j)==1)
			p[j*j-i*i].push_back({i,j});
	for(int i=1;i<=m&&cnt;i++){
//		cerr<<p[i].size()<<endl;
		int len=p[i].size();
		for(int x=0;x<len&&cnt;x++){
			for(int y=0;y<x&&cnt;y++){
				int A=p[i][x].A,B=p[i][x].B;
				int C=p[i][y].A,D=p[i][y].B;
				int AB=A*B,CD=C*D;
				int g=__gcd(AB,CD);
				int p=CD/g,q=AB/g;
				ll a=1ll*A*p,b=1ll*B*p,c=1ll*C*q,d=1ll*D*q;
				if(b>c)continue;
				printf("%lld %lld %lld %lld\n",a,b,c,d);
				cnt--;
			}
		}
	}
	cerr<<cnt;
	return 0;
}

#E. 来自璃月的生日礼物

计数题,应该是本题的压轴了。

首先转化条件:

a=b=ni[1,n],j=1iajj=1ibj

写了个 O(n5) 的 dp,前缀和优化到 O(n3),发现难以进一步优化。

考虑换个视角。

使用挡板法,n1 个空中放入 m1 个挡板。

这一步是解题的关键。

要求 a 中第 i 个挡板在 b 中第 i 个挡板后面。

发现每个空只有四种状态:

  1. a,b 都有挡板

  2. a,b 都没有挡板

  3. a 有挡板

  4. b 有挡板

发现 1,2 都不影响要求的限制,且 3,4 的情况数相同。

仔细分析一下,限制可以转化为 4,3 按顺序组成括号序列即可 4(,3)

所以枚举 3,4 的个数 i,计算答案:

ans=i=0m1(n12i)×fi×(n12im1i)

其中 f 为卡特兰数。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=5e6+10,mod=1e9+7;
int n,m;
int fac[N*2],ifac[N*2];
ll qpow(ll x,ll y=mod-2){
	ll ans=1;
	for(;y;(x*=x)%=mod,y>>=1)if(y&1)(ans*=x)%=mod;
	return ans;
}
void init(int n=::n*2){
	for(int i=fac[0]=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
	ifac[n]=qpow(fac[n]);
	for(int i=n;i>=1;i--)ifac[i-1]=1ll*ifac[i]*i%mod;
}
int C(int n,int m){
	if(0>m||m>n)return 0;
	return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
int catalan(int n){
	return (C(n*2,n)-C(n*2,n-1)+mod)%mod;
}
int main(){
	freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	cin>>n>>m;
	if(m>n)return puts("0"),0;
	init();
	int ans=0;
	for(int i=0;i<m;i++){
		ans=(ans+1ll*C(n-1,i*2)*catalan(i)%mod*C(n-1-i*2,m-1-i))%mod;
	}
	cout<<ans;
	return 0;
}

#F. 有根树上求八维偏序

7min 秒掉,因为法老当天下午刚刚讲过 meet in middle。

然后直接拆成 4+4,meet in middle 就做完了。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=2e5+10,K=8;
int n,a[N][K];
char str[10];
vector<int>to[N];
int cnt[5][5][5][5][5][5][5][5];
ll ans;
void dfs(int u){
	for(int i=0;i<a[u][0];i++){
		for(int j=0;j<a[u][1];j++){
			for(int k=0;k<a[u][2];k++){
				for(int x=0;x<a[u][3];x++){
					ans+=cnt[i][j][k][x][a[u][4]][a[u][5]][a[u][6]][a[u][7]];
				}
			}
		}
	}
	for(int i=a[u][4]+1;i<5;i++){
		for(int j=a[u][5]+1;j<5;j++){
			for(int k=a[u][6]+1;k<5;k++){
				for(int x=a[u][7]+1;x<5;x++){
					cnt[a[u][0]][a[u][1]][a[u][2]][a[u][3]][i][j][k][x]++;
				}
			}
		}
	}
	for(int v:to[u])dfs(v);
	for(int i=a[u][4]+1;i<5;i++){
		for(int j=a[u][5]+1;j<5;j++){
			for(int k=a[u][6]+1;k<5;k++){
				for(int x=a[u][7]+1;x<5;x++){
					cnt[a[u][0]][a[u][1]][a[u][2]][a[u][3]][i][j][k][x]--;
				}
			}
		}
	}
}
int main(){
	freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%s",str);
		for(int j=0;j<K;j++)a[i][j]=str[j]-'0'-1;
	}
	for(int i=2,x;i<=n;i++){
		scanf("%d",&x),to[x].push_back(i);
	}
	dfs(1);
	cout<<ans;
	return 0;
}

posted @   A_zjzj  阅读(472)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示