A
给n个英文字母,你可以组成最长的回文串长度是多少?
现在,请你利用程序帮助算出他能构成的最长回文串的长度是多少。
Input
第一行包含一个正整数 T(1≤T≤10),代表有 T 组数据。
对于每一组数据:
第一行包含一个正整数 n(1≤n≤10^5),表示字母数量。
接下来的一行包含 n个由空格分隔的英文字母 ci,表示第 i 个字母。
Output
对于每组数据,输出一行表示能构成的最长回文串的长度。
Sample 1
Inputcopy | Outputcopy |
---|---|
2 2 A a 3 v a a | 1 3 |
Note
"回文串"是一个正读和反读都一样的字符串,比如 "level"或者 "noon"等等就是回文串。
在第一组数据中,我们可以选出产物 "a" 排列成 "a",长度为1。
在第二组数据中,我们可以选出所有产物排列成 "ava",长度为3。
思路:每两个相同的字母能组成一对回文串,单个的能放在中间算一个。
注意:若一个字母出现了偶数次,则都能构成回文串,而奇数次的字母要分出现一次或者出现三次及以上,若只出现一次则输出偶数字母出现的次数加上1,若出现三次及以上需要加上奇数-1。
代码
#include<bits/stdc++.h>
void solve();
using namespace std;
int main(){
int T;
cin>>T;
while(T--){
solve();
}
}
void solve(){
int n,i,sum=0,b[80]={0},q=0,w=0;
char a[100005];
cin>>n;
if(n==1){
cout<<1<<endl;
return;
}
for(i=0;i<n-1;i++){
cin>>a[i];
b[a[i]-'A']++;
getchar();
}
cin>>a[i];
b[a[i]-'A']++;
for(i=0;i<80;i++){
if(b[i]%2==0&&b[i]!=0){
q+=(b[i]/2);
}
else if(b[i]%2!=0&&b[i]!=0){
q+=(b[i]-1)/2;
w++;
}
}
if(w!=0){
cout<<2*q+1<<endl;
}
else{
cout<<2*q<<endl;
}
return;
}
B
给一个数组,问你可以求出多少个总和为7777的子区间。
Input
第一行包含一个正整数 T(1≤T≤10),代表有 T 组数据。
对于每一组数据:
第一行为 n,表示有 n(1≤n≤10^5)个整数。
第二行有 n 个整数 ai(1≤ai≤5000)。
Output
对于每组数据,输出一个整数,代表有多少个不同的区间和为 7777。
Sample 1
Inputcopy | Outputcopy |
---|---|
1 4 5000 2000 777 5000 | 2 |
思路:可以用前缀和和哈希表解决,用哈希表存储前i个数之和,每次判断前i个数与7777之差的数是否出现过,出现过则加上其出现过的次数。
注意:读入和判断需要同时进行,否则会超时。
代码:
#include<bits/stdc++.h>
void asd();
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
asd();
}
}
void asd(){
unordered_map<long long,int>q;
long long n,i,sum=0,m,num=0;
cin>>n;
q[0]=1;
for(i=1;i<=n;i++){
scanf("%lld",&m);
num+=m;
q[num]++;
if(num>=7777){
if(q[(num-7777)]){
sum+=q[(num-7777)];
}
}
}
cout<<sum<<endl;
}
C
D
有一天,mob遇到一个很棘手的问题,问遍了周围的同学都不能解释。
在mob遇到人生挫折的时候想起了一位学长—— Joler。
但 Joler 有一个小毛病,说话东一句西一句。
这个毛病形式上的说,一句话有 n 个单词,每个单词为 ai(1≤i≤n)。
Joler会以 "a1a3a5⋯a6a4a2" 的形式说。
实际上他想说的是:
a1a2a3a4a5a6⋯⋯
例如Joler说:"This an problem easy is."
但他其实是想说:"This is an easy problem."
mob非常想知道 Joler 的教诲,请你帮帮他吧!
Input
第一行有一个数字 T(1≤T≤102),代表接下去有 T 行。
然后每行都有若干个单词组成,每个单词有且仅有小写字母 'a' 到 'z'、大写字母 'A' 到 'Z' 和数字 0∼90∼9。
值得注意的是:每行教诲最后都会紧跟一位标点符号(只会出现 '.'、'!' 或 '?' 三个字符中的一个)。
每个单词长度 1≤len≤30,每行的单词数不超过 1000 个。 题目保证每个单词之间只存在一个空格符。
Output
有 T 行,每行输出 Joler 通顺的语句吧!
每行结尾最后的特殊字符依旧在最后!
Sample 1
Inputcopy | Outputcopy |
---|---|
2 This an problem easy is. a c e f d b! | This is an easy problem. a b c d e f! |
思路:按字符串读入存入vector,当读入的字符串最后一位是.或!或?时停止读入,将其最后一个字符弹出(pop_bcak)再存,输出第一个和最后一个字符串,l++ r--(l<=r)直到最后输出字符。
注意:string类返回最后一个字符操作为:s.back();
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
vector<string>s;
string g;
char op;
while (cin>>g){
if(g.back()=='.'||g.back()=='!'||g.back()=='?'){
op=g.back();
g.pop_back();
s.push_back(g);
break;
}
s.push_back(g);
}
for (int l = 0,r=s.size()-1; l <=r ; ++l,r--) {
if(l==r){
cout<<s[l];
}
else{
cout<<s[l]<<' '<<s[r];
if(r-l>1)cout<<' ';
}
}
cout<<op;
cout<<endl;
}
signed main() {
int t=1;
cin>>t;
while (t--){
solve();
}
}
E
给定 n 个数组,每个数组 m 个数字。
分别从每个数组中取一个数字,组成一个集合,进行如下操作:
- 从集合中任取一个数,记作 a。
- 从集合中任取一个数,记作 b,将 |a−b| 计入答案。
- 丢弃 a,保留 b,并将其作为新的 a,重复步骤 2,直到数组中只剩一个数。
计算所有第 22 步中计入答案的数的和可能达到的最小值。
Input
首行给出 n,m(2≤n≤10,0≤m≤10^6,n⋅m≤10^6),表示共有 n 个数组,每个数组 m 个元素。
接下去 n 行,每行 m 个数表示数组各个元素 (aij 表示第 i 个数组第 j 个数字,∀i,j,0≤aij≤10^9)。
Output
一个整数,表示答案的最小值。
Sample 1
Inputcopy | Outputcopy |
---|---|
2 3 5 7 6 9 8 2 | 1 |
思路:我们可以这样考虑,若a=1,b=3,c=6,d=9那么∣∣a−c∣+∣c−d∣=d−a,其实不难发现,若我们把数组排序,只要我们选择首位和末位,一个数组两数的差的绝对值之和,等于最后一个元素于第一个元素的差,那么我们就可以考虑,pair存数,first为值,second为它属于哪一个数组,全部加入vector,然后按照first升序排列,从左遍历,那么我们就可以把遍历到的点加入map,如果我们map的size()为n,那么说明我们其中选的就已经符合题意了,那么我们就可以考虑边界l,r的移动问题,我们把l++,移动到一个不符合条件的左区间,期间符合条件的更新ans取最小值,不符合的,r++,然后就可以线性的维护出答案ans
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n,m;
cin>>n>>m;
vector<pair<int,int>>q;
for (int i = 0; i <n ; ++i) {
for (int j = 0; j < m; ++j) {
int x;
cin>>x;
q.push_back({x, i});
}
}
if(m==0){
cout<<"0";
return;
}
sort(q.begin(),q.end());
int ans=1e14;
map<int,int>mp;
int l=0;
for (int r = 0; r <q.size() ; ++r) {
int rr=q[r].second;
mp[rr]++;
if(mp.size()==n){
ans=min(ans,q[r].first-q[l].first);
for (int i = l; i <r ; ++i) {
l++;
int ll=q[i].second;
mp[ll]--;
if(!mp[ll])mp.erase(ll);
if(mp.size()!=n)break;
ans=min(ans,q[r].first-q[l].first);
}
}
}
cout<<ans<<endl;
}
signed main() { ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int t=1;
//cin>>t;
while (t--){
solve();
}
}
F
给两个边长为n的正方形A,B,正方形每一个格子都有一个数字,若有一个位置的数字不同,这两个正方形就不同。
我们可以将正方形绕中心顺时针旋转和逆时针旋转任意次数,问是否可以将A正方形旋转为B正方形,如果可以问最少次数是多少,如果不可以输出-1.
Input
输入第一行 T 表示一共有 T 组测试数据 (1≤T≤100)。
接下来一行输入一个正整数 N 表示正方形的大小 (1≤N≤20)。
接下来 2⋅N2⋅ 行,每行 N 个数:
其中前 N 行表示第一个正方形的颜色。
后 N 行表示第二个正方形的颜色,其中颜色用数字标号 colorij 表示 (1≤colori,j≤10^9)。
Output
输出 T行,每行输出 ans表示最小的操作次数,若不能通过操作使得两个正方形匹配,输出 −1。
Sample 1
Inputcopy | Outputcopy |
---|---|
2 2 1 2 1 2 2 2 1 1 2 1 2 1 2 2 1 1 2 | 1 -1 |
思路:可能的旋转次数只有0,1,2次因为逆时针旋转1次和顺时针旋转3次是相同的。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
vector<vector<int>>g(25,vector<int>(25));
vector<vector<int>>sc(25,vector<int>(25));
int n;
cin>>n;
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=n ; ++j) {
cin>>g[i][j];
}
}
int st0=1,st1=1,st2=2,st3=1;
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=n ; ++j) {
cin>>sc[i][j];
if(sc[i][j]!=g[i][j])st0=0;
}
}
if(st0){
cout<<"0\n";
return;
}
///逆时针旋转
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=n ; ++j) {
if(g[i][j]!=sc[n-i+1][n-j+1]){
st2=4;
}
}
}
///旋转180
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=n ; ++j) {
if(sc[i][j]!=g[j][n-i+1])st1=4;
}
}
///顺时针旋转
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=n ; ++j) {
if(sc[i][j]!=g[n-j+1][i])st3=4;
}
}
int ans=min({st1,st2,st3});
if(ans==4){
cout<<"-1\n";
}
else{
cout<<ans<<'\n';
}
}
signed main() {
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int t=1;
cin>>t;
while (t--){
solve();
}
}
G
现在你有一个电子表,但是他的时间可能是不准确的,请你对照准确时间确定电子表的时间相差了多少。
Input
单组数据输入。
输入一共 6 行,每行为一个长度为 18 的字符串。
前三行代表实际时间,后三行代表你的电子表时间,时间为 xx 时 xx 分 xx 秒。
每个数字占一个 3×3的大小。
0∼9 的数字格式参照样例 2。
Output
输出一共 44 行。
第 11 行输出两者时间关系:
- 如果你的电子表时间比实际时间慢输出 "late"(没有引号)。
- 如果比实际时间快输出 "early"(没有引号)。
- 如果完全一样输出 "gang gang hao"(没有引号)。
第 22 行到第 44 行输出 33 行,代表两者时间差。
Sample 1
Inputcopy | Outputcopy |
---|---|
_ _ _ _ _ _ _| _| _| _| _| _| |_ |_ |_ |_ |_ |_ _ _ _ _ _ _ _| _| _| _| _| _| |_ _||_ |_ |_ |_ | late _ _ _ _ _ | | || || || || | |_| ||_||_||_||_| |
Sample 2
Inputcopy | Outputcopy |
---|---|
_ _ _ _ _ ||_| _| | _||_ | _||_ | _| _| _ _ _ _ ||_| _||_ _||_| ||_||_ |_| _| | | early _ _ _ | | || | || | | |_| ||_| ||_| | |
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
void solve(){
/双向映射,方便转入和转出
/每个数字由3行组成,我们把它连接成一个字符串
map<string ,int >mp1;
map<int , string >mp2;
mp1[" _ | ||_|"] = 0; mp2[0] = " _ | ||_|";
mp1[" | |"] = 1; mp2[1] = " | |";
mp1[" _ _||_ "] = 2; mp2[2] = " _ _||_ ";
mp1[" _ _| _|"] = 3; mp2[3] = " _ _| _|";
mp1[" |_| |"] = 4; mp2[4] = " |_| |";
mp1[" _ |_ _|"] = 5; mp2[5] = " _ |_ _|";
mp1[" _ |_ |_|"] = 6; mp2[6] = " _ |_ |_|";
mp1[" _ | |"] = 7; mp2[7] = " _ | |";
mp1[" _ |_||_|"] = 8; mp2[8] = " _ |_||_|";
mp1[" _ |_| _|"] = 9; mp2[9] = " _ |_| _|";
string s1,s2,s3;
getline(cin,s1);
getline(cin,s2);
getline(cin,s3);
vector<string>a(6,"");
///每个数字三行,S1,S2,S3,且每一行代表6个数字的1/3部分,那么我们就可以组装成一个6string,然后映射成数字
for (int i = 0; i <6 ; ++i) {
a[i]+=s1.substr(i*3,3);
}
for (int i = 0; i <6 ; ++i) {
a[i]+=s2.substr(i*3,3);
}
for (int i = 0; i <6 ; ++i) {
a[i]+=s3.substr(i*3,3);
}
// for (int i = 0; i <6 ; ++i) {
// cout<<mp1[a[i]]<<' ';
// }
然后接着映射second时间
getline(cin,s1);
getline(cin,s2);
getline(cin,s3);
vector<string>b(6,"");
for (int i = 0; i <6 ; ++i) {
b[i]+=s1.substr(i*3,3);
}
for (int i = 0; i <6 ; ++i) {
b[i]+=s2.substr(i*3,3);
}
for (int i = 0; i <6 ; ++i) {
b[i]+=s3.substr(i*3,3);
}
// for (int i = 0; i <6 ; ++i) {
// cout<<mp1[b[i]]<<' ';
// }
vector<int>q;
for (int i = 0; i <6 ; ++i) {
q.push_back(mp1[a[i]]);
}
/lambda匿名函数表达式,函数内使用函数,这个你就可以不用全局变量,不用传递指针也可以调用函数,函数内可以使用局部变量
/gett函数得到秒数
auto gett=[&](int h,int m,int s){
return h*3600+m*60+s;
};
int h1=q[0]*10+q[1];
int min1=q[2]*10+q[3];
int se1=q[4]*10+q[5];
int r1=gett(h1,min1,se1);
初始时间r1,单位s
q.clear();
for (int i = 0; i <6 ; ++i) {
q.push_back(mp1[b[i]]);
}
h1=q[0]*10+q[1];
min1=q[2]*10+q[3];
se1=q[4]*10+q[5];
int r2=gett(h1,min1,se1);
///末尾时间r2,单位s
/f函数将时间单位为s的转换成h:min:s,6个数字依次加入vector ans之中返回ans
auto f=[&](int x){
vector<char>ans;
int h=x/3600;
int m=x%3600/60;
int s=x%60;
string hh=to_string(h);
string mm=to_string(m);
string ss=to_string(s);
if(hh.size()==1){
ans.push_back('0');
ans.push_back(hh.back());
}
else{
ans.push_back(hh[0]);
ans.push_back(hh[1]);
}
if(mm.size()==1){
ans.push_back('0');
ans.push_back(mm.back());
}
else{
ans.push_back(mm[0]);
ans.push_back(mm[1]);
}
if(ss.size()==1){
ans.push_back('0');
ans.push_back(ss.back());
}
else{
ans.push_back(ss[0]);
ans.push_back(ss[1]);
}
return ans;
};
if(r2<r1){
cout<<"early\n";
}
else if(r2==r1){
cout<<"gang gang hao\n";
}
else{
cout<<"late\n";
}
auto res=f(abs(r2-r1));
///得到数字数组然后转为字符,mp2反映射
for (int i = 0; i <3 ; ++i) {
for (int j = 0; j <6 ; ++j) {
string result=mp2[res[j]-'0'].substr(i*3,3);
cout<<result;
}
cout<<endl;
}
}
signed main() {
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int t=1;
//cin>>t;
while (t--){
solve();
}
}
H
I
虽然 PHarr 喜欢听邓园长唱歌,但是没有听到自己特别喜爱的歌还是有些遗憾的。
邓园长直播间的点歌规则为「先到先服务」,即开播时观众最先点的歌会加入队列中,也可以使用钞能力。
但是作为没有经济收入的大学生的 PHarr 显然不会使用钞能力。
他知道邓园长接下来马上就要开播了,所以他决定相信自己多年单身的手速,点到自己特别喜爱的歌。
PHarr 有 n 首特别喜爱的歌,他对每首歌的喜爱程度都能用一个整数来表示,且喜爱程度各不相同,喜爱程度越大,就说明他越想点这首歌。
由于 PHarr 没有错过邓园长的每场直播,所以他知道他最想点的前 k 首歌都已经被人点过了,显然他不想浪费点歌的机会,所以他会选择第 k+1 首最想点的歌。
邓园长的直播马上就要开始了,而 PHarr 实在太过紧张,不知道自己该点的歌是哪首,所以请你帮助他尽快找到他想点的歌。
Input
第一行包含一个数字 n(1≤n≤10^5),代表有 n 首歌。
接下来 n行,第 i 行包含一个正整数 wi(1≤wi≤10^9)和一个字符串 si(1≤|si|≤15),代表第 i 首歌的喜爱程度和歌名。
题目保证每首歌的喜爱程度和歌名各不相同。
最后一行包含一个正整数 k(0≤k<n),代表已经被点过的最想点的歌的数量。
Output
输出一行,代表想点的歌的歌名。
Sample 1
Inputcopy | Outputcopy |
---|---|
4 1 flos 3 Yellow 9 Starduster 1000000000 Kawakiwoameku 3 | flos |
思路:用结构体存储每首歌的喜爱程度和歌名,然后定义一个cmp函数用sort函数对喜爱程度进行降序,输出第k首歌的歌名。
代码:
#include<bits/stdc++.h>
struct asd{
long long n;
char b[16];
}a[100005];
bool cmp(asd x,asd y);
using namespace std;
int main(){
int T,k;
cin>>T;
for(int i=0;i<T;i++){
cin>>a[i].n;
getchar();
gets(a[i].b);
}
cin>>k;
sort(a,a+T,cmp);
puts(a[k].b);
}
bool cmp(asd x,asd y){
return x.n>y.n;
}
Sample 2
Inputcopy | Outputcopy |
---|---|
1 1000000000 CryingforRain 0 | CryingforRain |
J
K
袋鼠在一个有n个点的圆上,编号为0到n-1
你每次可以跳x长度
比如你从0跳到x
请你判断一下无限次数的跳跃(>=1)是否可以从0点跳回0点
Input
t 组输入 (1≤t≤103)。
每组输入包含两个数字 n(2≤n≤106),x(0≤x≤106)。
Output
t行输出,如果可以输出 "yes"(没有引号),否则输出 "no"(没有引号)。
Sample 1
Inputcopy | Outputcopy |
---|---|
2 3 1 4 2 | yes yes |
Sample 2
Inputcopy | Outputcopy |
---|---|
2 3 2 13 0 | yes no |
思路:容易看出,只要步长不为0总能跳回0点;
代码:
include<bits/stdc++.h>
typedef long long ll;
typedef double db;
int sum;
void solve();
using namespace std;
vector<int>q;
int main(){
int n,q,w;
cin>>n;
while(n--){
cin>>q>>w;
if(w==0){
cout<<"no"<<endl;
}
else{
cout<<"yes"<<endl;
}
}
}
L
在这场比赛,我的个人发挥不是很理想,写题有些犹豫,不知道到底先开始写哪题,一直卡在一题太久,简单题后面才去做,浪费了很多时间,有些题只是看起来不会,实际上仔细审题后还是会的,但是前面已经浪费了很多时间,导致AC掉的题目数量太少了。所以,一场比赛应该注意哪题过的人很多的时候就要解决那题了,即使你看起来不会写,可能只是障眼法罢了,认真审题就会有思路,不要畏惧题目,不要一直在一题卡着,太久写不出来就应该换题了。