套路题不会。考虑重修一下。
T1
经过考后的采访,joke3579、gtm1514、Chen_jr、Muel_imj四个人考场上写的Checker都拍过了然后都挂了零。
实际上从前往后扫,只要交换每个位置上比这个位置小 \(1\) 的数即可,因为这样会且仅会减少调整的这一对逆序对。
#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
int n,cnt,a[1010],pos[1010];
struct node{
int l,r;
}q[1000010];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
pos[i]=a[i];
}
for(int i=1;i<=n;i++){
while(a[i]!=i){
for(int j=i+1;j<=n;j++){
if(a[i]==a[j]+1){
swap(a[i],a[j]);
q[++cnt]={i,j};
break;
}
}
}
}
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++)printf("%d %d\n",q[i].l,q[i].r);
}
T2
考虑一个人类智慧构造。
首先我们把这个数左移若干位,直到最后一位与第一位重合,此时异或即可消掉最后一位。
然后我们将这个异或和与左移后的数加起来,那么最高位之前的就是异或和左移一位,最高位之后不变,都异或起来可以找到这个数的最高位。将最高位和这个数异或一下可以消掉,逐步消直至消到 \(1\) 即可。
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define int long long
int x,cnt;
struct node{
int od,x,y;
}q[100010];
int lowbit(int x){
return x&-x;
}
signed main(){
scanf("%lld",&x);
while(x!=1){
int y=x;
for(int i=1;i<=__lg(x);i++){
q[++cnt]={1,y,y};
y<<=1;
}
q[++cnt]={2,x,y};
int z=x^y;
q[++cnt]={1,y,z};
int ret=y+z;
q[++cnt]={1,y,y};
int tmp=y<<1;
q[++cnt]={2,tmp,ret};
tmp^=ret;
q[++cnt]={2,tmp,x};
int ans=x^tmp;
while(y!=lowbit(y)){
if(y&ans){
q[++cnt]={2,ans,y};
y^=ans;
}
q[++cnt]={1,ans,ans};ans<<=1;
}
q[++cnt]={2,x,y};x^=y;
}
printf("%lld\n",cnt);
for(int i=1;i<=cnt;i++)printf("%lld %lld %lld\n",q[i].od,q[i].x,q[i].y);
}
T3
大水题,然后考场没写出来,属于是套路都不会了。赶紧退役吧。
我们枚举popcount,然后问题就变成了区间最大值+最小值=2(而且是最大值)。这是个经典扫描线问题。
注意我们要把所有的操作离线下来,不能顺序扫一遍所有的,要不然复杂度不对。
虽然我这个CF上被卡常了。
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <vector>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
int n,top1,top2,cnt[70],c[1000010],maxx[1000010],minn[1000010];
long long ans,a[1000010];
struct node{
int l,r,max,cnt,lazy;
}tree[4000010];
void pushup(int rt){
tree[rt].max=max(tree[lson].max,tree[rson].max);
tree[rt].cnt=(tree[rt].max==tree[lson].max?tree[lson].cnt:0)+(tree[rt].max==tree[rson].max?tree[rson].cnt:0);
}
void pushdown(int rt){
if(tree[rt].lazy){
int lz=tree[rt].lazy;tree[rt].lazy=0;
tree[lson].max+=lz;tree[lson].lazy+=lz;
tree[rson].max+=lz;tree[rson].lazy+=lz;
}
}
void build(int rt,int l,int r){
tree[rt].l=l;tree[rt].r=r;tree[rt].cnt=r-l+1;
tree[rt].lazy=tree[rt].max=0;
if(l==r)return;
int mid=(l+r)>>1;
build(lson,l,mid);build(rson,mid+1,r);
}
void update(int rt,int l,int r,int val){
if(l<=tree[rt].l&&tree[rt].r<=r){
tree[rt].max+=val;tree[rt].lazy+=val;return;
}
pushdown(rt);
int mid=(tree[rt].l+tree[rt].r)>>1;
if(l<=mid)update(lson,l,r,val);
if(mid<r)update(rson,l,r,val);
pushup(rt);
}
struct stu{
int p,l,r,val;
};
vector<stu>q[64];
long long read(){
long long x=0;char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();c[i]=__builtin_popcountll(a[i]);
cnt[c[i]]++;
}
for(int i=1;i<=n;i++){
while(top1&&a[maxx[top1]]<=a[i]){
int p=maxx[top1--];
q[c[p]].push_back({i,maxx[top1]+1,p,-1});
}
q[c[i]].push_back({i,maxx[top1]+1,i,1});
maxx[++top1]=i;
while(top2&&a[minn[top2]]>a[i]){
int p=minn[top2--];
q[c[p]].push_back({i,minn[top2]+1,p,-1});
}
q[c[i]].push_back({i,minn[top2]+1,i,1});
minn[++top2]=i;
}
for(int i=0;i<=63;i++){
if(!cnt[i])continue;
build(1,1,n);
int ret=0;
for(int j=1;j<=n;j++){
while(ret<q[i].size()&&q[i][ret].p<=j){
update(1,q[i][ret].l,q[i][ret].r,q[i][ret].val);
ret++;
}
if(tree[1].max==2)ans+=tree[1].cnt;
}
}
printf("%lld\n",ans);
return 0;
}
T4
怪异的构造题。
考虑通过一个栈把所有的操作建出一个操作森林。具体的说,我们从小到大扫,每扫出三个同一个人选的牌就建出一个点出栈,同时将这个点与栈顶连边。
然后是构造方案。先手取的时候随便找一个归先手的叶子即可,后手取的时候只要保证取完以后仍然有一个根归后手即可。
证明不会。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
const int N=2e3 + 10;
int n,a[1210];
bool vis[1210];
struct node{
int cnt,a[4],fa,deg,player;
bool jud;
}rt;
vector<node>v;
stack<int>s;
signed main() {
scanf("%d",&n);
for(int i=1;i<=3*n;i++){
scanf("%d",&a[i]);
vis[a[i]]=true;
}
rt.cnt=rt.deg=0;rt.player=-1;rt.jud=true;
v.push_back(rt);s.push(0);
for(int i=1;i<=6*n;i++){
if(v[s.top()].player==vis[i]){
v[s.top()].a[++v[s.top()].cnt]=i;
if (v[s.top()].cnt==3)s.pop();
}
else{
v.push_back({1,{0,i,0,0},s.top(),0,vis[i],false});
v[s.top()].deg++;
s.push(v.size()-1);
}
}
for(int i=1;i<=2*n;i++){
int ret=-1;
for(int j=1;j<=2*n;j++){
if(v[j].jud||v[j].player!=(i&1)||v[j].deg>0)continue;
ret=j;
if((i&1)||v[j].fa!=0)break;
}
printf("%d %d %d\n",v[ret].a[1],v[ret].a[2],v[ret].a[3]);
v[ret].jud=true;
v[v[ret].fa].deg--;
}
return 0;
}
标签:13,ch,int,ret,异或,long,include,CSP,模拟
From: https://www.cnblogs.com/gtm1514/p/16735431.html