2022牛客蔚来杯第六场GJMBA

2022牛客蔚来杯第六场

G.Icon Design

  • 题意

    • 签到题,根据n的大小输出对应尺寸的符号矩阵,n<=5
  • 题解

    • 打表或者直接根据规律填充字符,需要一点耐心
  • 代码

打表

#include <iostream>

using namespace std;

int main() {
    int n;
    cin>>n;
    if(n==1){
        printf("********************************\n");
        printf("*..............................*\n");
        printf("*..@...@..@@@@@..@......@@@@@..*\n");
        printf("*..@@..@..@......@......@......*\n");
        printf("*..@.@.@..@@@@@..@......@@@@@..*\n");
        printf("*..@..@@..@......@..........@..*\n");
        printf("*..@...@..@......@@@@@..@@@@@..*\n");
        printf("*..............................*\n");
        printf("********************************\n");
    }
    if(n==2){
        printf("*********************************************\n");
        printf("*...........................................*\n");
        printf("*...........................................*\n");
        printf("*...@.....@...@@@@@@@...@.........@@@@@@@...*\n");
        printf("*...@@....@...@.........@.........@.........*\n");
        printf("*...@.@...@...@.........@.........@.........*\n");
        printf("*...@..@..@...@@@@@@@...@.........@@@@@@@...*\n");
        printf("*...@...@.@...@.........@...............@...*\n");
        printf("*...@....@@...@.........@...............@...*\n");
        printf("*...@.....@...@.........@@@@@@@...@@@@@@@...*\n");
        printf("*...........................................*\n");
        printf("*...........................................*\n");
        printf("*********************************************\n");
    }
    if(n==3){
        printf("**********************************************************\n");
        printf("*........................................................*\n");
        printf("*........................................................*\n");
        printf("*........................................................*\n");
        printf("*....@.......@....@@@@@@@@@....@............@@@@@@@@@....*\n");
        printf("*....@@......@....@............@............@............*\n");
        printf("*....@.@.....@....@............@............@............*\n");
        printf("*....@..@....@....@............@............@............*\n");
        printf("*....@...@...@....@@@@@@@@@....@............@@@@@@@@@....*\n");
        printf("*....@....@..@....@............@....................@....*\n");
        printf("*....@.....@.@....@............@....................@....*\n");
        printf("*....@......@@....@............@....................@....*\n");
        printf("*....@.......@....@............@@@@@@@@@....@@@@@@@@@....*\n");
        printf("*........................................................*\n");
        printf("*........................................................*\n");
        printf("*........................................................*\n");
        printf("**********************************************************\n");
    }
    if(n==4){
        printf("***********************************************************************\n");
        printf("*.....................................................................*\n");
        printf("*.....................................................................*\n");
        printf("*.....................................................................*\n");
        printf("*.....................................................................*\n");
        printf("*.....@.........@.....@@@@@@@@@@@.....@...............@@@@@@@@@@@.....*\n");
        printf("*.....@@........@.....@...............@...............@...............*\n");
        printf("*.....@.@.......@.....@...............@...............@...............*\n");
        printf("*.....@..@......@.....@...............@...............@...............*\n");
        printf("*.....@...@.....@.....@...............@...............@...............*\n");
        printf("*.....@....@....@.....@@@@@@@@@@@.....@...............@@@@@@@@@@@.....*\n");
        printf("*.....@.....@...@.....@...............@.........................@.....*\n");
        printf("*.....@......@..@.....@...............@.........................@.....*\n");
        printf("*.....@.......@.@.....@...............@.........................@.....*\n");
        printf("*.....@........@@.....@...............@.........................@.....*\n");
        printf("*.....@.........@.....@...............@@@@@@@@@@@.....@@@@@@@@@@@.....*\n");
        printf("*.....................................................................*\n");
        printf("*.....................................................................*\n");
        printf("*.....................................................................*\n");
        printf("*.....................................................................*\n");
        printf("***********************************************************************\n");
    }
    if(n==5){
        printf("************************************************************************************\n");
        printf("*..................................................................................*\n");
        printf("*..................................................................................*\n");
        printf("*..................................................................................*\n");
        printf("*..................................................................................*\n");
        printf("*..................................................................................*\n");
        printf("*......@...........@......@@@@@@@@@@@@@......@..................@@@@@@@@@@@@@......*\n");
        printf("*......@@..........@......@..................@..................@..................*\n");
        printf("*......@.@.........@......@..................@..................@..................*\n");
        printf("*......@..@........@......@..................@..................@..................*\n");
        printf("*......@...@.......@......@..................@..................@..................*\n");
        printf("*......@....@......@......@..................@..................@..................*\n");
        printf("*......@.....@.....@......@@@@@@@@@@@@@......@..................@@@@@@@@@@@@@......*\n");
        printf("*......@......@....@......@..................@..............................@......*\n");
        printf("*......@.......@...@......@..................@..............................@......*\n");
        printf("*......@........@..@......@..................@..............................@......*\n");
        printf("*......@.........@.@......@..................@..............................@......*\n");
        printf("*......@..........@@......@..................@..............................@......*\n");
        printf("*......@...........@......@..................@@@@@@@@@@@@@......@@@@@@@@@@@@@......*\n");
        printf("*..................................................................................*\n");
        printf("*..................................................................................*\n");
        printf("*..................................................................................*\n");
        printf("*..................................................................................*\n");
        printf("*..................................................................................*\n");
        printf("************************************************************************************\n");
    }
    return 0;
}

一点点填充,还是有点烦人的,因为没有那么简单qwq

#include <bits/stdc++.h>
using namespace std;

char s[53][103];
int main() {
  int n;
  cin >> n;
  int len = 13 * n + 19, height = 4 * n + 5;
  //处理背景
  for (int j = 1; j <= len; j++) s[1][j] = '*';
  for (int i = 2; i < height; i++) {
    s[i][1] = s[i][len] = '*';
    for (int j = 2; j < len; j++) s[i][j] = '.';
  }
  for (int j = 1; j <= len; j++) s[height][j] = '*';
  
  //处理横线
  int top = n + 2, mid = 2 * n + 3, bottom = 3 * n + 4;
  for (int j = 4 * n + 7; j <= 6 * n + 9; j++) s[top][j] = s[mid][j] = '@';
  for (int j = 7 * n + 11; j <= 9 * n + 13; j++) s[bottom][j] = '@';
  for (int j = 10 * n + 15; j <= 12 * n + 17; j++) s[top][j] = s[mid][j] = s[bottom][j] = '@';

  //处理竖线
  for (int i = top; i <= mid; i++)
    s[i][n + 3] = s[i][3 * n + 5] = s[i][4 * n + 7] = s[i][7 * n + 11] = s[i][10 * n + 15] = '@';
  for (int i = mid; i <= bottom; i++)
    s[i][n + 3] = s[i][3 * n + 5] = s[i][4 * n + 7] = s[i][7 * n + 11] = s[i][12 * n + 17] = '@';

  //处理斜线
  for (int i = top; i <= bottom; i++) s[i][i + 1] = '@';

  //输出
  for (int i = 1; i <= height; i++) {
    for (int j = 1; j <= len; j++) {
      cout << s[i][j];
    }
    cout << endl;
  }

  return 0;
}

J.Number Game

  • 题意

    • 给定a,b,c,x
    • 可以将b变成a-b;可以将c变成b-c
    • 问能否通过如上变化把c变成x
  • 题解

    • 连续使用两个一样的操作是无效的,相当于没有操作。故只能两个操作交替使用才有效

    • 枚举先1后2和先2后1两种交替方式,发现最终c的值为特定的几种形式(k整数)
      x ? = c = { k × ( a − 2 b ) + c k × ( a − 2 b ) + b − c k × ( a − 2 b ) + a − b − c x?=c= \begin{cases} k\times (a-2b)+c\\ k\times(a-2b)+b-c\\ k\times (a-2b)+a-b-c \end{cases} x?=c= k×(a2b)+ck×(a2b)+bck×(a2b)+abc

    • 只需检验以上式子能否等于x即可。枚举k太繁琐,可以转换成左边为k的式子,为检验看是否为整数即可。注意不能除以0的情况要特判

  • 代码

#include <iostream>

using namespace std;

bool solve() {
    int a,b,c,x;
    cin>>a>>b>>c>>x;
    
    if(a==2*b) {//不能转换为左边为k的式子,特判
        if(c==x) return 1;
        if(b-c==x) return 1;
        return 0;
    }
  
  //能转换时,判断三种形式下k是否为整数
    if((x-c)%(a-2*b)==0) return 1;
    if((x-b+c)%(a-2*b)==0) return 1;
    if((x-a+b+c)%(a-2*b)==0) return 1;
    return 0;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    
    int t;
    cin>>t;
    while(t--) cout<<(solve() ? "Yes":"No")<<'\n';
    
    return 0;
}

M.Z-Game on grid

  • 题意

    • n*m的矩阵,有’A’,‘B’,'.'三种符号
    • 游戏Alice 先走,Bob后走,从(1,1)只能向右和向下走。当走到A那么Alice赢,走到B那么Bob赢,否则直到走到(n,m)没有胜负,就是平局
    • 问不论Bob怎么下,Alice是否存在一种路径使得必胜、必平或必输
  • 题解

    • 把必胜、必平、必输三种情况分开看

    • 先解决必胜。如果从头到尾走,要搜索所有路径,每个点还要判断所有后面的子路径是否存在必胜,就是dfs了,复杂度写不了。既然都跟后面相关,那么我直接倒推,发现能够考虑到所有路径的情况,然后dp复杂度也够

    • dp

      定义:f[i,j]表示路径包含(i,j)时,能否达到Alice想要的必胜、平、输

      转移:

      如果Alice必胜,那么路径上有A必胜,有B必败;如果Alice平局,那么路径上所有AB都导致不平局,相当于必败态;如果Alice必输,那么路径上的所有A为必败态,B为必胜态。

      如果此点(i+j)%2=0说明此步为Alice选择,那么Alice一定选自己想要的状态就可能可以完成问题。而Bob我们假定一定阻止Alice达到想要的状态。即在最大阻力情况下存在想要路径,那么一定存在。

      转移方程直接贴代码里面了

  • 代码

#include <iostream>
#include <cstring>

using namespace std;
const int N=510;

int t,n,m;
int f[N][N];
char g[N][N];

void solve() {
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>g[i]+1;
    
    memset(f,0,sizeof f);//重置数组
    for(int i=n;i>=1;i--)
        for(int j=m;j>=1;j--) {
            if(!((i+j)&1)) {//Alice动手,右和下如果存在必胜态则此点必胜
                if(i+1<=n) f[i][j]|=f[i+1][j];
                if(j+1<=m) f[i][j]|=f[i][j+1];
            }
            else {//Bob动手,只有右和下都必胜才会使得Alice此点必胜
                if(i+1<=n&&j+1<=m) f[i][j]=(f[i+1][j]&f[i][j+1]);
                else if(i+1<=n) f[i][j]|=f[i+1][j];
                else if(j+1<=m) f[i][j]|=f[i][j+1];
            }
            if(g[i][j]=='A') f[i][j]=1;//只要此点是必胜,路径直接必胜
            if(g[i][j]=='B') f[i][j]=0;//只要此点是必败,那么一票否决
        }
    cout<<(f[1][1] ? "yes":"no")<<' ';
    
    memset(f,0,sizeof f);//重置
    f[n][m]=1;//假设是平局
    for(int i=n;i>=1;i--)
        for(int j=m;j>=1;j--) {
            if(!((i+j)&1)) {
                if(i+1<=n) f[i][j]|=f[i+1][j];
                if(j+1<=m) f[i][j]|=f[i][j+1];
            }
            else {
                if(i+1<=n&&j+1<=m) f[i][j]=(f[i+1][j]&f[i][j+1]);
                else if(i+1<=n) f[i][j]|=f[i+1][j];
                else if(j+1<=m) f[i][j]|=f[i][j+1];
            }
            if(g[i][j]!='.') f[i][j]=0;//只要路径上出现不是平局,那么必败
        }
    cout<<(f[1][1] ? "yes":"no")<<' ';
    
    memset(f,0,sizeof f);//重置
    for(int i=n;i>=1;i--)//与第一个一样
        for(int j=m;j>=1;j--) {
            if(!((i+j)&1)) {
                if(i+1<=n) f[i][j]|=f[i+1][j];
                if(j+1<=m) f[i][j]|=f[i][j+1];
            }
            else {
                if(i+1<=n&&j+1<=m) f[i][j]=(f[i+1][j]&f[i][j+1]);
                else if(i+1<=n) f[i][j]|=f[i+1][j];
                else if(j+1<=m) f[i][j]|=f[i][j+1];
            }
            if(g[i][j]=='B') f[i][j]=1;
            if(g[i][j]=='A') f[i][j]=0;
        }
    cout<<(f[1][1] ? "yes":"no")<<'\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    
    cin>>t;
    while(t--) solve();
    return 0;
}

B.Eezie and Pie

  • 题意

    • 给一颗以1节点为根的树,以及每个节点向根节点方向走能走的最远距离di
    • 求每个点能有几个点能够到达此点
  • 题解

    • 画图可知,每个点能送到的点为: 从该点出发到根节点路径中,长度为di的这些点
    • 上述覆盖的段路径ans都要+1,很想区间+c操作,所以差分思路,即树链差分
    • dfs所有路径,起点+1,终点上一点-1,完成差分处理。最后再dfs一遍统计答案
  • 代码

#include <iostream>
#include <cstring>
#include <vector>

using namespace std;
const int N=2e6+10;

int n;
int sz[N];//差分数组兼任答案数组
int d[N];
int h[N],e[2*N],ne[2*N],idx;//无向图,开两倍

void add(int a,int b) {
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

vector<int> path;//记录dfs中的某条路径
void dfs(int u,int fa) {//无向图,链式向前星会有父节点,传入父节点去掉上述情况
    path.push_back(u);//路径加入此节点
    sz[u]++;//差分数组,起点+1
    int len=path.size();
    if(len-d[u]-2>=0) sz[path[len-d[u]-2]]--;//如果终点上一节点存在,-1
    for(int i=h[u];i!=-1;i=ne[i]) {//dfs子节点
        int j=e[i];
        if(j!=fa) dfs(j,u);//不是父节点dfs
    }
    path.pop_back();//此点所有路径处理完毕,丢出路径数组
}

void cal(int u,int fa) {//计算差分的前缀和,计算答案
    for(int i=h[u];i!=-1;i=ne[i]) {
        int j=e[i];
        if(j!=fa) cal(j,u),sz[u]+=sz[j];
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    
    cin>>n;
    memset(h,-1,sizeof h);//初始化
    for(int i=1;i<n;i++) {//注意是n-1条边
        int u,v;
        cin>>u>>v;
        add(u,v);add(v,u);//无向边
    }
    for(int i=1;i<=n;i++) cin>>d[i];
    
    dfs(1,0);//处理差分数组
    cal(1,0);//计算答案
    for(int i=1;i<=n;i++) cout<<sz[i]<<' ';
    cout<<'\n';
    
    return 0;
}

把差分处理计算答案递归合并,即在线差分+计算

#include <iostream>
#include <cstring>
#include <vector>

using namespace std;
const int N=2e6+10;

int n;
int sz[N],d[N];
int h[N],e[2*N],ne[2*N],idx;

void add(int a,int b) {
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

vector<int> path;
int dfs(int u,int fa) {
    path.push_back(u);
    sz[u]++;
    int len=path.size();
    if(len-d[u]-2>=0) sz[path[len-d[u]-2]]--;
    for(int i=h[u];i!=-1;i=ne[i]) {
        int j=e[i];
        if(j!=fa) sz[u]+=dfs(j,u);
    }
    path.pop_back();
    
    return sz[u];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=1;i<n;i++) {
        int u,v;
        cin>>u>>v;
        add(u,v);add(v,u);
    }
    for(int i=1;i<=n;i++) cin>>d[i];
    
    dfs(1,0);
    for(int i=1;i<=n;i++) cout<<sz[i]<<' ';
    cout<<'\n';
    
    return 0;
}

A.Array

  • 题意

    • 给定一个下表从1开始长度为n的数组a
    • 请你构造出一个循环节长度为m的数组b,对于b中的任意连续ai个数一定出现i这个数
    • 输出循环节长度和这个循环节
  • 题解

    • 法一:官方题解,想不到
    • 贪心构造,把所有数从小到大排序(即按重复区间长度排序),贪心把这些区间摆满
  • 代码

#include<bits/stdc++.h>
using namespace std;
const int M = 1e6;
pair<int,int> a[M];
int res[M];
int fi[M];
int main() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {//读入
		cin >> a[i].first;
		a[i].second = i;
	}
	sort(a + 1, a + n + 1);//排序
	int m = max(n, a[n].first);//循环节长度
	int cnt = 0;
	for (int i = 1; i <= n; i++) {//遍历a
		while (res[cnt]) cnt++;//找到第一个空着的位置
		int aa = a[i].second;
		int bb = a[i].first;
		int k;
		for (k = cnt; k < m; k += bb) {//跨a[i]放一个i,保证连续存在
			if (!res[k]) res[k] = aa;//位置空着就放
			else {//位置被占
				int t = k - bb;//上一个i位置
				while (res[k] && k>t) k--;//在上一个i位置与这个位置中间找空位放,保证连续存在
				res[k] = aa;
			}
		}
    //当放到循环节外的位置,需要特判是否和下一个i出现的位置间隔超过a[i]
		k = k - bb;
		if (cnt + m - k>bb) {//如果超过间隔a[i],那么需要在循环节结尾前找一个空位置使得连续存在
			int s = m - 1;
			while (res[s]) s--;
			res[s] = aa;
		}
	}
	cout << m << '\n';
	for (int i = 0; i < m; i++) {//空着的位置都放1就行
		if (!res[i]) cout << 1 << ' ';
		else cout << res[i] << ' ';
	}
	return 0;
}

直接构造一个超大数组,把区间依次填满

#include<bits/stdc++.h>
using namespace std;
int n,ans[1000005],m;
pair<int,int>a[100005];
int main(){
	// 读入 
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i].first);
		a[i].second=i; // 记录下标 
	}
	sort(a+1,a+1+n); // 从小到大排序 
	
	// 填数字 
	m=1e6; // 足够大 
	for(int i=1,b=1;i<=n;b++,i++){
		while(ans[b]!=0)b++; // 找到第一个没填的位置 
		
		for(int j=b;;j+=a[i].first){ // 每隔a[i]个填一次 
			while(j>m || ans[j]!=0)j--; // 保证不越界且没填 
			
			ans[j]=a[i].second; // 填上下标 
			if(m-j+b<=a[i].first)break; //尾部走向头的这个循环中保证a[i]区间内有i
		}
	}
	
	// 输出答案 
	printf("%d\n",m);
	for(int i=1;i<m;i++){
		printf("%d ",ans[i]?ans[i]:1);
	}
	printf("%d\n",ans[m]?ans[m]:1);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值