A. 求出那个数
题目描述
求出一个最小的正整数 xxx,使得 xxx 每位数字的和恰好为 nnn。
输入格式
第一行一个正整数 TTT,代表测试数据的组数。
接下来 TTT 行每行一个正整数 nnn。
- 1≤T≤10001\le T\le10001≤T≤1000
- 0≤n<10000\le n<10000≤n<1000
输出格式
对于每组输入,输出最小的 xxx。
样例
输入 #1
2
5
14
输出 #1
5
59
- 尽量用 999,这样能使数位最小;
- nnn 不够 999 时,作为第一位输出;
- 若 nnn 为 000,特判输出 000。
#include <bits/stdc++.h>
//#define int long long
using namespace std;
void solve()
{
int n;
cin >> n;
if (n == 0)
{
printf("0\n");
return ;
}
string s = "";
while (n > 0) n -= 9,s += '9';
cout << n + 9 << s.substr(0,s.size()-1) << '\n';
}
signed main()
{
int TTT;
cin >> TTT;
// TTT = 1;
while (TTT--) solve();
return 0;
}
B. 田忌赛马·Easy
齐使者如梁,孙膑以刑徒阴见,说齐使。齐使以为奇,窃载与之齐。齐将田忌善而客待之。忌数与齐诸公子驰逐重射。孙子见其马足不甚相远,马有上、中、下辈。于是孙子谓田忌曰:“君弟重射,臣能令君胜。”田忌信然之,与王及诸公子逐射千金。及临质,孙子曰:“今以君之下驷与彼上驷,取君上驷与彼中驷,取君中驷与彼下驷。”既驰三辈毕,而田忌一不胜而再胜,卒得王千金。于是忌进孙子于威王。威王问兵法,遂以为师。
——「史记·孙子吴起列传第五」
在千年以前,孙膑就能靠着过人的智谋,通过巧妙地调整比赛的顺序,让三战皆背的田忌翻身成为两胜一败的赢家,也为自己赢得了别人的尊敬。在千年以后的今天,赛马依然是一项热门的娱乐活动,不过今天你要面对的却是更加困难的问题。
你和对手各自都有 NNN 匹马,要进行 NNN 场比赛。一匹马只能出场一次,同场比赛中速度快的马获得胜利。如果两匹马的速度一样的话,那么就是平局。你的对手会像齐王那样在第一场出速度最快的马,第二场出次快的马,…\dots…,第 NNN 场出速度最慢的马。
而你为了获胜,当然会按照某种策略安排你的 NNN 匹马的出场顺序。除此之外,你还可以决定比赛的时间,全部 NNN 场比赛都会在你决定的那一天举行。在比赛之前,你为了获胜会不辞辛苦的训练你的每一匹马;而你的对手自我感觉良好,不会训练他的马。每一匹马的素质不同,我们用 aia_iai 来表示你的第 iii 匹马的速度。每经过一天的训练,你的马的速度就会增加 111。
现在你拿到了对手的 NNN 匹马的资料,请你尽快计算训练的天数 MMM,以使得在第 M+1M+1M+1 天比赛的时候,你可以安排一个出场顺序使得你可以在全部的 NNN 场比赛中至少获胜 KKK 场。
输入格式
第一行给出一个正整数 TTT,代表测试数据的组数。
每组测试数据有 333 行,第一行有两个以空格分隔的数字 N,KN,KN,K,含义如题目种描述。
第二行有 NNN 个以空格分隔的正整数,第 iii 个数字代表你第 iii 匹马的速度 aia_iai。
第三行有 NNN 个以空格分隔的正整数,第 jjj 个数字代表你对手第 jjj 匹马的速度 cjc_jcj。
- 1≤T≤301\le T\le301≤T≤30
- 1≤K≤N≤1051\le K\le N\le 10^51≤K≤N≤105
- 0≤ai,cj≤1090\le a_i,c_j\le 10^90≤ai,cj≤109
输出格式
对于每组测试数据输出一个非负整数 MMM,代表在第 M+1M+1M+1 天举办的赛马比赛中你可以至少赢得 KKK 场。
如果不止有一个 MMM 满足条件,请输出最小的那个。
样例
输入 #1
2
4 2
3 1 2 4
0 4 3 2
1 1
10
10
输出 #1
0
1
- 第 M+1M+1M+1 天的时候,你的马匹的速度分别是 a1+M,a2+M,a3+M,…,an+Ma_1+M,a_2+M,a_3+M,\dots,a_n+Ma1+M,a2+M,a3+M,…,an+M,需要派出最好的 KKK 匹马,对上对手最差的 KKK 匹马;
- 假设我们最好的 KKK 匹马是 a1≤a2≤a3≤⋯≤aka_1\le a_2\le a_3\le\dots\le a_ka1≤a2≤a3≤⋯≤ak,对手最差的 KKK 匹马是 c1≤c2≤c3≤⋯≤ckc_1\le c_2\le c_3\le\dots\le c_kc1≤c2≤c3≤⋯≤ck;
- 我们要训练的天数就是:max(0,maxi(ci−ai+1))\max(0,\max_i(c_i-a_i+1))max(0,maxi(ci−ai+1))。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int a[100010],b[100010];
bool cmp(int a,int b) {return a > b;}
void solve()
{
int n,m,ans = 0;
cin >> n >> m;
for (int i = 1;i <= n;i++) cin >> a[i];
for (int i = 1;i <= n;i++) cin >> b[i];
sort(a+1,a+n+1,cmp);
sort(b+1,b+n+1);
for (int i = 1,j = m;i <= m;i++,j--) ans = max(ans,b[i]-a[j]+1);
cout << ans << '\n';
}
signed main()
{
int TTT;
cin >> TTT;
// TTT = 1;
while (TTT--) solve();
return 0;
}
C. 田忌赛马·Hard
齐使者如梁,孙膑以刑徒阴见,说齐使。齐使以为奇,窃载与之齐。齐将田忌善而客待之。忌数与齐诸公子驰逐重射。孙子见其马足不甚相远,马有上、中、下辈。于是孙子谓田忌曰:“君弟重射,臣能令君胜。”田忌信然之,与王及诸公子逐射千金。及临质,孙子曰:“今以君之下驷与彼上驷,取君上驷与彼中驷,取君中驷与彼下驷。”既驰三辈毕,而田忌一不胜而再胜,卒得王千金。于是忌进孙子于威王。威王问兵法,遂以为师。
——「史记·孙子吴起列传第五」
在千年以前,孙膑就能靠着过人的智谋,通过巧妙地调整比赛的顺序,让三战皆背的田忌翻身成为两胜一败的赢家,也为自己赢得了别人的尊敬。在千年以后的今天,赛马依然是一项热门的娱乐活动,不过今天你要面对的却是更加困难的问题。
你和对手各自都有 NNN 匹马,要进行 NNN 场比赛。一匹马只能出场一次,同场比赛中速度快的马获得胜利。如果两匹马的速度一样的话,那么就是平局。你的对手会像齐王那样在第一场出速度最快的马,第二场出次快的马,…\dots…,第 NNN 场出速度最慢的马。
而你为了获胜,当然会按照某种策略安排你的 NNN 匹马的出场顺序。除此之外,你还可以决定比赛的时间,全部 NNN 场比赛都会在你决定的那一天举行。在比赛之前,你为了获胜会不辞辛苦的训练你的每一匹马;而你的对手自我感觉良好,不会训练他的马。每一匹马的素质不同,我们用 aia_iai 来表示你的第 iii 匹马的速度。每经过一天的训练,你的第 iii 匹马的速度就会增加 bib_ibi。
现在你拿到了对手的 NNN 匹马的资料,请你尽快计算训练的天数 MMM,以使得在第 M+1M+1M+1 天比赛的时候,你可以安排一个出场顺序使得你可以在全部的 NNN 场比赛中至少获胜 KKK 场。
输入格式
第一行给出一个正整数 TTT,代表测试数据的组数。
每组测试数据有 333 行,第一行有两个以空格分隔的数字 N,KN,KN,K,含义如题目种描述。
第二行有 NNN 个以空格分隔的正整数,第 iii 个数字代表你第 iii 匹马的速度 aia_iai。
第三行有 NNN 个以空格分隔的正整数,第 jjj 个数字代表你对手第 jjj 匹马的速度 cjc_jcj。
- 1≤T≤1001\le T\le1001≤T≤100
- 1≤K≤N≤1041\le K\le N\le 10^41≤K≤N≤104
- 0≤ai,cj≤1080\le a_i,c_j\le 10^80≤ai,cj≤108
- 0≤bi≤1000\le b_i\le1000≤bi≤100
输出格式
对于每组测试数据输出一个非负整数 MMM,代表在第 M+1M+1M+1 天举办的赛马比赛中你可以至少赢得 KKK 场。
如果不止有一个 MMM 满足条件,请输出最小的那个。
如果没有任何 MMM 满足条件,请输出 -1。
样例
输入 #1
2
3 2
1 2
2 1
3 2
0
3
4
1 1
1 0
2
输出 #1
1
-1
- 第 M+1M+1M+1 天的时候,你的马匹的速度分别是 a1+M×b1,a2+M×b2,a3+M×b3,…,an+M×bna_1+M\times b_1,a_2+M\times b_2,a_3+M\times b_3,\dots,a_n+M\times b_na1+M×b1,a2+M×b2,a3+M×b3,…,an+M×bn;
- 不难发现,若训练了 DDD 天之后能赢 xxx 场,那么训练 D+1D+1D+1 天获胜的场数必然 ≥x\ge x≥x 场,所以我们可以二分枚举答案进行 checkcheckcheck;
- 尽量找实力相当的马来比。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m;
int b[100010];
struct node {int a,b;}a[100010];
bool cmp(int a,int b) {return a > b;}
bool check(int x) //训练 x 天
{
vector <int> now; //存储训练后马匹的速度
for (int i = 1;i <= n;i++) now.push_back(a[i].a+x*a[i].b);
sort(now.begin(),now.end(),cmp);
int j = 0,win = 0;
for (int i = 1;i <= n;i++) if (now[j] > b[i]) j++,win++;
return win >= m;
}
void bs(int l,int r)
{
int ans;
while (l <= r)
{
int mid = (l+r)/2;
if (check(mid)) ans = mid,r = mid-1;
else l = mid+1;
}
cout << ans << '\n';
}
void solve()
{
cin >> n >> m;
for (int i = 1;i <= n;i++) cin >> a[i].a >> a[i].b;
for (int i = 1;i <= n;i++) cin >> b[i];
sort(b+1,b+n+1,cmp);
int l = 0,r = 1e14;
if (!check(r)) cout << "-1\n"; //没有任何 M 满足条件
else bs(l,r);
}
signed main()
{
int TTT;
cin >> TTT;
// TTT = 1;
while (TTT--) solve();
return 0;
}
D. 放置方案数
现在有 kkk 种颜色的小球,每一种颜色的小球有若干个,有 nnn 个盒子排成一排,现在要往盒子里放球,每一个盒子需要放 111 个小球,要求相邻的盒子之间最多只有 222 个连续颜色相同的小球,问你有多少种方案,由于答案很大,请你对 109+710^9+7109+7 取模。
输入格式
第一行输入一个整数 TTT,代表有 TTT 组测试数据。
接下来 TTT 行,每行给出两个正整数 n,kn,kn,k,含义如题。
- 1≤T≤1031\le T\le10^31≤T≤103
- 1≤n,k≤1051\le n,k\le10^51≤n,k≤105
输出格式
对于每组测试数据,在一行中输出答案。
样例
输入 #1
2
1 1
3 2
输出 #1
1
6
- 最多可以有连续两个盒子放相同颜色的球,所以只需要考虑连续的三个盒子即可;
- 用 dpi0dp_{i_0}dpi0 表示第 iii 个盒子放和第 i−1i−1i−1 个盒子球颜色不同的球的方案数;
- 用 dpi1dp_{i_1}dpi1 表示第 iii 个盒子放和第 i−1i−1i−1 个盒子球颜色相同的球的方案数;
- dpi0=(dpi−10+dpi−11)×(k−1) % (109+7)dp_{i_0}=(dp_{{i-1}_0}+dp_{{i-1}_1})\times(k-1)\ \%\ (10^9+7)dpi0=(dpi−10+dpi−11)×(k−1) % (109+7);
- dpi1=dpi−10dp_{i_1}=dp_{{i-1}_0}dpi1=dpi−10。
- 最终的答案取 (dpn0+dpn1) % mod(dp_{n_0}+dp_{n_1})\ \%\ mod(dpn0+dpn1) % mod。
十年 OI 一场空,不开 long long 见祖宗!
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 1000000007;
int dp[100010][2];
void solve()
{
int n,m;
cin >> n >> m;
dp[1][0] = m;
dp[1][1] = 0;
for (int i = 2;i <= n;i++)
{
dp[i][0] = (dp[i-1][0]+dp[i-1][1]) * (m-1) % mod;
dp[i][1] = dp[i-1][0];
}
cout << (dp[n][0]+dp[n][1]) % mod << '\n';
}
signed main()
{
int TTT;
cin >> TTT;
// TTT = 1;
while (TTT--) solve();
return 0;
}
E. 密码破解
密码学是研究编制密码和破译密码的技术科学。研究密码变化的客观规律,常应用于编制密码以保守通信秘密的。从古代传递情报道现在电脑的通信一直扮演着一个十分重要的角色。相信你一定听说过「凯撒密码」,它属于是一种替换密码。一种凯撒密码的替换方式是 A→D,B→E,C→F,…,X→A,Y→B,Z→AA\to D,B\to E,C\to F,\dots,X\to A,Y\to B,Z\to AA→D,B→E,C→F,…,X→A,Y→B,Z→A。以数学的方式来说,我们让 A=0,B=1,C=2,…,Z=25A=0,B=1,C=2,\dots,Z=25A=0,B=1,C=2,…,Z=25,使用密钥 xxx 加密明文 aaa 得到的密文就是 :
Ex(a)=(a+x)mod26E_x(a)=(a+x) \operatorname{mod} 26Ex(a)=(a+x)mod26
以现在的计算机技术,凯撒密码是很容易破解的,即使我们不知道其中用来加密的密钥 xxx 的值,我们依然可以借助计算机强大的算力通过频率分析方法将其暴力解出。当密文长度足够大的情况下,可以先分析密文中每个字母出现的频率,然后将这一频率与正常情况下的该语言字母表中所有字母的出现频率做比较。例如在英语中,正常明文中字母 EEE 和 TTT 出现的频率特别高,而字母 QQQ 和 ZZZ 出现的频率特别低,而在法语中出现频率最高的字母是 EEE,最低的是 KKK 和 WWW。可以通过这一特点,分析密文字母出现的频率,可以估计出正确的密钥 xxx。
这里我们要介绍一种改良版的凯撒密码。现在你有一组密钥 x1,x2,x3,…,xlx_1,x_2,x_3,\dots,x_lx1,x2,x3,…,xl,要加密的信息 a1,a2,a3,…,ana_1,a_2,a_3,\dots,a_na1,a2,a3,…,an 得到密文 c1,c2,c3,…,cnc_1,c_2,c_3,\dots,c_nc1,c2,c3,…,cn。我们拿第一个密钥的字母 x1x_1x1 加密 a1a_1a1,拿第二个密钥的字母 x2x_2x2 加密 a2a_2a2,…\dots…。如果密钥用完了,我们就拿前面得到的密文来用,也就是拿 c1c_1c1 来加密 al+1a_{l+1}al+1。
ci={ai+ximod26i≤lai+ci−lmod26i>lc_i = \begin{cases} a_i+x_i \operatorname{mod} 26 & i \le l \\ a_i+c_{i-l} \operatorname{mod} 26 & i>l \end{cases}ci={ai+ximod26ai+ci−lmod26i≤li>l
现在,给你几组用同样的密钥加密的明文密文配对,请你写程序来破解出密钥。
输入格式
第一行一个正整数 TTT,代表测试数据的组数。
每组测试数据在第一行给出一个正整数 NNN,代表有几对明文密文配对。
接下来 NNN 行每行给出两个以空格分隔且只由大写字母组成的字符串 s1,s2s_1,s_2s1,s2,前面的代表明文,后面的是加密后的密文。
- 1≤T≤2001\le T\le2001≤T≤200
- 1≤N≤101\le N\le101≤N≤10
- 1≤∣s1∣=∣s2∣≤3001\le\lvert s_1\rvert=\lvert s_2\rvert\le3001≤∣s1∣=∣s2∣≤300
输出格式
对于每组输入在一行中输出一个字符串,代表能够将 NNN 组明文分别加密成对应密文的密钥。
如果有多种可能的密钥,请输出最短的那个。
如果没有任何符合的密钥,请输出 -。
样例
输入 #1
2
1
VAMRI VCYMK
2
CAKES DEOHW
CAKES DEOHW
输出 #1
ACM
BEE
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 20;
int n;
string s1[N],s2[N];
bool check(string str,string ming,string mi)
{
//ming -> 明文
//mi -> 密文
string s = "";
for (int i = 0;i < ming.size();i++)
{
char tmp = char(((ming[i]+str[i])%26) + 'A');
s += tmp;
str += tmp;
}
return s == mi;
}
string pre(string str[],int n)
{
sort(str,str+n,greater<string>()); //倒序排序
if (!check(str[0],s1[0],s2[0])) return "-"; //注意是字符串
for (int i = 1;i < n;i++)
if (str[0].substr(0,str[i].size()) != str[i] || !check(str[0],s1[i],s2[i]))
return "-";
return str[0];
}
void solve()
{
string str[N],s[N];
cin >> n;
for (int i = 0;i < n;i++)
{
cin >> s1[i] >> s2[i];
for (int j = 0;j < s1[i].size();j++)
str[i] += 'A' + ((s2[i][j]-s1[i][j]+26) % 26);
int id = 1;
for (int j = 0;j < str[i].size();j++)
{
if (str[i].substr(j) != s2[i].substr(0,str[i].size()-j))
id = j+1;
else
break;
}
s[i] = str[i].substr(0,id);
}
cout << pre(s,n) << '\n';
}
signed main()
{
int TTT;
cin >> TTT;
// TTT = 1;
while (TTT--) solve();
return 0;
}

791

被折叠的 条评论
为什么被折叠?



