“蔚来杯“2022牛客暑期多校训练营7 题解

C题 Constructive Problems Never Die
思路:把数字分为在A中出现过和没出现过两种,在构造的时候先用出现过的数字填补,这里我选择的是用错位填补的方法,即Pi=A(i+1),如果遇到相同的数字,就用没出现过的数字填补即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn=100010;
typedef long long ll;
int read(){
    int m=0,n=1; 
	char ch;
	ch=getchar();
    while(ch<'0'||ch>'9')
	{  
	    if(ch=='-') 
		 n=-1;
	    ch=getchar();
	}
    while(ch>='0'&&ch<='9')
	{
	    m=m*10+ch-'0';
	    ch=getchar();
	}
    return m*n;
}

int main(){
    int t,n,f;
    t=read();
    while(t--){//1e5
        vector<int> v;
        n=read();
        vector<int> a(n+5),vis(n+1),num(n+1);
        f=0;
        for(int i=1;i<=n;i++){
            num[i]=0;
            a[i]=read();
            if(i!=1&&a[i]!=a[i-1]) f=1;
            vis[a[i]]++;
        }
        if(f==0){
            puts("NO");
        }else{
            for(int i=1;i<=n;i++){
                if(vis[i]==0){//如果这个元素在a数组没出现过,说明在p中可以放在任意位置
                    v.push_back(i);
                }
            }
            int x=0;
            puts("YES");
            a[n+1]=a[1];
            for(int i=1;i<=n;i++){
                if(num[a[i+1]]==0&&a[i+1]!=a[i]){
                    printf("%d ",a[i+1]);
                    num[a[i+1]]++;
                }else{
                    printf("%d ",v[x]);
                    x++;
                }
            }
            printf("\n");
        }
    }  
	return 0; 
}

F题 Candies
思路:n个人围成一个圈,每个人有一个数字,相邻的人数字相同或者是数字相加为一个给定的数字x就可以消除,然后组成新的圈,问能消除的最大次数。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int vis[N],ne[N];
ll n,x;
ll v[N];
int qu(int a,int b){
    int ans=0;
    if(a==b) return 0;
    if(v[b]==v[a]||v[b]+v[a]==x){
    			//修改相邻位置的值
               vis[ne[a]]=vis[b];
               ne[vis[b]]=ne[a];
               //表示已经被访问过了,记录位置
               vis[b]=b;
               vis[a]=a;
                 ans+=qu(ne[a],vis[ne[a]])+1;
           }
     return ans;
}
int main(){
    scanf("%lld%lld",&n,&x);
    for(int i=0;i<n;i++) scanf("%lld",&v[i]);
    ll ans=0;
    for(int i=0;i<n;i++){
        vis[i]=(i+1)%n;//记录i的下一个相邻位置
        ne[i]=(i-1+n)%n;//记录i的上一个相邻位置
    }
       for(int i=0;i<n;i++){
           if(vis[i]==i) {//如果vis[i]==i,说明已经被消除了
                continue;      
            }	
           ans+=qu(i,vis[i]);
    }
    printf("%lld",ans);
}

G题 Regular Expression
思路:如果字符串长度为一,答案只能是“.”或者它本身两种;如果长度为2,在两个字母相同的情况下,有8种,不同则有6种;如果长度大于2,则都可以用两个符号表示,比如“.+”。模没啥用。

#include<bits/stdc++.h>
using namespace std;
int t;
string s;
int main(){
    cin>>t;
    while(t--){
        cin>>s;
        int f=0;
        for(int i=0;i<s.size()-1;i++){
            if(s[i]!=s[i+1]) {
                f=1;break;
            }
        }
        if(s.size()==1) cout<<1<<" "<<2<<endl;
        else if(f==0&&s.size()==2) cout<<2<<" "<<8<<endl;
        else if(f==1&&s.size()==2) cout<<2<<" "<<6<<endl;
        else if(f==1) cout<<2<<" "<<2<<endl;
        else cout<<2<<" "<<4<<endl;
    }
}

J题 Melborp Elcissalc
思路:能整除k的数字被认为是好的数字。一个数组只包含小于k的非负数,它的优度定义为和能整除k的非空连续子数组的个数。求长度为n优度为t的数组的个数,对答案取模。

#include<cstdio>
using namespace std;
const int M=998244353;
int n,K,t;
long f[65][2100];//第一维记录长度,第二维记录优度
long C[70][70];//
int main(){
	scanf("%d%d%d",&n,&K,&t);
	C[0][0]=1;
	for(int i=1;i<=65;i++){
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=(C[i-1][j-1]+C[i-1][j])%M;
	}
	f[0][0]=1;
	for(int u,i=0;i<K;i++)
		for(int k=n;k;k--)
			for(int l=t;l>=0;l--){
				for(int u,j=1;j<=k;j++){
					u=j*(i==0?(j+1):(j-1))/2;
					if(u>l) break;
					//第一维记录长度,第二维记录优度
					f[k][l]+=f[k-j][l-u]*C[k][j]%M;
				}
				f[k][l]%=M;
			}
	printf("%ld\n",f[n][t]);
}

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...