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++]
1
2
3