QAQ:我又开始更新了
A. Even But Not Even
题意:
给你一个数,你可以删去这个数中的某几位,使得到的新数是个奇数,但这个数的每位数之和是个偶数。如果可以输出新数,不可以输出-1
思路:
我们可以把所有的奇数都挑出来,这样的得到的数一定是个奇数,然后判断下长度,-1的情况就是长度为1时,此时不满足和是偶数且无法通过缩减长度达到满足条件。剩下的如果长度为偶数就直接输出,长度为奇数就不输出最后一位。
代码:
#include <bits/stdc++.h> using namespace std; int main() { int t; cin >> t; while(t--) { int len; string s; cin >> len; cin >> s; string t = ""; for(int i= 0;i<len;++i) { if((s[i]-'0')%2==1) { t+=s[i]; } } int k = t.size(); if(k<=1) { printf("-1 "); } else { if(k%2==0) cout <<t << " "; else { // cout << 1 << endl; for(int i = 0;i<k-1;++i) cout << t[i]; cout << " "; } } } return 0; }
B. Array Sharpening
题意:
给你一个长度为n的数组,对于每一个大于0的数,你可以把它们减1,问能不能将这个数组构造成单峰数组
思路:
首先,数组中要求存在的最小元素是0,我们可以从左到右枚举,从左到右能构造的最长严格上升子序列的右下标为l,然后再从右往左,从右往左能构造的最长严格下降子序列的左下标为r,假如这两段子序列不相交,即l<r,则输出No,否则输出Yes。
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 3e5+10; typedef long long LL; LL num[maxn]; int main() { int t; cin >> t; while(t--) { int n; cin >> n; for(int i = 0; i<n; i++) cin >> num[i]; int a = 0; bool flag = true; int l,r; for(int i = 0; i<n; ++i,++a) { if(num[i]<a) { l = i-1; flag = false; break; } } if(flag) { printf("Yes "); continue; } flag = true; a = 0; for(int i = n-1; i>=0; --i,++a) { if(num[i]<a) { r = i+1; flag =false; break; } } // cout << l << " " << r << endl; if(flag) { printf("Yes "); continue; } if(l>=r) { printf("Yes "); } else printf("No "); } return 0; }
C. Mind Control
题意:
有个长度为n的数组和n个人,你可以控制其中的k个人,n个人站成一个队列,你是第m个,每个人可以从数组的前面或者后面拿走一个数,问你在最坏的情况下拿到的数是多少,输出这个数。
思路:
首先,你能选择控制的人一定要排在你前面,这样对于结果才能产生作用,接下来排在你前面的人可以分为两种,一种人数是k,另一种的人数是m-1-k,接下来就是轮流从前取数,我们可以枚举从前面取数的人有多少,然后就可以就算出从后面取数的人有多少,然后根据条件更新答案就行
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 4000; LL num[maxn]; int main() { int t; scanf("%d",&t); while(t--) { int n,m ,k; scanf("%d %d %d",&n,&m,&k); for(int i= 1;i<=n;++i) scanf("%lld",&num[i]); k = min(m-1,k); int d = m-k-1; LL ans = 0; //cout << k << " " << d << endl; for(int l1 = 0;l1<=k;l1++) { int r1 = k-l1; LL tmp = 0; for(int l2 = 0;l2<=d;l2++) { int r2 = d-l2; int l3 = 1+l1+l2,r3 = n-r2-r1; if(tmp==0) { tmp = max(num[l3],num[r3]); } else { tmp = min(tmp,max(num[l3],num[r3])); } //cout << l1 << " " << r1 << " " << l2 << " " << r2 << " " << tmp <<endl; } ans = max(ans,tmp); //cout << ans << endl; } cout << ans << " "; } return 0; }
D. Irreducible Anagrams
题意:
对于两个字符串s,t定义一种情况anagrams of each other,表示将s中的字母重新放置以后能够得到t。
对于两个满足anagrams of each other的字符串s和t,假如满足以下条件,则可以称为reducible anagram。
条件为存在一个数k(k>=2),并将s划分为k个子串,标为s1……sk,t划分为k个子串
标为t1……tk,并且子串满足:1.完成划分后子串的相对顺序不能变,即将子串按照下标连接起来以后依然是原先的串。2.对应下标的串si和ti彼此之间是anagrams of each other
如果不满足上述条件,不满足上述条件,则称为 irreducible anagram,上面的定义时建立在s和t是anagrams of each othe时。
现在给出一个字符串s和q次询问
每次询问给出两个数l和r,代表从s中截出sl……sr这段子串,问能否找到一个字符串t使得这两段字符串满足 irreducible anagram。能Yes,否No。
思路:
首先,我们把截出来的子串表示为k。
能想到的是,如果k的长度是1那么一定是Yes,因为无法划分成两个子串。
接下来就是首尾两个字母不同即s[l]!=s[r],那我们只要交换s[l]和s[r]就一定是Yes。
最后剩下的就是首尾相同情况,此时参照上面的情况,如果k中出现的字母种类大于等于三种,我们就可以找一个最大的j使得s[j]!=s[n],然后与s[j]相同的放在最前面,接下来放与s[n]相同的,剩下的随便放,可以证明,这样的串一定是符合条件的。
前两种情况都比较好判定,第三种情况可以通过前缀和来解决。详情请见代码。
代码:
#include <bits/stdc++.h> using namespace std; const int N = 2e5+20; char s[N]; int n,q,l,r,sum[N][26]; int main() { cin >> (s+1); n = strlen(s+1); for(int i =1;i<=n;++i) { for(int j = 0;j<26;++j){ sum[i][j] = sum[i-1][j]; } sum[i][s[i]-'a']++; } cin >> q; while(q--) { cin >> l >> r; int cnt =0; for(int i = 0;i<26;++i) { cnt+=(sum[r][i]-sum[l-1][i]>0); } if(l==r||cnt>=3||s[l]!=s[r]) { cout << "Yes "; } else cout << "No "; } return 0; }