前两天打了第二场积分赛,难度明显比上次高,感觉更考验思维了,收集了一些我认为有价值的题目,因为太懒了,不想自己写思路题解了,搬来了别人的代码和题解,以后争取养成保存代码的习惯🐷

# A 徐半仙的数学难题

描述

徐半仙经常修炼。但是每次修炼所能提升的功力确是不确定的(可能是功力还不够深厚

吧)。

每次修炼结束之后,徐半仙的脑海中就会浮现出两个数字,n m,他的师父跟他说他每

次修炼增加的功力就是由这两个数决定的。每次增加的功力为 (n!!!)%m,即 n 的阶乘的阶乘的

阶乘对 m 取模之后的值。

徐半仙想让你帮他写一个程序,通过 n m 得到他每次修炼之后提升了多少功力。如果这

次修炼后提升的功力为 0,输出 baigei

输入数据

多组输入,第一行一个正整数 t(1 t 105) 表示数据组数

每组数据包含两个整数 n, m(0 n 109*,* 1 m 109)

输出数据

对于每组数据,如果答案为 0,输出 baigei,否则输出答案(每次修炼后提升的功力)

样例输入

2

2 6553

2 2

样例输出

2

baigei

提示

在样例中,(2!!!) = 2, 对 6553 取模为 2,直接输出,对 2 取模为 0,输出 baigei

# 分析

我们知道模最大是 109,并且很容易知道从 4 开始,这个数的阶乘的阶乘已经是大于 109 的,

并且因为我们求的是阶乘,阶乘最后取模和每次取模后相乘的结果相同,因为现在计算的数一

定大于模,所以一定会出现一项为 0,因此最后的结果也为 0。所以如果 n 小于 4,我们直接暴力

计算就可以了,反之直接输出 baigei 即可

# CODE

#include <bits/stdc ++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define mp make_pair
const int maxn = 1e5 +10;
const int mod = 1e9 +7;
const int INF = 0 x3f3f3f3f ;
int main () {
    int t; cin >>t;
    while(t--){
        ll n,m,ans;
        cin >>n>>m;
        if(n <=1){
        	ans =1%m;
        }else if(n==2){
        	ans =2%m;
        }else if(n==3){
        	ans=1;
        for(ll i=1;i <=720;i++){
            ans *=i;
            ans %=m;
        }
        }else{
        	ans =0;
        }
        if(ans ==0){
            cout <<"baigei\n";
        }else{
        	cout <<ans <<endl;
        }
    }
    return 0;
}

# B 徐半仙的八字谜盘

  • 题目描述

有一天徐半仙正在街道上给人算八字,他摆弄一个棋盘,和 K 个棋子,棋盘是 N × N 的矩阵方

格图,共有 N × N 个格子。

突然一位神秘 ACM 大佬来了,对徐半仙说:大仙,是不是您什么难题都算得出来啊?

徐半仙:Of course!

ACM 大佬:那你算算这 N × N 的棋盘,每个方格只能放一个棋子,要把 K 个棋子都放进去,并且

第一行,最后一行,第一列,最后一列,主对角线,副对角线都至少有一颗棋子的方案数是多

少?

顿时,徐半仙冷汗直流,不知如何应对这位不速之客,只好说:ok....ok.....

为了不显尴尬,徐半仙偷偷用他的迷你手机给你发了一通电报,告诉你 N 和 K,请求你尽快把答

案发送给他。

  • 输入数据

第一行为数据的组数 T (T ⩽ 1000)

接下来 T 行,每行为两个整数 N K (2 ⩽ N ⩽ 100*,* 0 ⩽ K ⩽ 100)

  • 输出数据

输出 T 行,第 i 行为第 i 组询问的答案。由于答案可能过大,请将答案模 1e9+7 之后再输出。

  • 样例输入
1

3 3
  • 样例输出
10

# 分析

这题主要考察了组合数 + 容斥原理,其中组合数不是难点,直接套模板就行。

这里如果直接求就必须得考虑很多的情况,所以可以反着来,先求个无规则的任意的摆放数,

再从这个总数里面减去不符合规则的。

但是我们发现,如果减去了第一行没有棋子的摆放数 A,再减去了最后一行没有棋子的摆放数 B,

其实就多减去了第一行和最后一行没有棋子的情况,所以这一部分减多的,还要加回来。这里

就可以看到容斥原理了,然后就可以写一个二进制枚举,一共就 6 条线上的格子,2 的 6 次方种

情况,对应 0~31 (1 代表该条线上没有棋子,0 代表可有可无),如果是奇数个 1 就减去对应的摆

放数,如果是偶数个 1,就加上对应的摆放数。代码稍微多点,但思路上并不难。

# CODE

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN=10010;
const ll MOD=1e9+7;
ll c[MAXN][110];
void __initC(ll N = 10005){
	c[1][1]=1;
	for(ll i=0;i<=N;i++) c[i][0] = 1;
	for(ll i=1;i<=N;i++){
		for(ll j =1;j<=105;j++){
			c[i][j]=(ll)(c[i-1][j]+c[i-1][j-1])% MOD;
		}
	}
}
ll N,K;
int main()
{
	__initC();
	ll t;
	scanf("%lld",&t);
	while(t--){
		scanf("%lld%lld",&N,&K);
		ll ans=0;
		for(ll i=0;i<(1<<6);i++){
			ll cnt=0,n=N,m=N,L=0,R=0;
			for(ll j=0;j<6;j++){
				if(i>>j &1){
					cnt++;
					if(j==0||j==1) n--;
					if(j==2||j==3) m--;
					if(j==4){
						L=N;
						if((i>>0&1)||(i>>2&1)) L--;
						if((i>>1&1)||(i>>3&1)) L--;
					}
					if(j==5){
						R=N;
						if((i>>0&1)||(i>>3&1)) R--;
						if((i>>2&1)||(i>>1&1)) R--;
					}
				}
			}
			ll num=n*m;
			if(L && R && N&1) num-=L+R-1;
			else num-=L+R;
			if(cnt&1) ans=(ans-c[num][K]+MOD)%MOD;
			else ans=(ans+c[num][K])%MOD;
	 	}
	 	printf("%lld\n",ans);
	}
	return 0;
}

# D 徐半仙的修仙之路

  • 描述

徐半仙每天闲来无事就在家中打坐,他相信这样能够悟道,得道升仙的方法;

有一天他接到了一个电话,电话中告诉他,蜀山的掌门给了他一次让他去蜀山学习的机会,约

他去城郊见面。于是他特别开心的答应了下来,但是他到了以后发现对方竟然是传销团伙,徐

半仙这时十分的后悔,他想偷偷的逃走但是这里守卫森严他一点办法都没有,这时他十分无助

的哭泣着并且十分后悔自己迷恋修仙。忽然旁边的憨憨龙告诉他,只要你能够计算出这个房子

有几间房间,并且最大的一间房间有多大就可以帮助他逃走了。

这个房子是只有一层,被分成了 n m 列,每一间房间的面积都是 1,但是因为传销团伙

为了节约空间,这些房间的四面墙有些被堵着了。并且如果两个房间连在一起就是一个面积

为 2 的房间。

这时徐半仙突然看到了机会,于是经过徐半仙的一波神奇的操作后他和憨憨龙一起逃出了

这个传销团伙,并且还配合警方抓捕了这个传销团伙。从这以后徐半仙再也不想着修仙了,他

一心专注于程序设计,并成为了一名优秀的 acmer。

聪明的你一定想知道徐半仙如何计算的吗?那么你也来尝试一下吧,看看你和徐半仙谁更

厉害一点!

  • 输入数据

每个测试有 T 组数据每组第一行输入两个数 n, m (1 ⩽ n, m ⩽ 50。接下来 n 行数据,每

m 个整数这个整数 p 表示表示这个房间所拥有的墙的编号和 (1 表示左墙,2 表示上墙,4 表示

右墙,8 表示下墙)

  • 输出数据

输出两个整数分别代表房间的数量,和最大的房间面积。

  • 样例输入
1

4 7

11 6 11 6 3 10 6

7 9 6 13 5 15 5

1 10 12 7 13 7 5

13 11 10 8 10 12 13
  • 样例输出
5 9

# 分析

这题主要考察你的 dfs 和你的建模能力。其实如果就是我们的一个模板题 Oil Deposits

只是在这道题上加了一个走下一步的限制条件。

如果 p&8 == 0 我们可以向下走

如果 p&4 == 0 我们可以向右走

如果 p&2 == 0 我们可以向上走

如果 p&1 == 0 我们可以向左走

这样的话就和上面的模板题一样了

# CODE

#include<bits/stdc++.h>
using namespace std;
int maze[60][60],M,N;
int book[60][60];
int roomnum =0, maxroom =0, room;// 记录 房 间数 、 最大房间 、 目 前 房 间 大 小 
void dfs(int x,int y){ 
	if(book[x][y]) return;
	room++;
	book[x][y]=1;
	if(( maze[x][y] & 1)==0) dfs(x,y-1);
	if(( maze[x][y] & 2)==0) dfs(x-1,y);
	if(( maze[x][y] & 4)==0) dfs(x,y+1);
	if(( maze[x][y] & 8)==0) dfs(x+1,y);
}
int main ()
{
	int t;cin>>t;
	while(t--){
		cin>>M>>N;
		memset(book ,0,sizeof(book ));
		for(int i=0;i<M;i++){
			for(int j=0;j<N;j++){
				cin>>maze[i][j];
			}
		}
		for(int i=0;i<M;i++){
			for(int j=0;j<N;j++){
				if(!book[i][j]){
					room=0;
					roomnum++;
					dfs(i,j);
					maxroom=max(maxroom,room );
				}
			}
		}
		cout<<roomnum<<" "<<maxroom<<"\n";
	}
	return 0;
}

# G 徐半仙的数学问题

  • 描述

已知有 a,b,c,d 四个正整数求满足下列两个等式的 x 的个数。

gcd (x, a) = b

lcm (x, c) = d

  • 输入数据

第一行输入一个整数 T,表示测试的组数

第 2 行到 T+1 行,每行 4 个整数,分别表示 a,b,c,d. 数据保证 a 能够被 b 整除,d 能够被 c 整除

1 <= T <= 2000

1 <= a, b, c, d <= 2e9

  • 输出数据

共 T 行,每行一个整数,如果不存在这样的 x, 输出 0, 否则,输出满足条件的 x 的个数

  • 样例输入
4

41 1 96 288

95 1 37 1776

8481 1 999976991 1999953982

32560 2 999992632 1999985264
  • 样例输出
6

2

4

0

# 分析

考察了唯一分解定理求 lcm 和 gcd,打一个素数表,枚举素数,打出质因子表。详细看 bilibili

# CODE

#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <vector>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#define ios ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define debug  freopen("in.txt","r",stdin),freopen("out.txt","w",stdout);
#define PI acos(-1)
#define fs first
#define sc second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const ll maxn = 1e6+10;
double eps = 1e-8;
 
int T;
int a0,a1,b0,b1;
bool vis[maxn];
int P[maxn],tail;
struct node{
    int a,b,c,d;
};
map<int,node> mp;
void initP(int N){
    for(int i = 2;i<=N;i++){
        if(!vis[i]) P[tail++] = i;
        for(int j = 0;P[j]<=N/i;j++){
            vis[P[j]*i] = true;
            if(i%P[j] == 0) break;
        }
    }
}
void divP(){
    int idx = 0;
    for(int t:{a0,a1,b0,b1}){
        ++idx;
        for(int j = 0;j<tail && P[j]*P[j] <=t;j++){
            if(t%P[j] == 0){
                int cnt = 0;
                while(t%P[j] == 0){
                    cnt++;
                    t/=P[j];
                }
                if(idx == 1) mp[P[j]].a = cnt;
                if(idx == 2) mp[P[j]].b = cnt;
                if(idx == 3) mp[P[j]].c = cnt;
                if(idx == 4) mp[P[j]].d = cnt;
            }
        }
        if(t>1){
            if(idx == 1) mp[t].a = 1;
            if(idx == 2) mp[t].b = 1;
            if(idx == 3) mp[t].c = 1;
            if(idx == 4) mp[t].d = 1;
        }
    }
}
ll fun(){
    ll res = 1;
    for(auto p:mp){
        node cur = p.second;
        int a = cur.a,b = cur.b,c = cur.c,d = cur.d;
        int cnt = 0;
        for(int i = 0;i<=31;i++){
            if(min(i,a) == b && max(i,c) == d) cnt++;
        }
        res *= cnt;
    }
    return res;
}
int main(){
    ios;
    initP(1<<16);
    cin>>T;
    while(T--){
        cin>>a0>>a1>>b0>>b1;
        mp.clear();
        divP();
        cout<<fun()<<endl;
    }
    return 0;
}
更新于

请我喝[茶]~( ̄▽ ̄)~*

PocketCat 微信支付

微信支付

PocketCat 支付宝

支付宝