1. 程式人生 > >NOI 十連測 Zbox loves ants

NOI 十連測 Zbox loves ants

版本 UC 分布 += int AC ppp sca pre

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

NOI 十連測 Zbox loves ants