PAT 520 钻石争霸赛真题(2020-05-20)题解 #后三题
7-6 随机输一次 (20分)
现要求你编写一个控制赢面的程序,根据对方的出招,给出对应的赢招。但是!为了不让对方意识到你在控制结果,你需要隔 K 次输一次,其中 K 是系统设定的随机数。
输入格式:
输入首先在第一行给出正整数 N(≤10),随后给出 N 个系统产生的不超过 10 的正随机数 { K1,K2,⋯,KN },数字间以空格分隔。这意味着第 i(i=0,1,⋯,N−1)次输局之后应该隔 Ki+1 次再让下一个输局。如果对方出招太多,则随机数按顺序循环使用。例如在样例中,系统产生了 3 个随机数 {2, 4, 1},则你需要:赢 2 次,输 1 次;赢 4 次,输 1 次;赢 1 次,输 1 次;然后再次回到第 1 个随机数,赢 2 次,输 1 次。
之后每行给出对方的一次出招:“ChuiZi”代表“锤子”、“JianDao”代表“剪刀”、“Bu”代表“布”。“End”代表输入结束,这一行不要作为出招处理。输入保证对方至少出了一招。
输出格式:
对每一个输入的出招,按要求输出赢或输局的招式。每招占一行。
输入样例:
3 2 4 1
ChuiZi
JianDao
Bu
JianDao
Bu
ChuiZi
ChuiZi
ChuiZi
JianDao
Bu
JianDao
Bu
ChuiZi
End
输出样例:
Bu
ChuiZi
ChuiZi
ChuiZi
JianDao
Bu
Bu
JianDao
ChuiZi
ChuiZi
ChuiZi
JianDao
JianDao
思路
判断flag是否等于a[cnt%N],这样模拟的思路最简单。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=1e6+10;
int a[100];
void win(string x) {
if (x == "ChuiZi") cout << "Bu\n";
else if (x == "JianDao") cout << "ChuiZi\n";
else cout << "JianDao\n";
}
void lose(string x) {
if (x == "ChuiZi") cout << "JianDao\n";
else if (x == "JianDao") cout << "Bu\n";
else cout << "ChuiZi\n";
}
int main() {
// freopen("in.txt","r",stdin);
int N;
cin>>N;
for (int i=0;i<N;i++) {
cin>>a[i];
}
int flag=0,cnt=0;
string s;
while (cin>>s&&s!="End") {
if (flag==a[cnt%N]) {
lose(s);
flag=0;
cnt++;
} else {
win(s);
flag++;
}
}
return 0;
}
7-7 阶乘的非零尾数 (20分)
7-7 阶乘的非零尾数 (20分)
“求 N 阶乘末尾的第一个非零数字”是一道常见的企业笔试题。这里我们略微做个变化,求 N 阶乘末尾的第一个非零 K 位数,同时输出末尾有多少个零。
输入格式:
输入给出一个不超过 107 的正整数 N 和要求输出的位数 0<K<10。
输出格式:
在一行中输出 N 阶乘末尾的第一个非零 K 位数(注意前导零也要输出)、以及末尾 0 的个数,其间以 1 个空格分隔。
输入样例:
18 5
输出样例:
05728 3
思路
先把所有的5和2剔除,然后把漏掉的5 或 2再乘上去。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const long long MAXN = 1e6 + 10;
int main()
{
// freopen("in.txt", "r", stdin);
long long N, K;
cin >> N >> K;
long long base = 1;
for (long long i = 0; i < K; i++)
{
base *= 10;
}
long long cnt2 = 0, cnt5 = 0, num = 1;
for (long long i = 1; i <= N; i++)
{
long long m = i;
while (m % 5 == 0) { m /= 5; cnt5++; }
while (m % 2 == 0) { m/=2; cnt2++; }
num*=m;
num%=base;
}
long long cnt=min(cnt2,cnt5);
for (long long i=0;i<cnt2-cnt;i++) { num=2ll*num%base; }
for (long long i=0;i<cnt5-cnt;i++) { num=5ll*num%base; }
long long tmp=num,bits=0;
while (tmp) {
bits++;
tmp/=10;
}
for (long long i=0;i<K-bits;i++) { cout<<"0"; }
cout<<num<<" "<<cnt<<endl;
return 0;
}
7-8 三足鼎立 (25分)
当三个国家中的任何两国实力之和都大于第三国的时候,这三个国家互相结盟就呈“三足鼎立”之势,这种状态是最稳定的。
现已知本国的实力值,又给出 n 个其他国家的实力值。我们需要从这 n 个国家中找 2 个结盟,以成三足鼎立。有多少种选择呢?
输入格式:
输入首先在第一行给出 2 个正整数 n(2≤n≤105)和 P(≤109),分别为其他国家的个数、以及本国的实力值。随后一行给出 n 个正整数,表示n 个其他国家的实力值。每个数值不超过 109,数字间以空格分隔。
输出格式:
在一行中输出本国结盟选择的个数。
输入样例:
7 30
42 16 2 51 92 27 35
输出样例:
9
样例解释:
能联合的另外 2 个国家的 9 种选择分别为:
{16, 27}, {16, 35}, {16, 42}, {27, 35}, {27, 42}, {27, 51}, {35, 42}, {35, 51}, {42, 51}。
思路
- 如果p不是最大,则满足条件的是小于a[i]+p的数
- 如果p是最大 , 则满足条件的是大于p-a[i]的数
用lower_bound是为了多计入一位,这样避免x==y,x-y=0。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=1e5+10;
long long a[MAXN];
int main() {
// freopen("in.txt","r",stdin);
long long N,P;
cin>>N>>P;
for (int i=0;i<N;i++) {
cin>>a[i];
}
long long ans=0;
sort(a,a+N);
for (int i=0;i<N;i++) {
long long x=lower_bound(a+i+1,a+N,a[i]+P)-a;
long long y=upper_bound(a+i+1,a+N,P-a[i])-a;
ans+=max(0ll,x-y);
}
cout<<ans<<endl;
return 0;
}