1.31训练赛总结

A

给n个英文字母,你可以组成最长的回文串长度是多少?

现在,请你利用程序帮助算出他能构成的最长回文串的长度是多少。

Input

第一行包含一个正整数 T(1≤T≤10),代表有 T 组数据。

对于每一组数据:

第一行包含一个正整数 n(1≤n≤10^5),表示字母数量。

接下来的一行包含 n个由空格分隔的英文字母 ci,表示第 i 个字母。

Output

对于每组数据,输出一行表示能构成的最长回文串的长度。

Sample 1

InputcopyOutputcopy
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

InputcopyOutputcopy
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

InputcopyOutputcopy
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 个数字。

分别从每个数组中取一个数字,组成一个集合,进行如下操作:

  1. 从集合中任取一个数,记作 a。
  2. 从集合中任取一个数,记作 b,将 |a−b| 计入答案。
  3. 丢弃 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

InputcopyOutputcopy
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

InputcopyOutputcopy
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

InputcopyOutputcopy
 _  _  _  _  _  _ 
 _| _| _| _| _| _|
|_ |_ |_ |_ |_ |_ 
 _  _  _  _  _  _ 
 _| _| _| _| _| _|
|_  _||_ |_ |_ |_ 
late
 _     _  _  _  _ 
| |  || || || || |
|_|  ||_||_||_||_|

Sample 2

InputcopyOutputcopy
    _  _  _  _  _ 
  ||_| _|  | _||_ 
  | _||_   | _| _|
    _  _  _  _    
  ||_| _||_  _||_|
  ||_||_ |_| _|  |
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

InputcopyOutputcopy
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

InputcopyOutputcopy
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

InputcopyOutputcopy
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掉的题目数量太少了。所以,一场比赛应该注意哪题过的人很多的时候就要解决那题了,即使你看起来不会写,可能只是障眼法罢了,认真审题就会有思路,不要畏惧题目,不要一直在一题卡着,太久写不出来就应该换题了。 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值