A: 偶数直接除2, 余下偶数个奇数,一半向上取整,一半向下取整
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e4+10;
int n;
int a[N];
int vis[N];
int main(){
scanf("%d", &n);
int cnt = 0;
for(int i = 0; i < n; i++){
scanf("%d", &a[i]);
if(a[i]%2 == 0){
cnt++;
}
}
int yu = (n - cnt)/2;
int j = 0;
for(int i = 0; i < n; i++){
if(a[i]%2 ==0){
a[i] /= 2;
}
else if(j < yu ){
a[i] = (a[i]+1)/2;
j++;
}
else a[i] = (a[i]-1)/2;
}
for(int i = 0; i < n; i++){
printf("%d\n", a[i]);
}
return 0;
}
B:vis[i] 标记 i 是否超车, 遍历未超车的a[j], 找到第一个与 a[j] 相等的 b[i] , i 之前的标记为超车
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
int n;
int a[N];
int b[N];
int vis[N];
int main(){
scanf("%d", &n);
for(int i = 0;i < n; i++){
scanf("%d", &a[i]);
}
for(int i = 0;i < n; i++){
scanf("%d", &b[i]);
}
int cnt = 0;
int j = 0;
for(int i = 0; i < n && j < n; i++){
if(vis[a[j]]) {
j++;
i--;
continue;
}
if(b[i] == a[j]){
j++;
cnt++;
}
else{
vis[b[i]] = 1;
}
}
printf("%d\n", n-cnt);
return 0;
}
C1:按x,y,z排序, 将所有点排序,首先将x 、y相同, z不同的按顺序两两配对,再将x 相同的为配对点, 按顺序两两配对,
最后将剩下的两两配对。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e3+10;
int n;
struct point{
int x, y, z;
int num;
bool operator < (const point &p) const{
if(x != p.x) return x < p.x;
else if(y != p.y) return y < p.y;
else return z < p.z;
}
}p[N];
int vis[N];
vector< pair<int, int> > ans;
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z);
p[i].num = i;
}
sort(p+1, p+1+n);
for(int i = 1;i <= n; i++){
if(vis[p[i].num]) continue;
for(int j = i+1;j <= n; j++){
if(i == j || vis[p[j].num]) continue;
if(p[i].x == p[j].x && p[i].y == p[j].y){
ans.push_back(make_pair(p[i].num, p[j].num));
vis[p[i].num] = vis[p[j].num] = 1;
break;
}
}
}
for(int i = 1;i <= n; i++){
if(vis[p[i].num]) continue;
for(int j = i+1;j <= n; j++){
if(i == j || vis[p[j].num]) continue;
if(p[i].x == p[j].x && p[i].y != p[j].y){
ans.push_back(make_pair(p[i].num, p[j].num));
vis[p[i].num] = vis[p[j].num] = 1;
break;
}
}
}
int u, v;
for(int i = n; i >= 1; ){
int x[2];
int flag = 1;
for(int j = 0; j < 2; j++){
while(vis[p[i].num] && i >= 1){
i--;
}
if(i < 1) {
flag = 0;
break;
}
x[j] = p[i].num;
i--;
}
if(flag == 0) break;
ans.push_back(make_pair(x[0], x[1]));
}
for(auto u:ans){
printf("%d %d\n", u.first, u.second);
}
return 0;
}
C2:思路和C1一样,用个vector、map维护一下就好
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4e5+10;
int n;
struct point{
int x, y, z;
int num;
bool operator < (const point &p) const{
if(x != p.x) return x < p.x;
else if(y != p.y) return y < p.y;
else return z < p.z;
}
}p[N];
int vis[N];
vector< pair<int, int> > ans;
vector<int> po[N];
map< pair<int, int> , int > mp;
map<int, int> mp2;
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z);
p[i].num = i;
}
sort(p+1, p+1+n);
int pos, cnt = 0;
for(int i = 1;i <= n; i++){
pair<int, int> pa = make_pair(p[i].x, p[i].y);
if(mp.count(pa)){
pos = mp[pa];
}
else{
pos = ++cnt;
mp[pa] = pos;
}
po[pos].push_back(p[i].num);
}
for(int i = 1;i <= cnt; i++){
if(po[i].size() >= 2)
for(int j = 0; j < po[i].size()-1; j += 2){
ans.push_back(make_pair(po[i][j], po[i][j+1]));
vis[po[i][j]] = vis[po[i][j+1]] = 1;
}
po[i].clear();
}
pos, cnt = 0;
for(int i = 1;i <= n; i++){
if(vis[p[i].num]) continue;
if(mp2.count(p[i].x)){
pos = mp2[p[i].x];
}
else {
pos = ++cnt;
mp2[p[i].x] = pos;
}
po[pos].push_back(p[i].num);
}
for(int i = 1;i <= cnt; i++){
if(po[i].size() >= 2)
for(int j = 0; j < po[i].size()-1; j += 2){
ans.push_back(make_pair(po[i][j], po[i][j+1]));
vis[po[i][j]] = vis[po[i][j+1]] = 1;
}
po[i].clear();
}
int u, v;
for(int i = n; i >= 1; ){
int x[2];
int flag = 1;
for(int j = 0; j < 2; j++){
while(vis[p[i].num] && i >= 1){
i--;
}
if(i < 1) {
flag = 0;
break;
}
x[j] = p[i].num;
i--;
}
if(flag == 0) break;
ans.push_back(make_pair(x[0], x[1]));
}
for(auto u:ans){
printf("%d %d\n", u.first, u.second);
}
return 0;
}
D: 当max(a) <= 2*min(a) 时答案全为-1, 否则答案最大为2*n,
二分枚举每个起点的答案,
用线段树维护区间最大值、最小值和区间是否合法(区间 ,任意点 i ,都有 )
要是区间 合法,则该区间左儿子Lson、右儿子Rson合法,并且max(Lson)<= 2*min(Rson)
查询:每次先向左查询,last_max表示已查询区间前面的最大值, 对于正在查询的区间如果区间合法并且当前区间最小值min*2 >= last_max , 那么该区间合法, return 1;
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+10;
int n;
int a[N];
struct node{
int mi, ma;
int flag;
}tr[N*4];
int last_max;
void up(int o, int l, int r, int pos, int v){
if(l == r){
tr[o].ma = tr[o].mi = v;
tr[o].flag = 1;
return ;
}
int mid = l+r>>1;
if(pos <= mid) up(o<<1, l, mid, pos, v);
else up(o<<1|1, mid+1, r, pos, v);
tr[o].ma = max(tr[o<<1].ma, tr[o<<1|1].ma);
tr[o].mi = min(tr[o<<1].mi, tr[o<<1|1].mi);
if(tr[o<<1].flag == 0 || tr[o<<1|1].flag == 0 || tr[o<<1].ma > tr[o<<1|1].mi*2){
tr[o].flag = 0;
}
else tr[o].flag = 1;
}
int qu(int o, int l, int r, int ql, int qr){
if(ql <= l && qr >= r){
int flag = 1;
if(last_max > tr[o].mi*2 || tr[o].flag == 0)
flag = 0;
last_max = max(last_max, tr[o].ma);
return flag;
}
int mid = l+r>>1;
int ans = 1;
if(ql <= mid) ans *= qu(o<<1, l, mid, ql, qr);
if(qr > mid) ans *= qu(o<<1|1, mid+1, r, ql, qr);
return ans;
}
int main(){
cin >> n;
int mi = 1e9+10, ma = 0;
for(int i = 0; i < n; i++){
cin >> a[i];
mi = min(mi, a[i]);
ma = max(ma, a[i]);
}
if(mi*2 >= ma){
for(int i = 0; i < n; i++){
printf("-1%c", i == n-1?'\n':' ');
}
return 0;
}
for(int i = 0; i < 3*n; i++){
up(1, 1, 3*n, i+1, a[i%n]);
}
for(int i = 1; i <= n; i++){
int l = 1, r = 2*n-1, mid;
while(l <= r){
mid = l+r>>1;
last_max = 0;
if(qu(1, 1, 3*n, i, i+mid)) l = mid + 1;
else r = mid - 1;
}
cout << r+1 << " ";
}
return 0;
}