电子科技大学第九届ACM趣味程序设计竞赛第二场(正式赛) 题解

A::魔王的直播

注意23:59之后是00:00即可,找出所有回文字符,取最近.

#include <bits/stdc++.h>

using namespace std;

bool check(int a,int b)
{
    int c=a%10*10+a/10;
    if(c==b)
        return false;
    return true;
}

int main()
{
    int a,b;
    scanf("%d:%d",&a,&b);
    int ans=0;
    while(check(a,b))
    {
        ans++;
        b++;
        a+=b/60;
        b%=60;
        a%=24;
    }
    cout<<ans<<endl;
}


B:绿帽自动机

题意:

定义“戴绿帽”操作:除了制定某一个某一个人之外,其他人的绿帽数+1。

给定n个数,进行尽量少的“戴绿帽”操作,使得第x个数最大。

输出“戴绿帽”操作所需的最少次数。

 

首先,明确一点,如果我一次性给所有人“戴绿帽”,那么“戴绿帽”前后,最大的那个人的绿帽数依旧最大,最小的那个依旧最小,即不影响题目要求。

现在题意为“ 除了指定的某一个人以外,其余所有人绿帽数+1”,可以分解为以下操作:

1.给所有人绿帽数+1

2.给指定的那个人绿帽数-1

事实上,题目就等价于:每次减少一个人的绿帽,至少进行多少次减少操作,可以使得第x-th数最大。

假设第x人原绿帽数为g,那么计算一下所有大于等于g-1的数与g-1的差即可。

结果可能爆int,请使用long long。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 100000+10;
ll g[MAXN];
ll sum;
int main()
{
	int n,x;
	cin>>n>>x;
	for(int i=1;i<=n;++i)	cin>>g[i];
	for(int i=1;i<=n;++i)	if(g[i]>=g[x]-1)	sum+=(g[i]-g[x]+1);
	cout<<sum-1;
	return 0;
}


C:洗牌机

洗牌方式是一个大环,因此连续洗牌 13 次后所有牌又会回到原位,那么洗一次牌相当于洗7*2次牌。
我们只需要模拟洗7*2次即可。
根据初始顺序和洗两次后的顺序,得到洗两次的洗牌方式,用二重循环,外循环模拟每一次洗牌,内循环模拟洗每一张牌,再输出洗7*2次牌后的结果。

#include <bits/stdc++.h>
using namespace std;
#define N 15
int a[N][N],nxt2[N],num;
//a[i][j]��ʾϴi���ƺ�ĵ�j����
//nxt2[i]=j��ʾԭ����i������ϴ���κ��ܵ���j��
int main()
{
    int n=13,times=7;
    scanf("%d",&num);
    while(num--)
    {
        for(int i=1; i<=n; i++)
            scanf("%d",&a[0][i]);
        for(int i=1; i<=n; i++)
            scanf("%d",&a[2][i]);
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                if(a[0][i]==a[2][j])
                {
                    nxt2[i]=j;
                    break;
                }
        for(int t=1; t<times; t++)
            for(int i=1; i<=n; i++)
            {
                a[2*(t+1)][nxt2[i]]=a[2*t][i];
            }
        for(int i=1; i<=n; i++)
        {
            printf("%d ",a[14][i]);
        }
        printf("\n");
    }
    return 0;
}




D:小帆宝与数字8

题目要求你得到一个长度为n的排列,使得相邻两个数的乘积都是8的倍数


1 2 4 8,这四个数,可以知道,1和1不能在一起,1和2不能在一起,1和4不能再一起,2和2不能在一起,其他都可以在相邻
并且1只能和8在一起,所以要让1旁边有尽量少的空位,那么我们就从第一个位置开始放1,并且隔一个位置,再放下一个1,直到把1放完,这样使得1旁边
有最少的空位。
如果这样放到最后要给位置,还没有把1放完,那么就是无解,输出NO


对于2,只要和2不相邻且和1不相邻。所以接着之前放1的位置的下下个位置放2,直到把2放完,这样可以放置最多的2。
如果这样放到最后一个位置,还没有把2放完,那么就是无解,输出NO


然后在空着的位置,先放8,再放4
最后check一下,相邻的乘积是否为8的倍数
如果不是,输出NO
如果是,输出YES


举个例子
6
1  1  2  4  8  8
先放置1,即第一个和第三个位置为1
再放置2,即第五个位置为2
然后先放8,即第二和第四个位置是8
最后放置4,即第六个位置是4


1 8 1 8 2 4  答案即是这个。

#include <iostream>
#include <cstdio>
using namespace std;


int a[4];
int b[105];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        int x;
        scanf("%d",&x);
        if(x==1) a[0]++;
        if(x==2) a[1]++;
        if(x==4) a[2]++;
        if(x==8) a[3]++;
    }
    int flag=0;
    for(int i=0;i<n;i+=2)
    {
        if(a[flag]==0)
        {
            if(flag==0) flag++;


            if(a[flag]==0) break;
        }
        b[i]=flag+1;
        a[flag]--;
    }
    if(a[0]!=0||a[1]!=0)
    {
        printf("NO\n");
        return 0;
    }
    flag=3;
    for(int i=0;i<n;i++)
    {
        if(b[i]!=0) continue;
        if(a[flag]==0)
        {
            if(flag==3) flag--;
        }
        if(flag==3) b[i]=8;
        else b[i]=4;
        a[flag]--;
    }
    bool sign=0;
    for(int i=1;i<n;i++)
    {
        if(b[i]*b[i-1]%8!=0)
        {
            printf("NO\n");
            sign=1;
        }
    }
    if(sign==0)
    {
        printf("YES\n");
        for(int i=0;i<n;i++) printf("%d ",b[i]);
    }
    return 0;
}

E:矩阵

当K=1时

先随便写出一个(N-1)*(M-1)的元素为1或-1的矩阵

对第i(1<=i<=N-1)行进行分类讨论

如果第i行里第1列到M-1列的元素之积为1,则在第N行第M列里填充1,则显然会使得第i行从第1列到第M列的元素之积为1,

如果第i行里第1列到M-1列的元素之积为-1,则在第N行第M列里填充-1,则显然会使得第i行从第1列到第M列的元素之积也为1,

也就是说令

对第j(1<=J<=M-1)列也这样处理,即令

这样分别处理完以后就可以保证第1行到第N-1行的各行内元素之积一定为1且第1行到第N-1列的各列内元素之积也一定为1,那么只要使得第N行和第M列的元素之积为1就可以了。

因为矩阵A的元素 ,

那么可以得到和,容易得到,也就是说不论在第N行第M列里填充1或者-1,都会使得第N行和第M列内各元素之积相等,所以,只要令就可以使得这个矩阵满足条件了。而且,显然可以的知道不论一个什么样的(N-1)*(M-1)的矩阵都有且只有一个满足K=1的条件的N*M的矩阵与之对应,也就是说当K=1时,答案就是

 

当K=-1的时候,方法与k=1的时候类似,但是当N和M的奇偶性不一样的时候就会使得不论一个什么样的(N-1)*(M-1)的矩阵都不会存在一个与之对应的符合条件的N*M的矩阵。因为此时 ,而

不论在第N行第M列里填充1或者-1,都会使得第N行和第M列内各元素之积都不 相等。

所以当K=-1且N,M的奇偶性相同时,答案就是,否则是0。

#include <cstdio>
#include <cstring>
#include <iostream>
#define ll long long
using namespace std;

int n , m  , k;

int main(){
    scanf("%d%d%d",&n,&m,&k);
    if ( ( k == 1) || (  ( k==-1 ) && ( (n+m)%2== 0 )  ) )
        {
            long long ans=1;
            for (int i = 1;i<= n-1 ;i++)
                for (int j= 1; j<=m-1;j++)
                    ans=ans*2ll;
            cout<<ans<<endl;
        }
    else
        puts("0");
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值