当前位置: 首页 > 工具软件 > Baton > 使用案例 >

hdu 5565 Clarke and baton

程冥夜
2023-12-01

传送门:
http://acm.hdu.edu.cn/showproblem.php?pid=5565

题意:
一堆数字,每次最大的数减1,如果最大的有多个,则取序号最小的,问最终序列?

其实这道题目还是蛮有意思的,一想肯定复杂度和q有关,而且肯定要从值入手,那么想每次减少的值肯定是从目前的和从上一个值降下来的取序号最小的,那么很显然就可以开两个vector来实现了!

这道题真的是醉了,交c++才能过,
交g++会爆内存,而且c++居然不识别bits/stdc++
struct居然可以开1e7,简直神奇,哈哈哈!!一般需要大的时候就开vector和struct!

code:

#include <stack>
#include <cstdio>
#include <list>
#include <cassert>
#include <set>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <queue>
#include <functional>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <string>
#include <map>
#include <cmath>
using namespace std;
const int maxn=1e7+10;
struct Queue{
    vector<int>g;
    int pos;
    int front(){
        return g[pos];
    }
    void pop(){
        pos++;
    }
    int empty(){
        return pos==g.size();
    }
    void push(int n){
        g.push_back(n); 
    }
}ini[maxn],rev[maxn];
int t,n,q;int ans[maxn],a[maxn];
long long seed;
int rand(int l, int r) {
    static long long mo=1e9+7, g=78125;
    return l+((seed*=g)%=mo)%(r-l+1);
}
void init(){
  int sum=rand(q, 10000000);
  for(int i=1; i<=n; i++) {
    a[i]=rand(0, sum/(n-i+1));
    sum-=a[i];
  }
  a[rand(1, n)]+=sum;
  for(int i=0;i<maxn;i++){
    ini[i].g.clear();ini[i].pos=0;
    rev[i].g.clear();rev[i].pos=0;
  }
}
void update(Queue &cur,int pos){
    int now=cur.front();cur.pop();
    rev[pos-1].push(now);
    ans[now]=pos-1;
}
int main(){
    cin>>t;
    while(t--){
        scanf("%d%d%d",&n,&q,&seed);
        init();
        for(int i=1;i<=n;i++){
            ini[a[i]].push(i);
            ans[i]=a[i];
        }int pos=maxn-1;
        while(q--){
            while(pos>=1&&ini[pos].empty()&&(rev[pos].empty())) pos--;
            if(pos==0) break;
            if(!ini[pos].empty()&&(!rev[pos].empty())){
                int inow=ini[pos].front();int rnow=rev[pos].front();
                if(inow<rnow){
                    update(ini[pos],pos);
                }
                else update(rev[pos],pos);
            }
            else if(ini[pos].empty()) update(rev[pos],pos);
            else if(rev[pos].empty()) update(ini[pos],pos);
        }int anss=0;
        for(int i=1;i<=n;i++){
            anss^=(ans[i]+i);
        }
        printf("%d\n",anss);
    }
}

当然上面的是标解,这题还有更优的解法!!!

就是考虑终态,肯定是减小到某个数停止了,其余的都不动,那么我们二分去查找那个数就ok了,还会有一些零散的数是应该减1的!!
注意在套我自己的那个二分板的时候,一定不要更改二分的写法,要去改那个判断条件的写法,不然就会出问题的!!

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7+10;
long long seed;int t,n,q;int a[maxn];
int rand(int l, int r) {
    static long long mo=1e9+7, g=78125;
    return l+((seed*=g)%=mo)%(r-l+1);
}
void init(){
  int sum=rand(q, 10000000);
  for(int i=1; i<=n; i++) {
    a[i]=rand(0, sum/(n-i+1));
    sum-=a[i];
  }
  a[rand(1, n)]+=sum;
}
bool check(int x){
    int k=0;
    for(int i=1;i<=n;i++){
        if(a[i]<x)continue;
        k+=a[i]-x;
    }
    if(k>=q) return 0;
    return 1;
}
int main(){
    cin>>t;
    while(t--){
        scanf("%d%d%d",&n,&q,&seed);
        init();
        int l=-1;int r=(int)1e7+1;int mid;
        while(l+1<r){
            mid=(l+r)/2;
            if(check(mid)) r=mid;
            else l=mid;
        }l=r;
        for(int i=1;i<=n;i++){
            if(a[i]<l) continue;
            q-=a[i]-l;
        }int ans=0;
        for(int i=1;i<=n;i++){
            if(a[i]<l)  ans^=(a[i]+i);
            else{
                if(q==0) ans^=l+i;
                else ans^=l-1+i,q--;
            }
        }
        printf("%d\n",ans);
    }
}
 类似资料:

相关阅读

相关文章

相关问答