2022-03-02每日刷题打卡
代码源——div2每日一题
Alice的德州扑克 - 题目 - Daimayuan Online Judge
德州扑克是目前世界上最流行的扑克游戏,全世界有众多相关的比赛,例如是 WSOP,WPT,EPT等,也让这款游戏的玩法变得层出不穷,丰富多变。 不要被简单的游戏规则而误导,复杂多变的比赛状况,让这款游戏在高水平的竞技中会变得非常复杂,这也让人们为德州扑克给出了这样一句评价 ”用一刻就能学会,但要用一生才能掌握” 。
现在我们并不在乎游戏规则是什么,因为 Alice 是一个德州扑克高手,他对于德州扑克的规则烂熟于心,不过他每次都记不得牌型的大小关系,他知道你是一个编程高手,所以他想让你帮他写一个程序:输入五张牌的大小和花色,输出这五张牌能组成的最大牌型.你能帮帮他吗?
为了降低你的编程难度,我们规定:
- 输入的牌都是来源于同一副扑克牌.
- 输入的牌的点数都是非递减的.
- 所有花色没有大小之分.
下面给出各牌型,(从大到小)
- 皇家同花顺(ROYAL FLUSH):五张顺连的牌(点数连续单调递增),且最大的一张牌是A(Ace),并且五张牌的花色相同
- 同花顺(STRAIGHT FLUSH):五张顺连的牌(点数连续单调递增),不规定最大的一张牌是A(Ace),并且五张牌的花色相同
- 四条(FOUR OF A KIND):至少四张牌的点数相同
- 葫芦(FULL HOUSE):至少三张牌的点数相同,并且除此之外还有两张牌的点数相同
- 同花(FLUSH):五张牌的花色都相同
- 顺子(STRAIGHT):五张顺连的牌(点数连续单调递增),不要求五张牌的花色相同
- 特别注意:由于 Alice 是个谨慎的人,所以比 三条(THREE OF A KIND) (包括三条) 小的牌型 Alice 不在乎他们的大小关系,你只需要告诉 Alice 弃牌就行
输入格式
输入两行,每行五个数字,第一行的第 ii 个字符表示第 ii 张扑克的点数,
第二行的第 ii 个数字表示第 ii 张扑克花色。(保证输入的牌的点数是非递减的,且所有输入均合法)
点数和对应输入的数字:
- 2−102−10 对应 2 - 10
- J(Jack)J(Jack) 对应 11
- Q(Queen)Q(Queen) 对应 12
- K(King)K(King) 对应 13
- A(Ace)A(Ace) 对应 14
花色和对应输入的数字:
- 黑桃 (Spades) 对应 1
- 方片 (Diamonds) 对应 2
- 红桃 (Hearts) 对应 3
- 梅花 (Clubs) 对应 4
输出格式
输出这五张牌能组成的最大牌型.
- 如果最大是皇家同花顺输出 “ROYAL FLUSH”
- 如果最大是同花顺输出 “STRAIGHT FLUSH”
- 如果最大是四条输出 “FOUR OF A KIND”
- 如果最大是葫芦输出 “FULL HOUSE”
- 如果最大是同花输出 “FLUSH”
- 如果最大是顺子输出 “STRAIGHT”
- 如果最大的牌型小于等于三条输出"FOLD",劝 Alice 弃牌
- 输出不包括引号
样例输入1
10 11 12 13 14
1 1 1 1 1
样例输出1
ROYAL FLUSH
模拟题嗷模拟题,没啥特别的知识
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>
typedef long long ll;
const int N = 100005;
int main()
{
bool two = false, three = false, four = false, flush = true, straight = true, A = false;
int ans;
map<int, int>mymap;
for (int i = 0; i < 5; i++)
{
int num;
cin >> num;
if (i == 0)ans = num;
else if (ans + 1 != num)
{
straight = false;
}
else ans = num;
mymap[num]++;
if (i == 4 && num == 14)A = true;
}
for (auto i : mymap)
if (i.second == 2)two = true;
else if (i.second == 3)three = true;
else if (i.second == 4)four = true;
for (int i = 0; i < 5; i++)
{
int flu;
cin >> flu;
if (i == 0)ans = flu;
else if (ans != flu)flush = false;
}
if (flush && straight && A)cout << "ROYAL FLUSH" << endl;
else if (flush && straight)cout << "STRAIGHT FLUSH" << endl;
else if (four)cout << "FOUR OF A KIND" << endl;
else if (two && three)cout << "FULL HOUSE" << endl;
else if (flush)cout << "FLUSH" << endl;
else if (straight)cout << "STRAIGHT" << endl;
else cout << "FOLD" << endl;
return 0;
}
选数 - 题目 - Daimayuan Online Judge
给定n个正整数a1,a2,…,an 。 要求从其中选出若干数字, 使得这些数字的和mod n=0(对于每个下标最多只能选择一次)。
输入格式
第一行一个数字n, 表示数字个数。
接下来一行 n 个整数 a1,a2,…,an , 表示这n个数。
输出格式
第一行输出MM, 表示选择的数的个数。
第二行输出MM个正整数, 用空格隔开, 表示这些数字的下标。
如果有多种方案满足要求, 输出任意一种。
如果没有满足要求的方案 输出 −1−1。
样例输入
4
1 3 2 5
样例输出
2
2 4
样例解释
3+5=8, 8 mod 4=0
数据规模
所有数据保证 1≤n≤100000,1≤ai≤10^9
这题用前缀和的思路来解。准备一个前缀和数组f,f[i]记录的是前i个元素的和,再%n。如果f[i]等于0,那就,满足题目要求,直接输出前i个元素即可。如果算完前缀和后,整个数组里都没有等于0的情况,此时就要用到抽屉问题了。首先我们知道,我们是对n取模,这样得到的数范围应该是0n-1,此时我们得到的数里没有0,那么范围就是1n-1,一共是n-2个数,但我们通过计算前缀和得到的元素个数应该是n,但此时所有元素的数据范围是1~n-1,这就说明了,至少有两个数会相等,既然相等,这两数的差值就是0,这就说明这两个数中间隔着的数,总和%n后等于0,所以这两个数之间相隔的数是满足条件的,输出即可。
例如:1 2 3 5这四个元素,计算前缀和并%4后得到的是1 3 2 3,相同的是第2个元素和第4个元素,那满足条件的就是第三到第四给元素,即3 和 5,3+5=8%4=0。
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>
typedef long long ll;
const int N = 100005;
ll f[N];
int main()
{
unordered_map<ll, vector<int>>mymap;
int n, ans = -1, res = 0;
cin >> n;
vector<ll>v(n+1);
for (int i = 1; i <= n; i++)
{
cin >> v[i], f[i] = (f[i - 1] + v[i]) % n;
if (f[i] == 0)ans = i;
mymap[f[i]].push_back(i);
if (mymap[f[i]].size() >= 2)res = f[i];
}
if (ans != -1)
{
cout << ans << endl;
for (int i = 1; i <= ans; i++)cout << i << " ";
return 0;
}
int a = mymap[res][0], b = mymap[res][1];
cout << b - a << endl;
for (int i = a + 1; i <= b; i++)
cout << i << " ";
return 0;
}
力扣——每日一题
564. 寻找最近的回文数
给定一个表示整数的字符串 n ,返回与它最近的回文整数(不包括自身)。如果不止一个,返回较小的那个。
“最近的”定义为两个整数差的绝对值最小。
示例 1:
输入: n = “123”
输出: “121”
提示:
1 <= n.length <= 18
n
只由数字组成n
不含前导 0n
代表在[1, 1018 - 1]
范围内的整数
有五种方式来构造回文整数:
1是取前一半的数镜像填到后面去,例:12345,把前面的123填到后面就是12321。
2是取前一半的数,+1后填到后面去,例:12345,把123+1后变成124,再填就是12421。
3是取前一半的数,-1后填到后面去,例:12345,123-1后是122,再填就是12221。
4是取上限,因为我们把中间数+1后(第二种方法)有可能会使数位加1,比如9999,会变成100001,但实际应该是10001,我们提前准备一个上限的数,取数的长度len,根据len构造一个10的len次方的数,再+1。比如9999长度是4,那就是10^4+1=10001。
5是取下线,我们把中间数-1后(第三种方法)有可能会使数位减一,比如1001,会变成99,但实际是999,我们提前准备一个下限的数,取数的长度len,根据len构造一个10的len-1次方的数,再-1。比如1001长度是4,那就是10^3-1=999。
最后我们依次拿这五个数和n进行比较,取之间差值最小的那一个,如果差值相同,取数较小的那一个,注意这五个数不能有和n相同的,而且根据题目的范围,我们全程的数应该开longlong。
class Solution {
public:
typedef long long ll;
ll get_back(string str,int ans,int len)
{
int n=len%2==0?len/2:len/2+1;
string s=str.substr(0,n);
ll num=stol(s);
num+=ans;
str=to_string(num);
n=str.size();
if(len%2)n--;
for(int i=n-1;i>=0;i--)str+=str[i];
return stol(str);
}
string nearestPalindromic(string n) {
vector<ll>v;
int len=n.size();
v.push_back(pow(10,len)+1);
v.push_back(pow(10,len-1)-1);
v.push_back(get_back(n,1,len));
v.push_back(get_back(n,0,len));
v.push_back(get_back(n,-1,len));
ll res=1e18,num=stol(n),ans=1e18;
for(int i=0;i<5;i++)
{
ll val=abs(v[i]-num);
if(res>=val&&v[i]!=num)
{
if(res==val) ans=min(ans,v[i]);
else ans=v[i];
res=val;
}
}
return to_string(ans);
}
};
一本通——动态规划
1297:公共子序列
【题目描述】
我们称序列Z=<z1,z2,…,zk>是序列X=<x1,x2,…,xm>的子序列当且仅当存在严格上升的序列<i1,i2,…,ik>,使得对j=1,2,…,k,有xij=zj。比如Z=<a,b,f,c> 是X=<a,b,c,f,b,c>的子序列。
现在给出两个序列X和Y,你的任务是找到X和Y的最大公共子序列,也就是说要找到一个最长的序列Z,使得Z既是X的子序列也是Y的子序列。
【输入】
输入包括多组测试数据。每组数据包括一行,给出两个长度不超过200的字符串,表示两个序列。两个字符串之间由若干个空格隔开。
【输出】
对每组输入数据,输出一行,给出两个序列的最大公共子序列的长度。
【输入样例】
abcfbc abfcab
programming contest
abcd mnp
【输出样例】
4
2
0
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>
typedef long long ll;
const int N = 1005;
int f[N][N];
int main()
{
string str1, str2;
while (cin >> str1 >> str2)
{
int n = str1.size(), m = str2.size(), res = 0;
for(int i=1;i<=n;i++)
for (int j = 1; j <= m; j++)
{
if (str1[i - 1] == str2[j - 1])
f[i][j] = f[i - 1][j - 1] + 1;
else
f[i][j] = max(f[i][j - 1], f[i - 1][j]);
res = max(f[i][j], res);
}
cout << res << endl;
}
return 0;
}
1298:计算字符串距离
【题目描述】
对于两个不同的字符串,我们有一套操作方法来把他们变得相同,具体方法为:
修改一个字符(如把“a”替换为“b”);
删除一个字符(如把“traveling”变为“travelng”)。
比如对于“abcdefg”和“abcdef”两个字符串来说,我们认为可以通过增加/减少一个“g”的方式来达到目的。无论增加还是减少“g”,我们都仅仅需要一次操作。我们把这个操作所需要的次数定义为两个字符串的距离。
给定任意两个字符串,写出一个算法来计算出他们的距离。
【输入】
第一行有一个整数n。表示测试数据的组数。
接下来共n行,每行两个字符串,用空格隔开,表示要计算距离的两个字符串。
字符串长度不超过1000。
【输出】
针对每一组测试数据输出一个整数,值为两个字符串的距离。
【输入样例】
3
abcdefg abcdef
ab ab
mnklj jlknm
【输出样例】
1
0
4
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>
typedef long long ll;
const int N = 1005;
int f[N][N];
int main()
{
int len;
cin >> len;
string str1, str2;
while (len--)
{
cin >> str1 >> str2;
int n = str1.size(), m = str2.size(), res = 0;
for (int i = 0; i <= n; i++)f[i][0] = i;
for (int i = 0; i <= m; i++)f[0][i] = i;
for(int i=1;i<=n;i++)
for (int j = 1; j <= m; j++)
{
f[i][j] = min(f[i - 1][j], f[i][j - 1]) + 1;
f[i][j] = min(f[i][j], str1[i - 1] == str2[j - 1] ? f[i - 1][j - 1] : f[i - 1][j - 1] + 1);
}
cout << f[n][m] << endl;
}
return 0;
}