洛谷刷题C语言:Herdle B、Non-Transitive Dice B、破译の论、小智的疑惑、三元组

记录洛谷刷题C语言QAQ


[USACO22JAN] Herdle B

题目描述

奶牛们发明了一种名为 Herdle 的新型解谜游戏,在牛界引起了轰动。

每天都会有一个新谜题发布供奶牛解决。游戏采用 3 × 3 3\times 3 3×3 方阵的形式表示农场的一块田地,田地的每个方格都由特定品种的奶牛占据。总共只有 26 26 26 种可能的品种,每一种由 A \text{A} A Z \text{Z} Z 中的不同大写字母标识。玩家不会被告知田地中的奶牛品种排列方式——游戏目标是通过一系列猜测确定它们。

每次猜测,奶牛们输入一个 3 × 3 3\times 3 3×3 的大写字母方阵,表示该田地可以用奶牛填充的可能方式。猜测的某些方格可能是正确的。这些方格以绿色高亮显示,让奶牛们知道这些是正确的。猜测的另一些方格可能填入了品种正确但位置错误的奶牛。这些以黄色高亮显示。

黄色高亮显示的方格的数量可以帮助指示某个品种的奶牛数量。 例如,假设猜测方阵包含 4 4 4 头品种 A \text{A} A 的奶牛,而答案方阵包含 2 2 2 只品种 A \text{A} A 的奶牛,其中没有正确位置上的 A \text{A} A (即,它们都不应该是绿色的)。 在这种情况下,猜测方阵中只有两个 A \text{A} A 应以黄色高亮显示。 更准确地说,如果猜测方阵中有 x x x 个特定品种的奶牛,并且 答案方阵中有 y ≤ x y \le x yx 头该品种奶牛(不包括位置正确而得到绿色高亮显示的奶牛),那么猜测方阵的 x x x 头奶牛中只有 y y y 头奶牛应该以黄色高亮显示。

给定正确答案的方阵和一个表示对该答案的猜测的方阵,请计算绿色和黄色高亮显示的方格的数量。

输入格式

输入的前 3 行给定了正确答案的方阵。以下 3 行表示对该答案的猜测。

输出格式

输出两行。输出的第一行包含应当以绿色高亮显示的方格的数量。输出的第二行包含应当以黄色高亮显示的方格的数量。

样例 #1

样例输入 #1

COW
SAY
MOO
WIN
THE
IOI

样例输出 #1

1
1

样例 #2

样例输入 #2

AAA
BBB
CCC
AYY
AAA
ZZZ

样例输出 #2

1
2

提示

【样例解释 1】

在这个例子中,最后一行中间的 O 是正确的,所以这个方格以绿色高亮显示。字母 W 位于错误的位置,所以它以黄色高亮显示。

【样例解释 2】

在这里,其中一个 A 位于正确的位置,所以它以绿色高亮显示。余下的 A 均不在正确位置上,由于答案方阵中有两个 A,所以有两个 A 应当以黄色高亮显示。

代码如下

#include<string.h>
#include<stdio.h>
#include<math.h>
#include <stdlib.h>


int min(int a,int b){
	if(a < b)
		return a;
	else
		return b;
}
char a[4][4], b[4][4];
int green, yellow, rall[27], gall[27];
int main() {
	char s; 
	for(int i = 1; i <= 3; i++)
	{
		for(int j = 1; j <= 3; j++)
		{
			scanf("%c",&a[i][j]);
		}
		s = getchar();
	}
		
			
	for(int i = 1; i <= 3; i++)
	{
		for(int j = 1; j <= 3; j++)
		{
			scanf("%c",&b[i][j]);
		}
		s = getchar();
	}
	
	for(int i = 1; i <= 3; i++)
		for(int j = 1; j <= 3; j++)
			if(a[i][j] == b[i][j]) green++;
			else {
				rall[a[i][j] - 'A' + 1]++;
				gall[b[i][j] - 'A' + 1]++;
			}
	for(int i = 1; i <= 26; i++) 
		yellow += min(rall[i], gall[i]);
	printf("%d\n%d\n", green, yellow);
	return 0;
}

[USACO22JAN] Non-Transitive Dice B

题目描述

为了消磨牛棚里的时光,奶牛们喜欢玩简单的骰子游戏。其中一种游戏使用两个骰子 X 和 Y 进行。两个骰子均被投掷,获胜的骰子是显示的数字较大的骰子。如果两者显示相同的数字,则重新投掷(只要持续打平,骰子可能会被重新投掷多次)。我们称骰子 X 击败骰子 Y,如果骰子 X 比骰子 Y 更有可能赢得这局游戏。

考虑以下的 4 4 4 面骰子:

骰子 A 在各面上有数字 4 4 4 5 5 5 6 6 6 7 7 7

骰子 B 在各面上有数字 2 2 2 4 4 4 5 5 5 10 10 10

骰子 C 在各面上有数字 1 1 1 4 4 4 8 8 8 9 9 9

这些骰子满足一个相当奇妙的性质:A 击败 B,B 击败 C,并且 C 也击败 A。特别地,三个骰子都不是「最佳的」,可以击败其他两个。在这种情况下,当没有两个骰子打平,也没有一个骰子是最佳的,我们称这三个骰子的集合为「非传递的」。在非传递的三个骰子的集合中,每个骰子击败一个其他骰子,并输给另一个其他骰子。

给定两个 4 4 4 面骰子 A 和 B 各面上的数字,请帮助奶牛们求出是否有方法为第三个骰子 C 的各面分配数字,使得这个骰子的集合是非传递的。所有骰子面上的数字必须是 1 1 1 10 10 10 的整数。

输入格式

每个测试用例包含多个独立的子测试用例,必须全部回答正确才能通过整个测试用例。输入的第一行包含 T T T 1 ≤ T ≤ 10 1\le T\le 10 1T10),为你需要求解的子测试用例的数量。

以下 T T T 行,每行描述了一个子测试用例,包含 8 8 8 个整数:骰子 A 的 4 4 4 面上的整数,以及骰子 B 的 4 4 4 面上的整数。所有的数均在 1 1 1 10 10 10 之间,不一定排序。可能同一个数会出现多次,即使在同一个骰子上也可能出现多个相同的数。

输出格式

输出 T T T 行。如果有可能为骰子 C 分配数字使得第 k k k 个测试用例成为一个非传递的骰子集合,则第 k k k 行输出 yes,否则输出 no

样例 #1

样例输入 #1

3
4 5 6 7 2 4 5 10
2 2 2 2 1 1 1 1
1 1 1 1 2 2 2 2

样例输出 #1

yes
no
no

提示

【样例解释】

第一个子测试用例对应题目中的例子。在第二个子测试用例中,不存在骰子 C 可以使得这个骰子集合是非传递的。同理第三个子测试用例的答案也是 no

代码如下

#include<string.h>
#include<stdio.h>
#include<math.h>
#include <stdlib.h>


int T;
int a[5];
int b[5];
int c[5];
int main(){
	scanf("%d",&T);
	while(T--){
		for(int i=1;i<=4;i++) scanf("%d",&a[i]);
		for(int i=1;i<=4;i++) scanf("%d",&b[i]);
		int win=0,lose=0;
		for(int i=1;i<=4;i++)
			for(int j=1;j<=4;j++)
				if(a[i]>b[j]) win++;
				else if(a[i]<b[j]) lose++;
		if(win==lose){ //处理打平
			printf("no\n");
			continue;
		}
		int flag=0;
		for(int i = 1;i < 5;i++)
		{
			for(int j = i +1;j < 5;j++)
			{
				if(a[i] < a[j])
				{
					a[i] = a[i] + a[j];
					a[j] = a[i] - a[j];
					a[i] = a[i] - a[j];
				}
				if(b[i] < b[j])
				{
					b[i] = b[i] + b[j];
					b[j] = b[i] - b[j];
					b[i] = b[i] - b[j];
				}
			}
		}
		if(win<lose) 
		{
			a[4] = a[4] + b[4];
			b[4] = a[4] - b[4];
			a[4] = a[4] - b[4];
			a[1] = a[1] + b[1];
			b[1] = a[1] - b[1];
			a[1] = a[1] - b[1];
			a[2] = a[2] + b[2];
			b[2] = a[2] - b[2];
			a[2] = a[2] - b[2];
			a[3] = a[3] + b[3];
			b[3] = a[3] - b[3];
			a[3] = a[3] - b[3];
		}
		for(c[1]=1;c[1]<=10;c[1]++){
			for(c[2]=c[1];c[2]<=10;c[2]++){
				for(c[3]=c[2];c[3]<=10;c[3]++){
					for(c[4]=c[3];c[4]<=10;c[4]++){
						int f1=1;
						int w1=0,l1=0,w2=0,l2=0;
						for(int i=1;i<=4;i++)
							for(int j=1;j<=4;j++){
								if(a[i]>c[j]) w1++;
								else if(a[i]<c[j]) l1++;
								if(b[i]>c[j]) w2++;
								else if(b[i]<c[j]) l2++;
							}
						if(w1<l1&&w2>l2){
							printf("yes\n");
							flag=1;
							break;
						}
					}
					if(flag) break;
				}
				if(flag) break;
			}
			if(flag) break;
		}
		if(!flag) printf("no\n");
	}
	return 0;
}

「PMOI-5」破译の论

题目背景

2077 年,穿越的 Lanuxhem 为与 2021 年的 Silver187 联系,发明了一种图形转数字的密码。

题目描述

lhm 现在有一个边长为 1 1 1 的正方形,现在要进行 k k k 次分割,每次分割需要把位于图形中右下角的矩形继续分割成 n × n n \times n n×n 的矩形。分割完成后所有矩形的个数即为破译后的答案。lhm 需要聪明的你帮助他解决这个问题。

注:由于题面形容比较困难,请移步至样例解释便于理解题意。

输入格式

输入数据共一行。
一行两个整数 n , k n,k n,k,含义如题目所示。

输出格式

输出格式共一行。
一行一个整数,表示最终答案。
由于答案可能过大,请把答案取模 998244353 998244353 998244353 后输出。

样例 #1

样例输入 #1

2 2

样例输出 #1

7

样例 #2

样例输入 #2

5 3

样例输出 #2

73

提示

样例解释

对于样例 #1,进行 2 2 2 次分割,每次将右下角矩形分割为 2 × 2 2\times 2 2×2 的矩形。

第一次分割,由于只有一个矩形,所以右下角矩形即为此矩形。分割前后如下:

变为

接下来进行第二次分割,将右下角矩形进行分割,分割为如下图形:

此图形包含 7 7 7 个矩形,因此答案为 7 7 7

数据规模与约定

对于 10 % 10\% 10% 的数据, k = 1 k=1 k=1
对于另 20 % 20\% 20% 的数据, 1 ≤ n , k ≤ 10 1 \leq n,k \leq 10 1n,k10
对于 100 % 100\% 100% 的数据, 1 ≤ n , k ≤ 1 0 9 1 \leq n,k \leq 10^9 1n,k109


2022.7.10 2022.7.10 2022.7.10:新增加一组 Hack \text{Hack} Hack 数据。

代码如下

#include<string.h>
#include<stdio.h>
#include<math.h>
#include <stdlib.h>

 long long ksc(long long a, long long b, long long c) {
    if (! b) return 0;
    long long ans = ksc(a, b >> 1, c);
    ans = (ans + ans) % c;
    if (b & 1) ans = (ans + a) % c;
    return ans;
}

signed main() {
    long long n, k;
    scanf ("%lld%lld", &n, &k);
    long long ans = 1 + ksc(n * n - 1, k, 998244353);
    ans = ans % 998244353;
    printf ("%lld", ans);
    return 0;
}

小智的疑惑

题目描述

传智专修学院给了小智一个仅包含小写字母的字符串 s s s,他想知道,里面出现了多少次子串 chuanzhi 呢。

我们称一个字符串 t t t s s s 的子串,当且仅当将 s s s 的开头若干个(可以为 0 个)连续字符和结尾若干个(可以为 0 个)连续字符删去后,剩下的字符串和 t t t 相同。例如,我们称 ababc 的子串,但 ac 不是 abc 的子串。

输入格式

输入只有一行一个字符串,表示字符串 s s s

输出格式

输出一行一个整数表示答案。

样例 #1

样例输入 #1

welcometochuanzhicupchuanzhi

样例输出 #1

2

提示

数据规模与约定

对于全部的测试点,保证 1 ≤ ∣ s ∣ ≤ 4 × 1 0 5 1 \leq |s| \leq 4 \times 10^5 1s4×105 ∣ s ∣ |s| s 表示 s s s 的长度,且 s s s 中只有小写字母。

代码如下

#include<string.h>
#include<stdio.h>
#include<math.h>
#include <stdlib.h>

int main(){
	char ch[400005];
	scanf("%s",ch+1);
	int len=strlen(ch+1);//长度 
	int ans=0;//计数器 
	for(int i=1;i<=len;i++){
		if(ch[i]=='c'&&ch[i+1]=='h'&&ch[i+2]=='u'&&ch[i+3]=='a'&&ch[i+4]=='n'&&ch[i+5]=='z'&&ch[i+6]=='h'&&ch[i+7]=='i'){//判断是否符合题意 
			ans++;
		}
	}
	printf("%d",ans);
} 

三元组

题目描述

给定一个长度为 n n n 的数列 a a a,对于一个有序整数三元组 ( i , j , k ) (i, j, k) (i,j,k),若其满足 1 ≤ i ≤ j ≤ k ≤ n 1 \leq i \leq j \leq k \leq n 1ijkn 并且 a i + a j = a k a_i +a_j = a_k ai+aj=ak,则我们称这个三元组是「传智的」。

现在请你计算,有多少有序整数三元组是传智的。

输入格式

本题单测试点内有多组测试数据

输入的第一行是一个整数 T T T,表示数据组数。

对于每组数据:

第一行是一个整数,表示数列的长度 n n n
第二行有 n n n 个整数,第 i i i 个整数表示 a i a_i ai

输出格式

对于每组数据,输出一行一个整数表示答案。

样例 #1

样例输入 #1

2
3
1 2 3
5
1 2 3 4 5

样例输出 #1

2
6

提示

样例 1 解释

对于第一组数据,因为 a 1 + a 1 = a 2 a_1 + a_1 = a_2 a1+a1=a2 a 1 + a 2 = a 3 a_1 + a_2 = a_3 a1+a2=a3,故共 ( 1 , 1 , 2 ) (1, 1, 2) (1,1,2) ( 1 , 2 , 3 ) (1, 2, 3) (1,2,3) 两个三元组。
对于第二组数据六个三元组分别是:

  • ( 1 , 1 , 2 ) (1, 1, 2) (1,1,2)
  • ( 1 , 2 , 3 ) (1, 2, 3) (1,2,3)
  • ( 1 , 3 , 4 ) (1, 3, 4) (1,3,4)
  • ( 1 , 4 , 5 ) (1, 4, 5) (1,4,5)
  • ( 2 , 2 , 4 ) (2, 2, 4) (2,2,4)
  • ( 2 , 3 , 5 ) (2, 3, 5) (2,3,5)

数据规模与约定

对于全部测试点,保证 1 ≤ T ≤ 100 1 \leq T \leq 100 1T100 1 ≤ n , a i ≤ 100 1 \leq n , a_i \leq 100 1n,ai100,且各个测试点的 n n n 之和不超过 100 100 100,即 ∑ n ≤ 100 \sum n \leq 100 n100

代码如下

#include<string.h>
#include<stdio.h>
#include<math.h>
#include <stdlib.h>

int n,a[105];
int main()
{
	scanf("%d",&n);
    while(n--){
        int m,sum=0;
        scanf("%d",&m);
        for(int i = 1;i <= m;i++)
			scanf("%d",&a[i]);
        for(int i = 1;i <= m;i++)
            for(int j = i;j <= m;j++)
                for(int k = j;k <= m;k++)
                    if(a[i]+a[j]==a[k])
                        sum++;
        printf("%d\n",sum);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值