牛客网 哈尔滨工程大学ACM预热赛 ABCEH题解

Adiagrams

题目描述

小虎刚刚上了幼儿园,老师让他做一个家庭作业:首先画3个格子,第二行有2个格子,第三行有1个格子。每行的格子从左到右可以放棋子,但要求除第一行外,每行放的棋子数不能超过上一行的棋子。玩了一会儿,小虎问大哥大虎:这个作业有很多种摆放法,我想都找到,但我不知道有多少中方案,你能帮助我么?
大虎是学校信息学集训队的,立刻想到用计算机来解决这个问题,并很快有了解答:13。第二天他把问题拿到了学校,并说如果第一行有N个格子,第二行有N-1个格子,…,第N行有1个格子,怎么办?现在请你一块来帮助他解决这个难题。
数据范围
30%数据:1≤N≤12
50%数据:1≤N≤30
100%数据:1≤N≤100

输入描述:

仅一行,一个正整数N。

输出描述:

一行,方案总数。

示例1

输入

复制

2

输出

复制

4

说明

样例1说明N=2时,有如下4中摆放棋子法(*表示棋子,_表示空格):
方案法    1    2    3    4
摆放法    *_    **    *_    **
摆放法    _    _    *    *

示例2

输入

复制

3

输出

复制

13

思路:

递推。

设dp[n][i]表示的是第n层放i个格子的方法数。

则:

i=1时,dp[n][1]=n;

i>1&&i<n时,dp[n][i]=dp[n-1][i]+dp[n-1][i-1]+...+dp[n-1][1]+1;

i=n时,dp[n][n]=dp[n][n-1];

此题用ll存不下结果,需要用大数运算做。

这里给出用java大数类做的答案。

代码如下:

import java.util.Scanner;
import java.math.*;
public class Main {
	public static void main(String args[]) {
		BigInteger [][]b=new BigInteger[105][];
		for (int i=1;i<=100;i++)
		{
			b[i]=new BigInteger[105];
		}
		for (int i=1;i<=100;i++)
		{
			Integer a=new Integer(i);
			b[i][1]=new BigInteger(a.toString());
		}
		for (int i=2;i<=100;i++)
		{
			for (int j=2;j<i;j++)
			{
				b[i][j]=new BigInteger("1");
				for (int k=1;k<=j;k++)
				{
					b[i][j]=b[i][j].add(b[i-1][k]);
				}
			}
			b[i][i]=new BigInteger(b[i][i-1].toString());
		}
		Scanner sc=new Scanner (System.in);
		int n;
		n=sc.nextInt();
		BigInteger ans=new BigInteger("0");
		for (int j=1;j<=n;j++) ans=ans.add(b[n][j]);
		System.out.println(ans.toString());
			
	}
}
B坑坑的伴随阵

题目描述

坑坑马上就要毕业了,但是在毕业之前需要完成毕业设计才能顺利毕业,可是坑坑的毕设题目很难,是有关图像处理的,涉及到矩阵方面的知识,对数学要求很高。坑坑在研究毕设的时候遇到了一个难题,需要通过今天的比赛发现好的解题方法,希望大家可以帮忙。需要解决的问题是这样的,有一个矩阵A,它是3*3的方阵,现在需要编程实现计算矩阵|A*|(矩阵A对应的伴随阵的行列式的值),矩阵中的每个元素值都在0~255之间。

输入描述:

输入数据为T组数据(1<=T<=10)。
每组数据有三行,每行三个数字,表示矩阵A中的元素值(0<=元素值<=255)。

输出描述:

对于每组数据,输出一个数字,表示矩阵A对应的伴随阵的行列式的值。

示例1

输入

复制

2
1 0 0
0 1 0
0 0 1
0 0 1
0 1 0
1 0 0

输出

复制

1
1

 思路:

直接套用矩阵求伴随矩阵对应的行列式的值即可。

公式为:

(a11*(a22*a33-a23*a32)-a12*(a21*a33-a23*a31)+a13*(a21*a32-a31*a22))^2;

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ans;
int t;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        ans=0;
        int a[5][5];
        for (int i=1;i<=3;i++)
        {
            for (int j=1;j<=3;j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        ll t1=a[1][1]*(a[2][2]*a[3][3]-a[2][3]*a[3][2]);
        ll t2=a[1][2]*(a[2][1]*a[3][3]-a[2][3]*a[3][1]);
        ll t3=a[1][3]*(a[2][1]*a[3][2]-a[3][1]*a[2][2]);
        printf("%lld\n",(t1-t2+t3)*(t1-t2+t3));
    }
    return 0;
}

 

Cking

题目描述

国王有一块神奇土地
第一天可以产a吨粮食,第二天会变成前一天的a倍,以此类推。
n天后大臣准备把这些粮食尽可能多的平均分给b个城池
为了方便,每个城池分到的粮食都是整吨整吨哒!
剩下的粮食国王准备贪污
国王能贪到多少吨粮食呢?

 

输入描述:

输入的第一行为一个数字T(T<=100),表示数据输入的组数。
之后每行3个数字,分别表示 a, n, b(1<=a,n<= 1000,000,000;1<=b<=1000 )。

输出描述:

对于每组数据输出对应结果

示例1

输入

复制

1
2 2 3

输出

复制

1

思路:

 题目的实际目的就是求a^n%b;

这可以直接转化成矩阵快速幂做。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;
ll quick (ll a,ll b,ll c)
{
    ll ans=1;
    while(b)
    {
        if(b%2) ans=ans*a%c;
        a=a*a%c;
        b>>=1;
    }
    return ans;
}
    
int main()
{
    scanf("%d",&t);
    ll a,n,b;
    while(t--)
    {
        scanf("%lld%lld%lld",&a,&n,&b);
        printf("%lld\n",quick(a,n,b));
    }
    return 0;
}

 

EMother's Day

链接:https://ac.nowcoder.com/acm/contest/554/E
来源:牛客网
 

题目描述

Mother's Day is a celebration honoring the mother of the family, as well as motherhood, maternal bonds, and the influence of mothers in society, which is celebrated on various days in many parts of the world, but mostly, the date is on the second Sunday in May. 
    Like Mother's Day, there are also several celebrations have no fixed date, but are set in the form of "the Bth(st/nd) weekday C of the Ath(st/nd) month in a year", for example, as above, Mother's Day is on the second Sunday in May of a year, but also can be described as "the 2nd weekday 7 of the 5st month in a year"(A=5, B=2, C=7). 
    Now, to help remember these special days, HVT wants you to calculate all the exact date of such celebrations in the past and future hundreds of years, which means that you are given 4 numbers: A(1 ≤ A ≤ 12), B(B ≥ 1), C(1 ≤ C ≤ 7, 1=Monday,2=Tuesday,...,7=Sunday) and y(represents the year, 1850 ≤ y ≤ 2050), and you should write code to calculate the exact date of "the Bth(st/nd) weekday C of the Ath(st/nd) month in a year y".
    For your convenience, we will noice you that: January 1st, 1850 is a Tuesday.

 

输入描述:

The input contains multiple lines of test data, each line has 4 numbers: A B C and y.

输出描述:

For each input, you should output a exact date in the format of "yyyy/mm/dd"(When the number of digits is insufficient, 0 should be added to the front);
if the Bth(st/nd) weekday C of the Ath(st/nd) month in a year y does not exist(for example, there will never be a 7th Monday in any months of any year), you should output "none" (without quotes).

示例1

输入

复制

4 2 7 2018
4 1 7 2018
2 5 4 2018
2 4 3 2018

输出

复制

2018/04/08
2018/04/01
none
2018/02/28

思路:

根据基姆拉尔森计算公式直接求出要求的月的第一天然后模拟即可。

代码如下:

#include <bits/stdc++.h>
using namespace std;
int a,b,c,y;
int main()
{
    while(scanf("%d%d%d%d",&a,&b,&c,&y)!=EOF)
    {
        int td,tm,ty;
        td=1,tm=a,ty=y;
        if(tm==1||tm==2) {
                tm+=12;
                ty-=1;
        }
        int w=(td+2*tm+3*(tm+1)/5+ty+ty/4-ty/100+ty/400)%7;
        int day[15]={0,31,28,31,30,31,30,31,31,30,31,30,31};
        if((y%4==0&&y%100)||(y%400==0)) day[2]++;
        int st=w;
        int d=1,num=0;
        while(st!=c-1)
        {
            st=(st+1)%7;
            d++;
        }
        while(num<b-1&&d<=day[a])
        {
             num++;
             d+=7;
        }
        if(num==b-1&&d<=day[a])
        {
            printf("%d/%02d/%02d\n",y,a,d);
        }
        else
        {
            printf("none\n");
        }
    }
    return 0;
}
H蹲着还是站着?

题目描述

杨主席这段时间由于要找实习,所以非常焦躁。因为公司的面试都非常的难,杨主席不知道从哪入手。于是他就找了他的学长坑坑询问情况,坑坑告诉他要注重算法的学习,于是就给杨主席出了一个题目看看他算法学的怎么样,这道题是这样的:有N个人排成一排,从1到N按顺序依次编号,现在要执行N次操作,第一次操作让所有的人都蹲下,之后第二次操作让编号是2和2的倍数的人全部站起来,然后第三次操作让编号是3和3的倍数的人全部做相反的动作(站着的人蹲下,蹲下的人站起来),以此类推...,最后第N此操作让编号为N的这个人也做相反的动作。请问N次操作后,从第A个人到第B个人之间(包括A和B这两个数字,且A<B)有多少人是站着的?

输入描述:

输入数据为T组数据(1<=T<=10)。
每组数据输入包含三个数字N,A,B(1<=N<=1000000,1<=A<B<=N)。

输出描述:

对于每组数据,输出一个整数,表示从第A个人到第B个人之间有多少人站着。

示例1

输入

复制

1
5 1 3

输出

复制

2

思路:

先求出1000之内的素数,然后分解1----1e6的素因子,然后求出约数个数,然后判断即可。

代码如下:

 

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
typedef long long ll;
int t;
int pri[maxn];
int num[maxn];
vector<int>v;
int n,a,b;
void judge()
{
    for (int i=2;i<1005;i++)
    {
        if(pri[i]==0)
        {
            v.push_back(i);
            if((ll)i*i>=maxn) continue;
            for (int j=i*i;j<1005;j+=i) pri[j]=1;
        }
    }
}
int main()
{
    memset (pri,0,sizeof(pri));
    memset (num,1,sizeof(num));
    judge();
    //printf("---\n");

    for (int i=1;i<=1000000;i++)
    {
        int t=i;
        int Size=v.size();
        for (int j=0;j<Size;j++)
        {
            if(v[j]>t) break;
            if(t%v[j]==0)
            {
                int tnum=0;
                while(t%v[j]==0)
                {
                    tnum++;
                    t/=v[j];
                }
                num[i]*=(tnum+1);
            }
        }
        if(t!=1) num[i]*=2;
    }
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&a,&b);
        int ans=0;
        for (int i=a;i<=b;i++) if(num[i]%2==0) ans++;
        printf("%d\n",ans);
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值