ABC203
C
题意:有从0开始编号的村子0, 1, 2, 3, ..., 一开始taro在0号,有k元,每去一个村子需要花费1元,taro有N个朋友,分别站在N个村子,当taro到第i个朋友站的村子的时候,第i个朋友会给他ki元,问taro能走到的最大编号是多少
方法:模拟或者二分(一开始想复杂了)
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int N = 2e5 + 10;
int n, k;
struct node{
int a, b;
bool operator<(const node &n){
return a < n.a;
}
}a[N];
signed main(){
cin >> n >> k;
for(int i = 1; i <= n; i ++) cin >> a[i].a >> a[i].b;
sort(a + 1, a + 1 + n);
int res = k, i = 0;
while(res >= a[i].a){
res += a[i].b;
i ++;
if(i > n) break;
}
cout << res;
}
D
题意:给你一个NxN网格g,每一个网格上有一个数字,问这个网格中所有大小为KxK的子矩阵中最小能达到的中位数的值是多少
方法:二分答案,如果存在一个K^2的网格使得中位数小于等于x,那么所有>= x的值均能满足条件,所以满足二段性,一定能找到最小的x,另外就是check函数复杂度的问题,如果直接暴力去找每一个K^2大小的矩阵的中位数再和x比的话是\(O((N-K+1)^2K^2)\), 肯定T,因为check函数需要判断是否存在一个k^2大小的矩阵使得它的中位数<= x, 所以只需要对每一个k^2大小的矩阵判断他里面> x的数的个数是否满足< k^2 / 2就行了,这里可以用提前标记+前缀和来做,复杂度\(O(N^2log1e9)\)
#include<iostream>
using namespace std;
const int N = 810;
int n, k;
int a[N][N], st[N][N];
int check(int x){
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
st[i][j] = a[i][j] > x;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
st[i][j] += st[i - 1][j] + st[i][j - 1] - st[i - 1][j - 1];
for(int i = 1; i <= n - k + 1; i ++)
for(int j = 1; j <= n - k + 1; j ++){
int p = i + k - 1, q = j + k - 1;
int val = st[p][q] - st[i - 1][q] - st[p][j - 1] + st[i - 1][j - 1];
if(val < k * k / 2 + 1) return 1;
}
return 0;
}
int main(){
cin >> n >> k;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
cin >> a[i][j];
int l = 0, r = 1e9;
while(l < r){
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
}
类似的题:https://codeforces.com/contest/1288/problem/D
题意:给你n个序列\(a_1, a_2, ..., a_n\),每一个序列长为m(m <= 8),任选序列ai和aj构成b,令bk = max(aik, ajk),问能够构成的序列b中最小值最大为多少
方法:二分答案,注意如果再check函数里面直接枚举i和j然后求b看是否能够找到这样的b它的最小值>= x,复杂度\(O(N^2)\)过不了,方法是对于ai计算一个数字t,如果ai是5,4,3,2,1,而x = 3,那么ai所得到的数字是\(t=(11100)_2\),就是只要是aik满足>= x就令t的从高向低的第k位为1,因为m很小,所以对于所有的ai,计算得到的数字数不超过2m,将所有得到的数字存起来,然后枚举其中的任意两个数,如果满足两者相或为2m - 1,那么就说明通过这两个序列得到的序列b满足最小值>= x,直接返回1即可
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
const int N = 3e5 + 10;
int a[N][10];
int n, m;
pair<int, int> ans{1, 1};
int check(int x){
map<int, int> mp;
for(int i = 1; i <= n; i ++){
int t = 0;
for(int j = 1; j <= m; j ++)
t = t * 2 + (a[i][j] >= x);
mp[t] = i;
}
for(auto i : mp)
for(auto j : mp)
if((i.first | j.first) == (1 << m) - 1){
ans = {i.second, j.second};
return 1;
}
return 0;
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
cin >> a[i][j];
int l = 0, r = 1e9;
while(l < r){
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout << ans.first << ' ' << ans.second << endl;
}