A题贪心二分前缀和 可以直接upper_bound(x)找到大于x的第一个数的下标再减一 自己感觉还是板子好用
[A] [c++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include<bits/stdc++.h> using namespace std; long long n,q,a[100010],v[100010],ans; long long k,x,m; long long check(long long x1 ) //升序 找到小于等于x的第一个下标 { long long l=0,r=n; while(l<r) { long long mid=(l+r+1)/2; if(v[mid]<=x1) l=mid; else r=mid-1; } return l; } int main() { cin>>n>>q; for(int i=1;i<=n;i++) cin>>v[i]; sort(v+1,v+n+1); for(int i=1;i<=n;i++) a[i]=a[i-1]+v[i]; //前缀和一下 sort升序 while(q--) { cin>>k>>x; m=check(x); if(m-k<=0) ans=a[m]; else ans=a[m]-a[m-k]; cout<<ans<<endl; } return 0; }
B题难点:读懂题 字典序比较就是从左往右的第一个 所以最优的就是每个人拿一个石子放空的格子 如果是偶数 大家都是这么多格子 平手 如果是奇数 先手多拿了一个 那么后手必胜
C题 贪心 长度一样只要两个串完全一样肯定是等于 而如1234和1243 我们只要找到第一个不一样的数 其大小关系随映射关系而变化
经典错解就是长度一样长的一定大 如11444和222 如果1->0 2->3 4->1 则变成了00111和333 由于前导0的存在 长的不一定大 主要矛盾就是这
解决方法就是找到让长的不一定大的方法 若长度分别为nx,,ny 相差nx-ny 若x的前n个数映射后有一个不为0 那么肯定x大 所以我们可以假设前n个数映射后都是0 再比较后面的 那么我们就根据前导零分类讨论找一定大于和一定小于两种情况 其它的都是!
[C] [c++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #include <bits/stdc++.h> using namespace std; string a, b; int main() { ios::sync_with_stdio(false); cout.tie(NULL); cin >> a >> b; char ans = '>';//假定a更大 if(a.length() < b.length()){ ans = '<';//如果a更短,则为小于号 swap(a, b); } int n = a.length(); int m = b.length(); if(a == b) {//相等就一定相等 cout << "="; return 0; } if(n == m){//长度相等,但两者不等一定不确定答案 cout << "!"; return 0; } //因为排列不同,数字间的大小就变的无意义,在一个排列下大于的是小于,另一种排列大于的还是大于 //长度不同,若无前导0则一定是长的大,所以我们假设a前面全是前导0最坏情况,看是否有可能 长的数 <= 短的数 int id1 = 0; for(int i = 1; i < n; i ++){ if(a[i] == a[0]) id1 = i; else break ; } //因为假设a前面全是前导0,所以若b前面数字相同的也是前导0也不能算 int id2 = -1; for(int i = 0; i < m; i ++){ if(b[i] == a[0]) id2 = i; else break; } int len1 = n - id1 - 1;//a最小情况下的有效长度 int len2 = m - id2 - 1;//b最小情况下的有效长度 if(len1 > len2){ cout << ans; } else if(len1 == len2){//因为已经确定a[0]所代表的数字就是最小的0,所以还需要比较一下 for(int i = 1; i <= len1; i ++){ if(a[id1 + i] == b[id2 + i]) continue; if(b[id2 + i] == a[0]){ cout << ans; return 0; } else break;//a可能更小 } cout << "!"; } else cout << "!"; return 0; }
假设当前答案为num 得到一个区间后 如果左端点在num里 num扩大到其右端点
[D] [c++]