Clarke and baton
Accepts: 1
Submissions: 126
Time Limit: 12000/6000 MS (Java/Others)
Memory Limit: 524288/524288 K (Java/Others)
问题描述
克拉克是一名人格分裂患者。某一天,克拉克fork出了n个自己,序号从1到n。 他们准备玩一个减肥游戏,每一个克拉克都有一个体重a[i]。他们有一个接力棒,这个接力棒任何时刻总是在最重的克拉克(如果重量相同则在序号最小的)的手中,得到这个接力棒的克拉克需要减肥,使得体重变成a[i]−1,随后接力棒便传递到下一个人(可以是自己)的手中。 现在克拉克们知道接力棒一共被传递过q次,他们想知道最终每一个克拉克的体重分别是多少。
输入描述
第一行一个整数T(1≤T≤10),表示数据的组数。 每组数据只有一行三个整数n,q,seed(1≤n,q≤10000000,∑n≤20000000,1≤seed≤109+6),分别表示克拉克的个数、接力棒传递次数还有一个随机种子。 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;
输出描述
每组数据输出一行一个数,这个数ans是这样得到的。 假设b[i]是最终克拉克们的体重,则ans=(b[1]+1)xor(b[2]+2)xor...xor(b[n]+n),其中xor是异或操作。
输入样例
1 3 2 1
输出样例
20303
Hint
首先a[1]=20701,a[2]=31075,a[3]=26351 第一次接力棒在2号克拉克手上,所以a[2]=31074。 第二次接力棒在2号克拉克手上,所以a[2]=31073。 所以答案等于(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 0x3f3f3f3f ll 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 zsc freopen("input.txt","r",stdin); #endif int 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 15000005 ll 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 zsc freopen("input.txt","r",stdin); #endif int 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; }