题解:牛客寒假训练赛1

牛客寒假训练赛1,自己水平还是太差了。

A:

题意:有计算符号和结果,求最初的数

思路:简单模拟

#include<cstdio>
#define ll long long
struct note
{
    int opt;
    ll num;
}a[101];
int main()
{
    int n;
    ll k;
    scanf("%d%lld",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d%lld",&a[i].opt,&a[i].num);
    for(int i=n;i>=1;i--)
        {
            switch(a[i].opt)
            {
                case 1:k-=a[i].num;break;
                case 2:k+=a[i].num;break;
                case 3:k/=a[i].num;break;
                case 4:k*=a[i].num;break;
            }
        }
    printf("%lld",k);
    return 0;  
}

B:给定2,0,4的数量,对其进行排列,计算1~i的(a[i]-a[i-1])^2的和

构造,4,0,4,0是最优解,所以需要先排列,然后再考虑其他情况

#include<cstdio>
int a[5];
int main()
{
    int n;
    int ans=0;
    int p=0;
    int num;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        {
            scanf("%d",&num);
            a[num]++;  
        }   
    for(int i=1;i<=n;i++)
        {
            switch(p)
            {
                case 0:
                        {
                             if(a[4])
                                {
                                    ans+=16;
                                    a[4]--;
                                    p=4;
                                }
                            else
                                if(a[2])
                                    {
                                        ans+=4;
                                        a[2]--;
                                        p=2;
                                    }
                            break;
                        }
                case 2:
                        {
                            if(a[4])
                                {
                                    ans+=4;
                                    a[4]--;
                                    p=4;
                                }
                            else
                            if(a[0])
                                {
                                    ans+=4;
                                    a[0]--;
                                    p=0;
                                }
                            break;
                        }
                case 4:
                        {
                            if(a[0])
                                {
                                     ans+=16;
                                     a[0]--;
                                     p=0;
                                }
                            else if(a[2])
                                {
                                    ans+=4;
                                    a[2]--;
                                    p=2;
                                }
                            break;
                        }
            }      
        }
    printf("%d",ans);
    return 0;
}

C:

题意:n个节点,第i个节点有pi,当pi>pj时,飞船可以从i到j,飞往后,耐久变为t异或pj,t的初始值为1,求到达n的耐久最大为多少

思路:dp,实际上有点floyd的感觉,又有点搜索的感觉(确实可以拿搜索过

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 10003
#define MAXP 4096
//3000用二进制表示最大也就是1<<12
//less,greater包含在iostream里面??挠头.jpg
using namespace std;
int n;
int p[MAXN];
int dp[MAXP];
int main()
{
	int max=-1;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&p[i]);
	int begin=p[1],x=1,y=n,end=p[n];
	if(n==1)//排除n==1的特殊情况
		{
			printf("%d",p[1]?p[1]:-1);
			return 0;
		}
    if(begin<=end)//只有在这种情况下才无法到达
        {
             printf("-1");
            return 0;
        }
	sort(p+1,p+1+n,greater<int>());
	while(p[x]>begin&&x<n)	
		x++;
	while(p[y]<end&&y>1)	
		y--;
	dp[end^begin]=1;
	for(int i=x+1;i<y;i++)
		{
				for(int j=MAXP-1;j>=0;j--)		
					dp[j]|=dp[j^p[i]];//需要保证之前的情况也能够到达
		}
	for(int i=MAXP-1;i>=0;i--)
				if(dp[i])	//找到最大值
					{
						printf("%d",i);
						return 0;
					}
	return 0;
} 

D:

题意:初始黄金数分别为A,B,两人从两端相向而行,当位置和n互质的时候,A*k^x,B*k^y,求最后两者之和,并向1e9+7取模

思路:数论,求出与n互质的数的和,然后快速幂(或者其他操作

#include<cstdio>
#define mod 1000000007
#define ll long long
//relocation truncated to fit 内存使用超限 
//欧拉函数
//此处应该使用求单个数欧拉函数的函数
//因为根本不需要求全部
int phi(int x){
    int ans = x;
    for(int i = 2; i*i <= x; i++){
        if(x % i == 0){
            ans = ans / i * (i-1);
            while(x % i == 0) x /= i;
        }
    }
    if(x > 1) ans = ans / x * (x-1);
    //若x有大于根号下x的因数,则需继续删去
	//易得,x只有可能又一个这样的因数
	//所以判断一次即可 
    return ans;
}
//快速幂
//有时间可以学下位运算的写法
ll qik(ll a,ll x)
{
	ll res=1;
	while(x)
		{
			if(x%2!=0)
				res=(res*a)%mod;
			a=(a*a)%mod;
			x/=2;
		}
	return res;
} 
int main()
{
	ll n,k,a,b;
	scanf("%ld%ld%ld%ld",&n,&k,&a,&b);
	ll x=phi(n)*n/2; 
	printf("%ld",1ll*(qik(k,x)*(a+b))%mod);
	return 0;
}

E:

题意:n*m的矩阵,p个轰炸机,两种轰炸模式,一种是对角线分别为x,y的菱形,一种只轰炸上半部分,求最后轰炸次数的异或和

思路:查分,但是暂时还是看不懂几个数组之间是怎么实现的(我理解能力真差.jpg)

F:

题意:长度为n的序列,数字在1~V之间,给任意位置的数赋值形成子序列,子序列需满足严格递增,萌值定义为除序列最大值以外所有值的乘积,若只有一个数则为1,求所有序列萌值的和

思路:dp,自己尝试着去写状态转移方程,并且利用sum作为前缀和,记录前面的代价

​
#include<cstdio>
#define MAXN 5005
#define ll long long
#define mod 1000000007 
#define MAXN 5005 
int dp[MAXN][MAXN];
int main()
{
	int n,v;
	scanf("%d%d",&n,&v);
	for(int i=1;i<=v;i++)
	 	dp[1][i]=1;
	for(int i=2;i<=n;i++)
		{
			ll sum=1;
            //类似前缀和 
			//用sum来表示长度小于自己的合法子序列 
			//因为明显每次增加最后一个数之后,最大的数就不是之前的数
			//然后就需要被乘增加入萌值
			for(int j=1;j<=v;j++)
				{
					dp[i][j]=(dp[i-1][j]+sum)%mod;
					sum=(sum+dp[i-1][j]*j)%mod;	
				} 
		}
	ll ans=0;
	for(int i=1;i<=v;i++)
		ans=(ans+dp[n][i])%mod;
	printf("%lld",ans);
	return 0;
} 

​

G:

题意:排序后所有数左右相差值为1,则说明这个序列为“萌”的,现在给出序列n,求最小长度[l,r]的萌序列,并且要求含有x,y

H:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值