字节跳动-文远知行杯 广东工业大学第十四届程序设计竞赛(部分题解)

zsl 和 hzy 来到了臭臭城堡,打算挑战臭臭城堡的大魔王 hyz ,大魔王 hyz 准备让他们进行这样的一个挑战:

挑战开始,zsl 和 hzy 两个人各自来到一间密室,期间两人无法以任何形式交流,期间两人无法以任何形式交流
大魔王 hyz 会随机在两个人的脑海里各发送一个数字,00 或者是 11
zsl 和 hzy 需要猜对对方听到的数字才算通关(当然是在各自的密室中回答的,也就是说回答的时候,zsl 听不到 hzy 的回答,同样,hzy 也听不到 zsl 的),但是大魔王 hyz 觉得人生不能过于无敌,因此降低难度,只要两个人中有一个人答对就算是通关
进行挑战之前,zsl 和 hzy 讨论并制定了一个详细的作战方案,使得自己通关的几率最高,并开始了这次挑战……

显然大魔王 hyz 给这两个人出的数字所有可能的情况有 0000, 0101, 1010, 1111 四种,请按上述枚举的顺序,计算所有情况下 zsl 和 hzy 通关的几率。

Input
(空)

Output
输出四个答案,每个答案后面跟随一个换行符并且保留两位小数位,分别对应 0000, 0101, 1010, 1111的情况下,zsl 和 hzy 通关的几率

样例输入 复制
(空)
样例输出 复制
1.00
0.00
0.50
0.55 (输出仅做格式参考,不保证正确性)

一个人报自己听到的数字,另一个报相反的

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cstdlib>
#include<cmath>
#include<stack>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define endl '\n'
const double pi = acos(-1);
const int maxn = 1e5 + 10;
const int maxm = 5e5 + 10;
const int mod = 998244353;

int main()
{
    cout << "1.00" << endl;
    cout << "1.00" << endl;
    cout << "1.00" << endl;
    cout << "1.00" << endl;
    return 0;
}

作为 CNCS 的半壁江山,狗哥常常在宇宙中心邵阳眺望黄浦江,夜晚的星空总是迷人,有时候还能见到彗星滑落。

狗哥是幸运的,他在两秒钟内看到了十七颗彗星划过天际,作为打 ACM 的学者,自然不会有「稳定-1」情况。他开始研究彗星运动的轨迹,发现他们都遵照斐波那契螺旋线在运动着。

尤里卡!狗哥觉得这就是找寻「生命,宇宙和一切的终极答案」的精要所在,但是怎么表示呢?狗哥觉得求取斐波那契螺旋线经过的一个个方格的面积之和就是公式的表现。

如下图,螺旋线每划过一个方格,都转过了四分之一圈。我们从第 0+\frac{0}{4}0+
4
0

圈转到第 0+\frac{1}{4}0+
4
1

圈,划过了最里面的两个方格,面积之和为 2(=1+1)2(=1+1) 。同理,从第 0+\frac{0}{4}0+
4
0

圈到第 1+\frac{0}{4}1+
4
0

圈划过了最里面的五个方格,他们的面积之和为 40(=1+1+4+9+25)40(=1+1+4+9+25) 。

但是聪明的狗哥需要一个程序去获得指定范围内的螺旋线面积之和,狗哥给了你一首「希望之花」的时间,而他需要利用这个时间去打出四暗刻单骑。如果你能完成这个程序,狗哥会封你为格拉摩根伯爵。

Input
不定组数据。

首先输入一个整数 QQ,代表狗哥询问次数。

接下来 QQ 行,每行四个整数 a , b , c , da,b,c,d,代表狗哥想求 a+\frac{b}{4}a+
4
b

到 c+\frac{d}{4}c+
4
d

之间的螺旋线面积之和。

1 \le Q \le 100001≤Q≤10000

0 \le a , c \le 100000≤a,c≤10000

0 \le b , d \le 30≤b,d≤3

结果对 192600817192600817 取模。

Output
一个数字,表示螺旋线面积之和。

样例输入 复制
4
0 0 0 1
0 0 1 0
1 2 2 1
1 1 0 3
4
0 0 0 1
0 0 1 0
1 2 2 1
1 1 0 3
样例输出 复制
2
40
4791
98
2
40
4791
98

按题意搞个前缀和搞搞

#include<bits/stdc++.h>
using namespace std;
#define maxn 50005
#define ll long long
const ll mod=192600817;

int t,a1,b1,a2,b2;
ll f[maxn],sum[maxn];

void init(){
	f[0]=f[1]=1;
	sum[0]=0;sum[1]=2;
	for(int i=2;i<maxn;i++){
		f[i]=(f[i-1]+f[i-2])%mod;
		sum[i]=(sum[i-1]+f[i]*f[i]%mod)%mod;
		//sum[i]%=mod;
	}
}
int main()
{
	init();
	while(~scanf("%d",&t)){
		while(t--){
			scanf("%d %d %d %d",&a1,&b1,&a2,&b2);
			int s1=4*a1+b1,s2=4*a2+b2;
			if(s1>s2)swap(s1,s2);
			if(s1!=0)printf("%lld\n",((sum[s2]-sum[s1]+mod)%mod+f[s1]*f[s1]%mod) % mod);
			else printf("%lld\n",(sum[s2]-sum[s1]+mod)%mod);
		}
	}
	return 0;
}

通常来说,题面短的题目一般都比较难,所以我要把题面写得很长很长。

通常来说,题面短的题目一般都比较难,所以我要把题面写得很长很长。

通常来说,题面短的题目一般都比较难,所以我要把题面写得很长很长。

鸽子数字由以下过程定义:从任何正整数开始,将数字替换为其各个数位的平方和,并重复该过程,直到该数字等于 11。如果不能,则这个数字不是鸽子数。

例如 77 是鸽子数,因为 7 \to 49 \to 97 \to 130 \to 10 \to 17→49→97→130→10→1

( 7 \times 7 = 497×7=49 , 4 \times 4 + 9 \times 9 = 97 , 9 \times 9 + 7 \times 7 = 130 \cdots4×4+9×9=97,9×9+7×7=130⋯如此类推)

显然 11 是第一个鸽子数。

有 QQ 个询问,每个询问给出一个数 kk ,你需要输出第 kk 个鸽子数。

Input
第一行一个 QQ ,代表询问的个数( Q \le 100000Q≤100000 )接下来 QQ 行,每行一个数字 kk( kk < 150000150000)

Output
每行输出一个数,代表第 kk 个鸽子数

样例输入 复制
2
1
2
样例输出 复制
1
7

打表

#include<bits/stdc++.h>
using namespace std;
#define maxn 150005

int t,x,n,sum,cnt;
int a[150005];
int main()
{
    a[++cnt]=1;
    for(int i=2;i<=1200000;i++){
        n=i;
        while(n!=1&&n!=4){
            sum=0;
            while(n){
                sum+=(n%10)*(n%10);
                n/=10;
            }
            n=sum;
        }
        if(n==1)a[++cnt]=i;
        if(cnt==150000)break;
    }
    scanf("%d",&t);
    while(t--){
    	scanf("%d",&x);
    	printf("%d\n",a[x]);
	}
    return 0;
}

又在和群里的大佬们打日本麻将了,她熟练地从牌山中摸来一个牌,然后发现,手里 1414 张牌全都是同一个花色的,也就是说,如果这些牌能够组成四个“面子”和一个“对子”构成的“一般形”,或者是七个互不相同的“对子”的“七对形”,那她就可以达成杀伤力极强的番种 - 清一色。

所谓“面子”,指的是“刻子”和“顺子”中的其中一种(我们不考虑“吃碰杠”等特殊情况,“暗杠”就更不考虑了)。“刻子”就是三张一模一样的牌,比如 111, 222111,222 等(这里由于都是同一种花色,所以麻将牌的花色省略,只看麻将牌的数字),而“顺子”就是三张数字可以组成以 11 为等差数列的牌,如 123, 234, 345123,234,345 等,但是,891, 912891,912 这样的不算。

而所谓“对子”,指的就是两张一样的牌,如 11 , 2211,22 等。

由于 Annie2212Annie2212 第一次做这么厉害的牌,缺乏经验,她想知道,她是不是已经做出了“清一色”,如果做出来了,她就可以喊一句“自摸”并把牌推倒亮明,赢得本局。

如果还没做出来,她想知道自己是否已经“听牌”,所谓“听牌”就是指换掉一张牌就可以自摸的状态,而且她想知道可以怎么换牌,她需要知道所有的选项以方便她做出决定。

值得注意的是,游戏中每种牌各有四张,如果所等的牌自己已经有四张的话,我们当然不能再等这种牌。

那么这个烧脑的任务就交给你了。

Input
本题有多组测试数据,每组测试数据有两行:

第一行:Annie2212Annie2212 刚从牌山中摸到的牌,毕竟都是同一花色,我们直接用一个范围在 11 到 99 (闭区间)以内的数字表示麻将牌,下同。

第二行:摸牌前 Annie2212Annie2212 手上的 1313 张牌,每张牌用一个空格隔开,保证这 1313 张牌已从小到大排序。

最后一个测试数据之后,会有单独的一行,这一行只有一个数字 "0"“0” ,表示输入结束。

Output
如果能自摸,输出一行 “tsumo”“tsumo” 即可 (没有引号,下同)

如果不能自摸,但是能听牌,输出一行 “tenpai”“tenpai” 后,下面若干行表示出所有换牌的选项,格式为:

X1: Y11 Y12 … Y1j …X1:Y11Y12…Y1j…X2: Y21 Y22 … Y2j …X2:Y21Y22…Y2j…Xi: Xi1 Xi2 … Yij …Xi:Xi1Xi2…Yij…

表示如果换掉 XiXi 这种牌中的一张的话,应该等 Yi1, Yi2, …Yi1,Yi2,… 这些牌中的一张才能自摸,注意,XiXi 和 Yi1Yi1 之间是用一个冒号和一个空格隔开的,同一行的各个 YijYij 之间是用一个空格隔开的,并且所有的 XiXi 必须从小到大排序,同一行的 YijYij 也要从小到大排序。

如果连听牌都做不到,输出一行 “noten”“noten” 即可。

Hint
样例解释:

第一组数据:12456791245679 正好是七种牌,各有两张,构成“七对形”,直接自摸

第二组数据:若摸到的 99 直接打出,这 1313 张手牌可以拆解成 123-123-123-23-44123−123−123−23−44 ,对这个 2323 要构成“一般形”中的“顺子”要等 11 或 44,也可以拆解成 111-222-33-234-34111−222−33−234−34 ,那么对这个 3434 要构成“顺子”要等 22 或 55,而 22 已经有四张,不可能再摸到了,所以不考虑 22 而考虑 55

第三组数据:“七对形”要求七个“对子”的种类各不相同,所以像这样有两个相同“对子”的牌型,在日本麻将中不被承认,需要再换掉两张牌才能胡“七对型”,连听牌都没有。

样例输入 复制
9
1 1 2 2 4 4 5 5 6 6 7 7 9
9
1 1 1 2 2 2 2 3 3 3 3 4 4
5
1 1 1 1 3 3 5 6 6 8 8 9 9
0
样例输出 复制
tsumo
tenpai
1: 9
4: 9
9: 1 4 5
noten

大模拟

#include<bits/stdc++.h>
using namespace std;
const int mod = 192600817;
#define ll long long
const int maxn = 10005;
int shun,ke , pai[10],paire[10];
int ff=0;
void init(){
	for(int i=1;i<=9;i++){
		pai[i]=paire[i];
	}
	ke=0,shun=0;ff=0;
}
void kezi(int num);
void shunzi(int num);
void judge();
bool dui(){
	int ans=0;
	for(int i=1;i<=9;i++){
		if(pai[i]==2)ans++;
	}
	if(ans==7)return 1;
	else return 0;
}
bool work(){
		init();
		if(dui())return 1;
		init();
		shunzi(0);
		kezi(0);
		if(ff)
		return 1;
		else return 0;
}
int main(){
	int n, pppp = 0;
    for(int i = 1 ; i <= 150 ; ++ i) pppp ++;
	int num,flag;
	while(~scanf("%d",&n))
	{
		for(int i=1;i<=9;i++)
		{
			paire[i]=0;
		}
		if(n==0)break;
		else paire[n]++;
		int x;
		flag=0;
			for(int i=1;i<=13;i++){
				scanf("%d",&x);
				paire[x]++;
			}
		if(work()){
			printf("tsumo\n");
			continue;
		}
		for(int i=1;i<=9;i++)
		{
			num=0;
			for(int j=1;j<=9;j++){
				if(paire[i]>=1&&paire[j]<4&&i!=j)
				{
					paire[i]--,paire[j]++;
					if(work()){
						flag++;
						if(flag==1)printf("tenpai");
						if(num==0)
						{
							printf("\n%d:",i);
							num++;
						}
						printf(" %d",j);
					}
					paire[j]--,paire[i]++;
				}
			}
		}
			if(flag==0)
			printf("noten\n");
			else printf("\n");
	}
	return 0;
}
void shunzi(int num){
	if(num==4)
	{
		judge();
	}
	for(int i =1 ;i <= 9;i++){
			if(pai[i]>=3)
			{
			pai[i]-=3;
			shunzi(num+1);
			kezi(num+1);
			pai[i]+=3;
			}
	}
}

void kezi(int num){
	if(num==4)
	{
		judge();
	}
	for(int i =1 ;i <= 7;i++){
			if(pai[i]&&pai[i+1]&&pai[i+2]){
				pai[i]--;
				pai[i+1]--;
				pai[i+2]--;
					shunzi(num+1);
					kezi(num+1);
				pai[i]++;
				pai[i+1]++;
				pai[i+2]++;
			}
		}
	}
void judge(){
	for(int i=1;i<=9;i++)
	{
		if(pai[i]==2)ff = 1;
	}
}

今天 zyb 参加一场面试,面试官听说 zyb 是 ACMer 之后立马抛出了一道算法题给 zyb :

有一个序列,是 11 到 nn 的一种排列,排列的顺序是字典序小的在前,那么第 kk 个数字是什么?

例如 n=15,k=7n=15,k=7, 排列顺序为1, 10, 11, 12, 13, 14, 15, 2, 3, 4, 5, 6, 7, 8, 91,10,11,12,13,14,15,2,3,4,5,6,7,8,9 ; 那么第 77 个数字就是 1515.

那么,如果你处在 zyb 的场景下,你能解决这个问题吗?

Input
TT 组样例 ( T \le 100 )(T≤100)

两个整数 nn 和 kk ( 1 \le n \le 10^6 , 1 \le k \le n )(1≤n≤10
6
,1≤k≤n) , nn 和 kk 代表的含义如上文

Output
输出 1 - n1−n 之中字典序第 kk 小的数字

样例输入 复制
1
15 7
样例输出 复制
15

数学推理

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 1000001

int T,n,k;
struct zfc{
    int num;
    char s[7];
}a[maxn];
bool cmp(zfc x,zfc y){
    return strcmp(x.s,y.s)<0;
}
void init(){
	for(int i=1;i<maxn;i++){
        a[i].num=i;
        int t=i,e=0,m;
        while(t>0){
            a[i].s[e++]=t%10+'0';
            t/=10;
        }
        for(int j=0;j<e/2;j++){
            char ch=a[i].s[j];
            a[i].s[j]=a[i].s[e-j-1];
            a[i].s[e-j-1]=ch;
        }
    }
    sort(a+1,a+maxn,cmp);
}
int main()
{
	init();
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&k);
        int i;
        for(i=1;i<maxn;i++){
            if(a[i].num>n)continue;
            else k--;
            if(k==0)break;
        }
        printf("%d\n",a[i].num);
    }
    return 0;
}

Farmer John 有 nn 头奶牛.

某天奶牛想要数一数有多少头奶牛,以一种特殊的方式:

第一头奶牛为 11 号,第二头奶牛为 22 号,第三头奶牛之后,假如当前奶牛是第 nn 头,那么他的编号就是 22 倍的第 n-2n−2 头奶牛的编号加上第 n-1n−1 头奶牛的编号再加上自己当前的 nn 的三次方为自己的编号.

现在 Farmer John 想知道,第 nn 头奶牛的编号是多少,估计答案会很大,你只要输出答案对于 123456789123456789 取模.

Input
第一行输入一个 TT ,表示有 TT 组样例

接下来 TT 行,每行有一个正整数 nn , 表示有 nn 头奶牛 (n \ge 3)(n≥3)

其中,T=10^4,n\le 10^{18}T=10
4
,n≤10
18

Output
共 TT 行,每行一个正整数表示所求的答案

样例输入 复制
5
3
6
9
12
15
样例输出 复制
31
700
7486
64651
527023

矩阵快速幂

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

#define MOD 123456789LL
#define endl '\n'
#define MAX_N 6

template<typename T, int N = 1>
struct Matrix {
    Matrix(int f = 0) : n(sizeof(data[0]) / sizeof(data[0][0])) {
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                data[i][j] = T(0);
        if (f)
            for (int i = 0; i < n; data[i][i] = T(1), ++i) {}
    }

    Matrix operator * (const Matrix& other) const {
        Matrix<T, N> ret;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                for (int k = 0; k < n; k++)
                    ret.data[i][j] = (ret.data[i][j] + data[i][k] * other.data[k][j] % MOD) % MOD;
        return ret;
    }

    Matrix operator + (const Matrix& other) const {
        Matrix<T, N> ret;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                ret.data[i][j] = (data[i][j] + other.data[i][j]) % MOD;
        return ret;
    }

    Matrix& operator % (const LL mod) {
        return *this;
    }

    T data[N][N];
    int n;
};

template<typename T>
T mul(T a, LL n, LL mod)
{
    T ret(1);
    for (; n; n >>= 1) {
        ret = ret * (n & 1 ? a : T(1)) % mod;
        a = a * a % mod;
    }
    return ret;
}

const LL modulu[MAX_N][MAX_N] = {
    {1, 2, 1, 3, 3, 1},
    {1, 0, 0, 0, 0, 0},
    {0, 0, 1, 3, 3, 1},
    {0, 0, 0, 1, 2, 1},
    {0, 0, 0, 0, 1, 1},
    {0, 0, 0, 0, 0, 1}
};

int main()
{
    int T;
    cin >> T;
    for (LL n; T--; ) {
        cin >> n;
        n --;
        if (n <= 1) {
            cout << n +1<< endl;
            continue;
        }
        Matrix<LL, MAX_N> a;
        memcpy(a.data, modulu, sizeof(modulu));
        a = mul(a, n - 1, MOD);
        cout << (a.data[0][0] * 2 + a.data[0][1] * 1 + a.data[0][2] * 8 +
                a.data[0][3] * 4 + a.data[0][4] * 2 + a.data[0][5]) % MOD << endl;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值