8.20 2020 Multi-University Training Contest 10题解及补题

8.20 2020 Multi-University Training Contest 10题解及补题

比赛过程

结尾场最后一场多校比赛,确实可能比较懈怠了,爆零

题解

1003 Mine Sweeper

题意

定义《扫雷》游戏的地图中每个空白格子的值为其周围八个格子内地雷的数量(即游戏内临近地雷数量的提示)

则一张地图的值S为所有空白格子的值总和

给定S,要求构造出一张长度与宽度均不超过25的地图,使其值等于S

解法

如果 \(*S* *≤* 24\),我们可以构造这样的地图:“.X.X.X· · · ”,可知当长度为 l 的时候,数字和就等于\(l -1\)

如果 \(*S >* 24\),我们可以把 \(*S*\) 写成 \(*S* = 8*a* + 3*b*\) 的形式,其中$ a, b 0, b < 8$,那么我们可以构造类

似如下的地图:

. . . . . . . . .

.X.X.X.X.

. . . . . . . . .

.X.X . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . XX

其中包含恰好 $a $个孤立的 “X” 和 \(*b*\) 个右下角那种连续的 “X”,可知一个孤立的 “X” 可以对数字和带来 8 的贡献,而右下角那种连续的 “X” 一个可以带来 3 的贡献。

代码

#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define INF 0x3f3f3f3f
#define pi 3.141592654
#define pb push_back
#define fi first
#define se second
#define mp make_pair
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <ll,ll> pii;
const int N = 2e6+5;
char s[33][33];
int main(){
    int t,n;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        if(n <= 24){
            printf("1 %d\n",n+1);
            for(int i = 1 ; i <= n+1 ; i++)
                if(i%2 == 1)    printf("X");
                else        printf(".");
            printf("\n");
        }else{
            printf("25 25\n");
            int a=0,b=0;
            int tem = n%8;
            if(tem%3 == 0)  a = n/8,b=tem/3;
            if(tem%3 == 1)  a = n/8 - 1 ,b = tem/3 + 3;///25,28,31
            if(tem%3 == 2)  a = n/8 - 2 ,b = tem/3 + 6;///26,29
            for(int i = 1 ; i <= 24; i ++){
                for(int j = 1 ; j <= 25 ; j++){
                    if(i%2 == 1)    printf(".");
                    else if(j%2 == 0 && a>0) {printf("X");a--;}
                    else    printf(".");
                }
                printf("\n");
            }
            for(int i = 1 ; i <= 25 ; b--,i++)
                if(b>0) printf("X");
                else    printf(".");
            printf("\n");
        }
    }
    return 0;
}

1004 Permutation Counting

题意

对于任一种\(N\)的排列\(A\),定义它的\(E\)值为序列中满足\(A[i]>i\)的数的个数。给定\(N\)\(K(K<=N<=1000)\),问\(N\)的排列中\(E\)值为\(K\)的个数。

解法

简单DP。\(dp[i] [j]\)表示\(i\)个数的排列中\(E\)值为\(j\)的个数。假设现在已有一个\(E\)值为\(j\)\(i\)的排列,对于新加入的一个数\(i+1\),将其加入排列的方法有三:1)把它放最后,加入后\(E\)值不变 2)把它和一个满足\(A[k]>k\)的数交换,交换后\(E\)值不变 3)把它和一个不满足\(A[k]>k\)的数交换,交换后\(E\)\(+1\) 根据这三种方法得到转移方程\(dp[i] [j] = dp[i - 1] [j] + dp[i - 1] [j] * j + dp[i - 1] [j - 1] * (i - j)\);

代码

#include<stdio.h>
#include<iostream>
using namespace std;
const int MAXN=1001;
long long dp[MAXN][MAXN];
const long long MOD=1000000007;
int main()
{
    int n,k;
    int i,j;
    for(i=1;i<=1000;i++)
    {
        dp[i][0]=1;
        for(j=1;j<i;j++)
          dp[i][j]=(dp[i-1][j]+dp[i-1][j]*j+dp[i-1][j-1]*(i-j))%MOD;
    } 
    while(scanf("%d%d",&n,&k)!=EOF)
      printf("%I64d\n",dp[n][k]);
    return 0;  
}  

1010 Tic-Tac-Toe-Nim

题意

在一个3*3的矩阵给九堆石头,A和B每次取正整数块石头,谁先使成矩阵出现一行或一列的空堆谁就赢了,斜着的不算。第一轮必须拿走整个的一堆石头。问赢的方案数

解法

第一轮如果AB取走同行同列的那么B必输,肯定是取走两堆不同行不同列的石头。则剩下七堆石头中有一堆与前面不同行不同列。那么谁先取到其余六堆都只剩一个且第七堆石头剩0个谁就赢了。就变成简单的nim博弈

代码

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a[4][4],n,t;
    scanf("%d",&t);
    while(t--){
        for(int i = 1 ; i <= 3; i++)
            for(int j = 1 ; j<=3 ; j++)
                scanf("%d",&a[i][j]);
        int sum = 0;
        for(int i = 1 ; i <= 3 ; i++)
        for(int j = 1 ; j <= 3 ; j++){
            int flag = 1;
            for(int ii = 1 ; ii <= 3 ; ii++){
                for(int jj = 1 ; jj <=3 ; jj++){
                    if(ii == i || jj == j)  continue;
                    int x = 0;
                    for(int k = 1 ; k <= 3 ;k++)
                    for(int l = 1 ; l <= 3 ; l++){
                        if((k==i&&l==j)||(k==ii&&l==jj))    continue;
                        if(k==i || l==j || k== ii || l == jj)
                            x ^= (a[k][l]-1);
                        else    x ^= a[k][l];
                    }
                    if(x == 0){
                        flag = 0;
                        break;
                    }
                }
                if(!flag)   break;
            }
            sum += flag;
        }
        printf("%d\n",sum);
    }
}

1011 Task Scheduler

题意

\(n\)个任务,\(m\)个工人,其中\(k\)个工人不能用,每个任务需要\(a_i\)个工人,且必须是可用的工人,每次任务随机选\(a_i\)个工人,如果有不可用的工人,则会重新进行选择,输出你安排任务的选择顺序,使得选择的期望最小。包装\(m-k\)个工人可以完成\(n\)个任务。

解法

对输入进行下标排序

代码

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct aaa{
    int val;
    int num;
};
bool cmp(aaa a,aaa b)
{
    if(a.val!=b.val)
    return a.val>b.val;
    else
    return a.num<b.num;
}

aaa a[10005];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i].val);
            a[i].num=i;
        }
        if(k!=0)
        sort(a+1,a+n+1,cmp);
        for(int i=1;i<=n;i++)
        {
        	if(i!=n)
        	printf("%d ",a[i].num);
        	else
        	printf("%d",a[i].num);
		 } 
        
        printf("\n");     
    }
    return 0;
}

posted @ 2020-09-01 22:25  cugbacm03  阅读(271)  评论(0)    收藏  举报