模拟。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
pair<int,int> a[110];
int main(){
int n;
cin>>n;
a[0]=make_pair(0,0);
for(int i=1;i<=n;i++){
int x,y;
cin>>x>>y;
a[i]=make_pair(x,y);
}
sort(a,a+n+1);
int k;
for(k=0;k<=n;k++){
if(a[k].first==0)break;
}
int p=0;
int ans=0;
while(1){
p++;
if(k+p>n)break;
if(k-p<0)break;
ans+=a[k+p].second;
ans+=a[k-p].second;
}
if(k+p<=n)ans+=a[k+p].second;
if(k-p>=0)ans+=a[k-p].second;
cout<<ans<<endl;
return 0;
}
尺取法。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int cnt[1000010];
int a[100010];
int main(){
int n;
cin>>n;
int MAX=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
cnt[a[i]]++;
MAX=max(MAX,cnt[a[i]]);
}
int l=0,r=0;
int cur=0;
memset(cnt,0,sizeof(cnt));
int ans=1e9;
int ansl,ansr;
while(1){
if(cur<MAX){
r++;
if(r>n)break;
cnt[a[r]]++;
cur=max(cur,cnt[a[r]]);
}else{
if(r-l<ans){
ans=r-l;
ansr=r; ansl=l;
}
l++;
cnt[a[l]]--;
if(cnt[a[l]]==MAX-1){
cur--;
}
}
}
cout<<ansl+1<<" "<<ansr<<endl;
return 0;
}
n个数,每次对一个数操作。共有两种操作,乘以2和整除2。问最少要多少次操作,才能使得所有n个数相等。
暴力。对于某个数来说,它通过操作得到100000以内的数的数量,最多是log^2(100000)。我们就可以通过二重循环计算出它可以到达的所有数需要的最少步。然后考察一下所有数都能达到的那些数,找一个最小的答案。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
using namespace std;
int a[100010];
int cnt[100010]; //统计n个数中有多少数能得到i
int ans[100010];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
int rightcarry=0; //先右移再左移,枚举右移量
while(1){
int tmp=a[i];
tmp>>=rightcarry;
if(tmp==0)break;
cnt[tmp]++;
ans[tmp]+=rightcarry;
if(rightcarry){
if( (a[i]>>(rightcarry-1)) == (tmp<<1) ){
rightcarry++;
continue;
}
}
int c=0;
while(1){
c++;
tmp<<=1;
if(tmp>100000)break;
cnt[tmp]++;
ans[tmp]+=(rightcarry+c);
}
rightcarry++;
}
}
int re=1e9;
for(int i=1;i<=100000;i++){
if(cnt[i]==n){ //有数得不到i的时候忽略
if(ans[i]<re)re=ans[i];
}
}
cout<<re<<endl;
return 0;
}
高度为h的满二叉树。节点从上到下从左到右编号,从根开始沿着某路径往下走直到叶子。有q个询问,每个询问获得的信息是在第i层有没有经过区间[l,r]。判断询问的答案是否矛盾,以及询问是否足够充分得到唯一的结果。
把Yes和No的两种询问分开,lr双关键字升序排序。先处理回答为Yes的询问,如果得到了不唯一的区间,就是矛盾的。然后处理回答为No的询问,去缩小那个区间,如果区间缩小为1,就是有唯一解,否则询问不够充分。最后还要判一遍矛盾,即判断Yes的回答是否都被满足。有很多要注意的细节,见代码。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
struct node{
ll l,r;;
node(){}
node(ll l,ll r):l(l),r(r){}
bool operator<(const node& other)const{
if(l==other.l)return r<other.r;
return l<other.l;
}
};
node Yes[100010];
node No[100010];
int main(){
int h,q;
cin>>h>>q;
int pYes=0;
int pNo=0;
for(int i=1;i<=q;i++){
int x,ans;
ll l,r;
scanf("%d%I64d%I64d%d",&x,&l,&r,&ans);
//弄到最下一层
for(int hh=x;hh<h;hh++){
l<<=1;
r<<=1;
r|=1;
}
if(ans){
pYes++;
Yes[pYes].l=l;
Yes[pYes].r=r;
}else{
pNo++;
No[pNo].l=l;
No[pNo].r=r;
}
}
sort(Yes+1,Yes+pYes+1);
sort(No+1,No+pNo+1);
bool cheated=0;
bool mulsol=0;
set<node> ans; //因为矛盾优先级比不唯一高,所以需要记录所有可能答案
//处理Yes询问
ll l=Yes[1].l,r=Yes[1].r;
for(int i=2;i<=pYes;i++){
if(Yes[i].l>r){
cheated=1;
}else{
l=Yes[i].l;
r=min(r,Yes[i].r);
}
}
if(pYes==0){ //如果没有Yes询问,所有叶子都有可能
l=1LL<<(h-1);
r=(1LL<<(h))-1;
}
//处理No询问
for(int i=1;i<=pNo;i++){
if(i<pNo&&No[i].r>=No[i+1].l){
No[i+1].l=No[i].l;
No[i+1].r=max(No[i].r,No[i+1].r);
continue;
}
if(No[i].r<l){
continue;
}else{
if(No[i].l>l){
//这里要特别注意,不能越过r
ans.insert(node(l,min(r,No[i].l-1) ));
}
l=No[i].r+1;
if(l>r)break;
}
}
//补上可能漏掉的区间
if(l<=r)ans.insert(node(l,r));
for(int i=1;i<=pYes;i++){
set<node>::iterator it=ans.lower_bound(Yes[i]);
bool ok=0;
if(it!=ans.end()&&it->l<=Yes[i].r){
ok=1;
}
if(it!=ans.begin()){
it--;
if(it->r>=Yes[i].l)ok=1;
}
if(!ok){
cheated=1;break;
}
}
ll re;
if(ans.size()==1&&ans.begin()->l==ans.begin()->r){
re=ans.begin()->l;
}else{
mulsol=1;
}
if(ans.size()==0)cheated=1;
if(cheated){
cout<<"Game cheated!"<<endl;
}else if(mulsol){
cout<<"Data not sufficient!"<<endl;
}else{
cout<<re<<endl;
}
return 0;
}
一个字符串,包含小写字母,有q次操作,每次操作升序或者降序排序一个区间。求操作完后的串。
对26个字符分别建线段树,维护区间有多少该字符。维护方法是使用类似计数排序的方法,如升序排序,查询区间中有多少'a',放到最前面,再查询bcd...
#include <bits/stdc++.h>
using namespace std;
#define ll long long
struct node{
int l,r;
int val;
int lazy; //
}tree[26][400010];
char str[100010];
void push_up(int which,int n){
tree[which][n].val = tree[which][n<<1].val+tree[which][(n<<1)|1].val;
}
void push_down(int which,int n){
int val=tree[which][n].val;
if(tree[which][n].l==tree[which][n].r)return;
if(tree[which][n].lazy==-1){
int llen=tree[which][n<<1].r-tree[which][n<<1].l+1;
if(val>llen){
tree[which][n<<1].val=llen;
tree[which][(n<<1)|1].val=val-llen;
}else{
tree[which][n<<1].val=val;
tree[which][(n<<1)|1].val=0;
}
}
if(tree[which][n].lazy==1){
int rlen=tree[which][(n<<1)|1].r-tree[which][(n<<1)|1].l+1;
if(val>rlen){
tree[which][(n<<1)|1].val=rlen;
tree[which][n<<1].val=val-rlen;
}else{
tree[which][(n<<1)|1].val=val;
tree[which][n<<1].val=0;
}
}
tree[which][n<<1].lazy=tree[which][n].lazy;
tree[which][(n<<1)|1].lazy=tree[which][n].lazy;
tree[which][n].lazy=0;
}
void build_tree(int which,int n,int l,int r){
tree[which][n].l=l; tree[which][n].r=r;
if(l==r){
if(str[l]==which+'a'){
tree[which][n].val=1;
}
return;
}
int mid=(l+r)>>1;
build_tree(which,n<<1,l,mid);
build_tree(which,(n<<1)|1,mid+1,r);
push_up(which,n);
}
int query(int which,int n,int l,int r){
if(tree[which][n].l==l&&tree[which][n].r==r){
return tree[which][n].val;
}
int mid=(tree[which][n].l+tree[which][n].r)>>1;
if(tree[which][n].lazy){
push_down(which,n);
}
if(r<=mid){
return query(which,n<<1,l,r);
}else{
if(l>mid){
return query(which,(n<<1)|1,l,r);
}else{
return query(which,n<<1,l,mid)+
query(which,(n<<1)|1,mid+1,r);
}
}
}
void update(int which,int n,int l,int r,int val,int lr){
if(l>r)return;
if(tree[which][n].l==l&&tree[which][n].r==r){
tree[which][n].lazy=lr;
tree[which][n].val=val;
return;
}
int mid=(tree[which][n].l+tree[which][n].r)>>1;
if(tree[which][n].lazy){
push_down(which,n);
}
if(r<=mid){
update(which,n<<1,l,r,val,lr);
}else{
if(l>mid){
update(which,(n<<1)|1,l,r,val,lr);
}else{
if(lr==-1){ //升序
int lval=min(val,tree[which][n<<1].r-l+1);
int rval=val-lval;
update(which,n<<1,l,mid,lval,lr);
update(which,(n<<1)|1,mid+1,r,rval,lr);
}else{ //降序
int rval=min(val,r-tree[which][(n<<1)|1].l+1);
int lval=val-rval;
update(which,(n<<1)|1,mid+1,r,rval,lr);
update(which,n<<1,l,mid,lval,lr);
}
}
}
push_up(which,n);
}
int main(){
int n,q;
cin>>n>>q;
scanf("%s",str+1);
for(int i=0;i<26;i++){
build_tree(i,1,1,n);
}
for(int i=1;i<=q;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
int cnt[26];
for(int ch=0;ch<26;ch++){
cnt[ch]=query(ch,1,x,y);
}
int l=x,r=y;
if(z==0){ //降序
for(int ch=0;ch<26;ch++){
if(cnt[ch]==0)continue;
update(ch,1,r-cnt[ch]+1,r,cnt[ch],1);
update(ch,1,r+1,y,0,1);
r-=cnt[ch];
update(ch,1,x,r,0,1);
}
}else{ //升序
for(int ch=0;ch<26;ch++){
if(cnt[ch]==0)continue;
update(ch,1,l,l+cnt[ch]-1,cnt[ch],-1);
update(ch,1,x,l-1,0,-1);
l+=cnt[ch];
update(ch,1,l,y,0,-1);
}
}
}
for(int i=1;i<=n;i++){
for(int ch=0;ch<26;ch++){
if(query(ch,1,i,i)){
str[i]=ch+'a';
break;
}
}
}
printf("%s\n",str+1);
return 0;
}