hdu 5565 Clarke and baton

18 篇文章 0 订阅
12 篇文章 0 订阅

传送门:
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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值