2022牛客暑期多校训练营6 个人题解

57 篇文章 0 订阅
7 篇文章 0 订阅

title :2022牛客暑期多校训练营6 题解
date : 2022-9-22
tags : ACM,练习记录
author : Linno


2022牛客暑期多校训练营6 题解

题目链接 :https://ac.nowcoder.com/acm/contest/33191

补题进度 :6/13

已经补不动题了。

A-Array

可以考虑2的幂次,对于所有 a i a_i ai,我们转化成他在 2 k 2^k 2k次方个数内必须出现一次,那么这样填可以保证题目的条件满足。我们排序之后知道了m的大小,然后填法大概就是直接贪就行了,这个长度会有很多中填法。

//#pragma GCC optimize("Ofast", "inline", "-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define int long long
using namespace std;
const int N=2e6+7;
const int mod=1e9+7;

//int read(){	int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
//void write(int x){if(x>9) write(x/10);putchar(x%10+'0');}
struct node{
	int a,id;
}s[N];

bool cmp(node A,node B){
	return A.a<B.a; 
}

int n,cnt=0,b[N],c[N],bin[33];

void Solve(){
	cin>>n;
	int mi=1;
	bin[0]=1;for(int i=1;i<=30;++i) bin[i]=bin[i-1]<<1;
	for(int i=1;i<=n;++i){ 
		cin>>s[i].a;
		s[i].id=i;
	}
	sort(s+1,s+1+n,cmp);
	for(int i=1;i<=n;++i){
		int k=lower_bound(bin,bin+31,s[i].a)-bin;
		s[i].a=bin[k-1];
	}
	//for(int i=1;i<=n;++i) cout<<i<<" "<<s[i].a<<" "<<s[i].id<<"\n";
	int cnt=1,m=s[n].a;
	for(int i=1;i<=n;++i){
		while(c[cnt]) cnt++;
		int now=cnt;
		while(now<=m){
			c[now]=s[i].id;
			now+=s[i].a;
		}
	}
	cout<<m<<"\n";
	for(int i=1;i<=m;++i) cout<<max(1ll,c[i])<<" ";
	cout<<"\n"; 
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
//  freopen("in.cpp","r",stdin);
//  freopen("out.cpp","w",stdout);
	int T=1;
//	cin>>T;
//	clock_t start,finish;
//	start=clock();
	while(T--){
		Solve();
	}
//	finish=clock();
//	cerr<<((double)finish-start)/CLOCKS_PER_SEC<<endl;
	return 0;
}

B-Eezie and Pie

树上差分,dfs对当前点以及k级祖先打tag,然后统计答案即可。

#include <bits/stdc++.h>
#define maxn 2000005
using namespace std;
int a[maxn],q[maxn],ans[maxn],cnt,d[maxn],n;
vector<int> f[maxn];
void dfs(int x,int fa,int dep)
{
    d[x]++;
    if (dep-a[x]-1>0) d[q[dep-a[x]-1]]--;
    int len=f[x].size();
    for (int i=0;i<len;++i)
        if (f[x][i]!=fa)
        {
            q[++cnt]=f[x][i];
            dfs(f[x][i],x,dep+1);
            --cnt;
        }
}
void getans(int x,int fa)
{
    int len=f[x].size();
    for (int i=0;i<len;++i)
    if (f[x][i]!=fa)
    {
        getans(f[x][i],x);
        ans[x]+=ans[f[x][i]];
    }
    ans[x]+=d[x];
}
int main()
{
    
    cin>>n;
    for (int i=1;i<n;++i)
    {
        int v,u;
        scanf("%d%d",&u,&v);
        f[u].push_back(v);
        f[v].push_back(u);
    }
    for (int i=1;i<=n;++i)
    {
        scanf("%d",&a[i]);
    }
    q[++cnt]=1;
    dfs(1,0,1);
    getans(1,0);
    for (int i=1;i<=n;++i)
        printf("%d ",ans[i]);
    return 0;
}

G-Icon Design

搬砖题,直接看着题写就完事了。

//#pragma GCC optimize("Ofast", "inline", "-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define int long long
using namespace std;
const int N=2e5+7;
const int mod=1e9+7;

//int read(){	int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
//void write(int x){if(x>9) write(x/10);putchar(x%10+'0');}

int n;
char mp[505][505];  //n+2,

void Solve(){
	cin>>n;
	int W=13*n+19,H=4*n+5;
	for(int i=1;i<=H;++i) for(int j=1;j<=W;++j) mp[i][j]='.';
	for(int i=1;i<=W;++i) mp[1][i]=mp[H][i]='*';
	for(int i=1;i<=H;++i) mp[i][1]=mp[i][W]='*';
	for(int i=n+2,j=0;i<=3*n+4;++i,++j) mp[i][n+3+j]=mp[i][n+3]=mp[i][3*n+5]='@'; //N 
	for(int i=3*n+4+(n+2)+1;i<=6*n+8+1;++i) mp[n+2][i]=mp[2*n+3][i]='@'; //F横 
	for(int i=n+2;i<=3*n+4;++i) mp[i][3*n+4+(n+2)+1]='@';   //F竖 
	for(int i=n+2;i<=3*n+4;++i) mp[i][3*n+4+(n+2)+(2*n+3)+(n+2)]='@';  //L竖 
	for(int i=3*n+4+(n+2)+(2*n+3)+(n+2);i<=3*n+4+(n+2)+(2*n+3)+(n+2)+(2*n+2);++i) mp[3*n+4][i]='@';  //L竖 
	for(int i=n+2;i<=3*n+4;++i){
		int k=(i<=H/2)?0:2*n+2;
		mp[i][3*n+4+(n+2)+(2*n+3)+(2*n+3)+(n+2)+(n+1)+k]='@';  //S竖 
	}
	for(int i=3*n+4+(n+2)+(2*n+3)+(2*n+3)+(n+2)+(n+1);i<=3*n+4+(n+2)+(2*n+3)+(2*n+3)+(n+2)+(n+1)+(2*n+2);++i) mp[n+2][i]=mp[2*n+3][i]=mp[3*n+4][i]='@'; //F横 
	for(int i=1;i<=H;++i){
		for(int j=1;j<=W;++j) cout<<mp[i][j];
		cout<<"\n";
	} 
}

signed main(){
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
//  freopen("in.cpp","r",stdin);
//  freopen("out.cpp","w",stdout);
	int T=1;
//	cin>>T;
//	clock_t start,finish;
//	start=clock();
	while(T--){
		Solve();
	}
//	finish=clock();
//	cerr<<((double)finish-start)/CLOCKS_PER_SEC<<endl;
	return 0;
}

I-Line

题解区的代码,非常精妙。因为数据范围很小,我们直接对每个向量建立不同的维度,然后从(0,0)开始,对每个向量,答案都加入当前点集往这个向量的方向走th的倍数长所得的点。

#include<bits/stdc++.h>
#define pii pair<int,int>
#define F first
#define S second
#define mk make_pair
using namespace std;

int th[10];

signed main(){
	th[0]=1;
	for(int i=1;i<10;++i){
		th[i]=th[i-1]*23;
	}
	int n,d;
	scanf("%d%d",&n,&d);
	set<pii>s,ans;
	for(int i=1,x,y;i<=n;++i){
		scanf("%d%d",&x,&y);
		int d=__gcd(x,y);
		s.insert(mk(x/d,y/d));  //插入向量
	}
	ans.insert(mk(0,0));
	int id=-1;
	for(auto dir:s){  //对于所有向量
		++id; //th都要取不同的方向
		auto t=ans; 
		for(auto i:t){
			for(int j=1;j<d;++j){  //取其中d个点
				ans.insert(mk(i.F+j*dir.F*th[id],i.S+j*dir.S*th[id])); //插入点集
			}
		}
	}
	printf("%d\n",ans.size());
	for(auto i:ans) printf("%d %d\n",i.F,i.S);
	return 0;
} 

J-Number Game

我们可以做很多次变换,但实际上结果只有几种而已,分类讨论就行。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,c,x;
int main () {
	int t ;
	scanf("%d",&t);
	while(t--) {
		scanf("%lld%lld%lld%lld",&a,&b,&c,&x);
		ll x1=x-c;
		ll x2=x+c+b-a;
		if(x==c||x==b-c||x==a-b-c) {
			puts("Yes");
			continue;
		}
		if(a==2ll*b) {
			puts("No");
			continue;
		}
		if((x1%(a-2ll*b)==0)||(x2%(2ll*b-a)==0)) {
			puts("Yes");
		} else puts("No");
	}
}

M-Z-Game on grid

从(1,1)到(n,m)dp一次去得到每个格子是否能转化为某种局面,复杂度是 O ( n m ) O(nm) O(nm)的,我们只需要做三次就可以了。这里推荐ygg的题解,非常简单易懂。

#include <bits/stdc++.h>
using namespace std;
int T,n,m,f[505][505],g[505][505],ans[10];
char a[505][505];
void towin() {
	for (int i=0; i<=n+1; i++)
		for (int j=0; j<=m+1; j++)
			f[i][j]=g[i][j]=0;
	int flag=0;
	if (a[n][m]=='.') {
		flag=1;
		a[n][m]='B';
	}
	for (int i=n; i>=1; i--)
		for (int j=m; j>=1; j--)
			if ((i+j)&1) {  //Bob走的点
				if (a[i][j]=='B') g[i][j]=1;
				if (a[i][j]=='A') g[i][j]=-1;
				if (a[i][j]=='.') {
					if (i==n) {
						if (f[i][j+1]==1) g[i][j]=-1;
						else g[i][j]=1;
					} else if (j==m) {
						if (f[i+1][j]==1) g[i][j]=-1;
						else g[i][j]=1;
					} else {
						if (f[i+1][j]==1&&f[i][j+1]==1) g[i][j]=-1;
						else g[i][j]=1;
					}
				}
			} else {
				if (a[i][j]=='A') f[i][j]=1;
				if (a[i][j]=='B') f[i][j]=-1;
				if (a[i][j]=='.') {
					if (i==n) {
						if (g[i][j+1]==1) f[i][j]=-1;
						else f[i][j]=1;
					} else if (j==m) {
						if (g[i+1][j]==1) f[i][j]=-1;
						else f[i][j]=1;
					} else {
						if (g[i][j+1]==1&&g[i+1][j]==1) f[i][j]=-1;
						else f[i][j]=1;
					}
				}
			}
	if (f[1][1]==1) ans[1]=1;
	else ans[1]=0;
	if (flag) a[n][m]='.';
}
void tolose() {
	for (int i=0; i<=n+1; i++)
		for (int j=0; j<=m+1; j++)
			f[i][j]=g[i][j]=0;
	int flag=0;
	if (a[n][m]=='.') {
		flag=1;
		a[n][m]='A';
	}
	for (int i=n; i>=1; i--)
		for (int j=m; j>=1; j--)
			if ((i+j)&1) {  //Bob走的点
				if (a[i][j]=='A') g[i][j]=1;
				if (a[i][j]=='B') g[i][j]=-1;
				if (a[i][j]=='.') {
					if (i==n) {
						if (f[i][j+1]==1) g[i][j]=-1;
						else g[i][j]=1;
					} else if (j==m) {
						if (f[i+1][j]==1) g[i][j]=-1;
						else g[i][j]=1;
					} else {
						if (f[i+1][j]==1&&f[i][j+1]==1) g[i][j]=-1;
						else g[i][j]=1;
					}
				}
			} else {
				if (a[i][j]=='B') f[i][j]=1;
				if (a[i][j]=='A') f[i][j]=-1;
				if (a[i][j]=='.') {
					if (i==n) {
						if (g[i][j+1]==1) f[i][j]=-1;
						else f[i][j]=1;
					} else if (j==m) {
						if (g[i+1][j]==1) f[i][j]=-1;
						else f[i][j]=1;
					} else {
						if (g[i][j+1]==1&&g[i+1][j]==1) f[i][j]=-1;
						else f[i][j]=1;
					}
				}
			}
	if (f[1][1]==1) ans[3]=1;
	else ans[3]=0;
	if (flag) a[n][m]='.';
}
void toequal() {
	if (a[n][m]!='.') return;
	for (int i=0; i<=n+1; i++)
		for (int j=0; j<=m+1; j++)
			f[i][j]=g[i][j]=0;
	f[n][m]=1;
	g[n][m]=-1;
	for (int i=n; i>=1; --i)
		for (int j=m; j>=1; --j)
			if (i==n&&j==m) continue;
			else if ((i+j)&1) { //Bob走的点
				if (a[i][j]=='B'||a[i][j]=='A') g[i][j]=1;
				else {
					if (i==n) {
						if (f[i][j+1]==1) g[i][j]=-1;
						else g[i][j]=1;
					} else if (j==m) {
						if (f[i+1][j]==1) g[i][j]=-1;
						else g[i][j]=1;
					} else {
						if (f[i+1][j]==1&&f[i][j+1]==1) g[i][j]=-1;
						else g[i][j]=1;
					}
				}
			} else {
				if (a[i][j]=='B'||a[i][j]=='A') f[i][j]=-1;
				else {
					if (i==n) {
						if (g[i][j+1]==1) f[i][j]=-1;
						else f[i][j]=1;
					} else if (j==m) {
						if (g[i+1][j]==1) f[i][j]=-1;
						else f[i][j]=1;
					} else {
						if (g[i+1][j]==1&&g[i][j+1]==1) f[i][j]=-1;
						else f[i][j]=1;
					}
				}
			}
	if (f[1][1]==1) ans[2]=1;
	else ans[2]=0;
}
int main() {
	cin>>T;
	while (T--) {
		scanf("%d%d",&n,&m);
		for (int i=1; i<=n; ++i) {
			scanf("%s",a[i]+1);
		}
		if (a[1][1]=='A') ans[1]=1;
		else if (a[1][1]=='.') towin();
		if (a[1][1]=='B') ans[3]=1;
		else if (a[1][1]=='.') tolose();
		toequal();
		for (int i=1; i<=3; ++i)
			if (ans[i]) printf("yes ");
			else printf("no ");
		ans[1]=ans[2]=ans[3]=0;
		putchar('\n');
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RWLinno

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值