Zbox loves ants
题目描述
从小热爱生物的Zbox开始观察蚂蚁了.她有一根长度为m的绳子,在最初的时刻,上面分布着n只蚂蚁,她发现,每一只蚂蚁在最初都可能选择任意一个方向爬,爬行的速度始终为1,当有两只蚂蚁相遇时,它们会各自调转方向,以原有的速度继续爬行.Zbox知道,每只蚂蚁随意选择一种方向一共有2^n种方案,每一种方案都存在一个时间使得最后一只蚂蚁恰好爬离绳子.现在她想问问你,每一个这样的时间对应的方案数分别是多少.
输入描述
第一行一个整数n,表示蚂蚁数量.
第二行输入为4个32位无符号整数x,a_0,b_0,c_0用于生成(伪)随机数.
蚂蚁的初始位置以及绳子的长度的生成方式,我们将以文件形式下发并且有使用该数据生成方式的有正确性保证的代码在选手目录下(包含cpp和pascal两个版本).
代码中m表示绳子的长度,数组A最终将储存编号为1到n的蚂蚁的初始位置到绳子左端点的距离,且保证A数组中的数单调递增.
数据保证所有的蚂蚁到绳子两端的距离(共2n个数)都不相同.
数据规模
对于20%的数据n<=10
对于40%的数据n<=10^3
对于60%的数据n<=10^5
对于100%的数据2<=n<=5*10^6;0<=A_i,m<2^63;1<=x,a_0,b_0,c_0<2^31
SOL:
我们可以注意到,两个蚂蚁相遇后各自调转方向等价于没有转向。那么我们枚举最后出去的蚂蚁的时间,统计方案数就好了。
#include<bits/stdc++.h> using namespace std; #define mo 1000000007 typedef long long ll; const int maxn=5000000; int n,x,a,b,c; ll m,A[maxn+5],B[maxn+5],C[maxn+5]; inline int myrand(){ x=(1ll*a*x+b)%c; return x; } struct Node{ ll x; int b; inline bool operator <(const Node&XX)const{ return x<XX.x; } Node(){} Node(ll X,int Y):x(X),b(Y){} }AA[maxn<<1|7]; inline void Init(){ cin>>n; cin>>x>>a>>b>>c; for(int i=1;i<=(n+1)/2;i++)B[i]=B[i-1]+myrand()+5; m=B[(n+1)/2]<<1|1; for(int i=1;i<=n-(n+1)/2;i++)C[i]=m-(myrand()%(B[i]-B[i-1]-1)+B[i-1]+1); reverse(C+1,C+(n-(n+1)/2)+1); for(int i=1;i<=(n+1)/2;i++)A[i]=B[i]; for(int i=1;i<=n-(n+1)/2;i++)A[i+(n+1)/2]=C[i]; } ll ans,ooo,ppp; int tot=0,tp1=1,tp2; bool No[maxn|77]; int main(){ freopen("ants.in","r",stdin); freopen("ants.out","w",stdout); Init(); tp2=n; while (tp1<=n&&tp2) { if (A[tp1]+A[tp2]<m) AA[tot].x=A[tp1],AA[tot].b=tp1++,tot++; else AA[tot].x=m-A[tp2],AA[tot].b=tp2--,tot++; } while (tp1<=n) AA[tot].x=A[tp1],AA[tot].b=tp1++,tot++; while (tp2) AA[tot].x=m-A[tp2],AA[tot].b=tp2--,tot++; ooo=n; ppp=1; for (int i=0;i<(n<<1);i++) { ans+=ooo>1?0:1ll*ppp*(AA[i].x%mo)%mo; ans%=mo; if (!No[AA[i].b]) { No[AA[i].b]=1,ooo--;} else (ppp<<=1)%=mo; } cout<<ans<<endl; // cout<<(522833677ll+522833676ll*2+2*m)%mo; return 0; }