1. 程式人生 > >電子科技大學第九屆ACM趣味程式設計競賽第二場(正式賽) 題解

電子科技大學第九屆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;
}