您的位置:首页 > 其它

BestCoder Round #62 (div.2)-Clarke and baton(二分搜索)

2015-11-15 00:38 363 查看

Clarke and baton

  Accepts: 1  Submissions: 126 Time Limit: 12000/6000 MS (Java/Others)  Memory Limit: 524288/524288 K (Java/Others)问题描述
克拉克是一名人格分裂患者。某一天,克拉克fork出了nn个自己,序号从11到nn。
他们准备玩一个减肥游戏,每一个克拉克都有一个体重a[i]a[i]。他们有一个接力棒,这个接力棒任何时刻总是在最重的克拉克(如果重量相同则在序号最小的)的手中,得到这个接力棒的克拉克需要减肥,使得体重变成a[i]-1a[i]−1,随后接力棒便传递到下一个人(可以是自己)的手中。
现在克拉克们知道接力棒一共被传递过qq次,他们想知道最终每一个克拉克的体重分别是多少。
输入描述
第一行一个整数T(1 \le T \le 10)T(1≤T≤10),表示数据的组数。
每组数据只有一行三个整数n, q, seed(1 \le n, q \le 10000000, \sum n \le 20000000, 1 \le seed \le 10^9+6)n,q,seed(1≤n,q≤10000000,∑n≤20000000,1≤seed≤10​9​​+6),分别表示克拉克的个数、接力棒传递次数还有一个随机种子。
a[i]a[i]按照以下规则生成:

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);
}

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;
输出描述
每组数据输出一行一个数,这个数ansans是这样得到的。
假设b[i]b[i]是最终克拉克们的体重,则ans=(b[1]+1) xor (b[2]+2) xor ... xor (b
+n)ans=(b[1]+1)xor(b[2]+2)xor...xor(b[n]+n),其中xorxor是异或操作。
输入样例
1
3 2 1
输出样例
20303
Hint
首先a[1]=20701, a[2]=31075, a[3]=26351a[1]=20701,a[2]=31075,a[3]=26351
第一次接力棒在22号克拉克手上,所以a[2]=31074a[2]=31074。
第二次接力棒在22号克拉克手上,所以a[2]=31073a[2]=31073。
所以答案等于(20701+1)xor(31073+2)xor(26351+3)=20303(20701+1)xor(31073+2)xor(26351+3)=20303
思路:
这题非常的巧妙,一开始就想到了用优先队列来做,结果超时了。不过也是理所当然的事,不可能给你水过的,肯定卡你的时间。最后看了看别人的代码,看了好一会儿才明白他的原理,发现真的是巧妙啊,做出这题的人思维真是非常活跃,ORZ了。最后还是说说思路吧!这题其实就是要找到一个0-max的值中那个中间数值是能让输入的值减少q的,如果大了,就继续二分,直到L>R就停止。但是还是有一个bug,那就是当几个数非常接近时,就是你减一次,它减一次,它它再减一次。。。这样直到减完为止,这样就会出现一些减了一,一些没减1的情况,所以还要一个ans来记录有多少个是减了一的,其实它们不应该减的,再加回来就OK了。
AC代码:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<string>#include<cmath>#include<queue>#include<vector>typedef long long ll;using namespace std;#define T 15000005#define inf 0x3f3f3f3fll seed;ll a[T];int n,q,val,ans;int rand(int l, int r) {static long long mo=1e9+7, g=78125;return l+((seed*=g)%=mo)%(r-l+1);}//判断mid的值时有多少个是可以减去的int jugde(int x){int sum=0;for(int i=1;i<=n;++i){if(a[i]>x){sum+=a[i]-x;}}return sum;}//二分符合减去q个数的那个mid值void BS(int L,int R){int now;ans=inf;do{int mid = (L+R)>>1;now = jugde(mid);if(now>=q){val = mid,L = mid + 1;}else{R = mid - 1;}//判断是否出现有多个符合mid值却不需要减的数有多少个if(now>=q)ans = min(ans,now-q);}while(L<=R);}void solve(){int maxn=0,i,j;for(i=1;i<=n;++i){maxn = max((ll)maxn,a[i]);}BS(0,maxn);//更新需要减少的数,还包括了不要减的数for(i=n;i;--i)if(a[i]>val)a[i]=val;//变回不用减的ans个数for(i=n;i;--i)if(ans>0&&a[i]==val)ans--,a[i]++;//计算总值int sum = 0;for(i=1;i<=n;++i)sum^=(a[i]+i);printf("%d\n",sum);}int main(){#ifdef zscfreopen("input.txt","r",stdin);#endifint N;scanf("%d",&N);while(N--){scanf("%d%d%lld",&n,&q,&seed);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;solve();}return 0;}
TLE代码:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<string>#include<cmath>#include<queue>#include<vector>typedef long long ll;using namespace std;#define T 15000005ll seed;ll a[T];struct node{ll x,num;friend bool operator<(const node& a,const node& b){return a.x<b.x;}}v;int rand(int l, int r) {static long long mo=1e9+7, g=78125;return l+((seed*=g)%=mo)%(r-l+1);}int main(){#ifdef zscfreopen("input.txt","r",stdin);#endifint N;scanf("%d",&N);while(N--){int n,q;scanf("%d%d%lld",&n,&q,&seed);priority_queue<node> t;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=1;i<=n;++i){v.x = a[i],v.num = i;t.push(v);}while(q--){v=t.top();t.pop();/*printf("%d\n",v.x);*/v.x--;t.push(v);}node s = t.top();t.pop();ll ss=s.x+s.num;while(!t.empty()){s = t.top(),t.pop();ss^=(s.x+s.num);}printf("%lld\n",ss);}return 0;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bc 二分 搜索