2016陕西省赛 Rui and her functions
题目链接:http://oj.xjtuacm.com/contest/4/problem/35/
题目大意:每组数据给定$n$和$m$,定义$f_i(x)=(a_ib_i^{x_i}+c_i)\%d_i$,数据满足$x_i$不严格递增,问对于每个$f_i(x)$取最小值的时候,$x_i$是多少.
分治
注意到$x_i$不严格递增,直接暴力的话最差复杂度为$O(m^2)$,极端数据为$x_0=x_1=...=x_{n-1}=1$.
为了避免这种情况,采取分治策略:先计算$x_{mid}$,使得$mid$左边部分有了较低的上界,复杂度大大降低.
代码如下:
1 #include <cstdio> 2 #define N 100005 3 using namespace std; 4 typedef long long ll; 5 ll n,m,x,T,a[N],b[N],c[N],d[N],ans[N]; 6 ll mul(ll a,ll b,ll p){return (a*b)%p;} 7 ll add(ll a,ll b,ll p){return (a+b)%p;} 8 ll pow(ll a,ll n,ll p){ 9 ll r=1; 10 while(n){ 11 if(n&1)r=mul(r,a,p); 12 a=mul(a,a,p); 13 n>>=1; 14 } 15 return r; 16 } 17 ll getx(ll a,ll b,ll c,ll d,ll l,ll r){ 18 ll x=l; 19 ll temp=mul(a,pow(b,x,d),d); 20 ll minn=add(temp,c,d); 21 for(ll i=x+1;i<=r;++i){ 22 if(minn==0)break; 23 temp=mul(temp,b,d); 24 if(add(temp,c,d)<minn){ 25 minn=add(temp,c,d); 26 x=i; 27 } 28 } 29 return x; 30 } 31 void solve(ll il,ll ir,ll xl,ll xr){ 32 if(il>ir)return; 33 ll mid=(il+ir)/2; 34 ans[mid]=getx(a[mid],b[mid],c[mid],d[mid],xl,xr); 35 solve(il,mid-1,xl,ans[mid]); 36 solve(mid+1,ir,ans[mid],xr); 37 } 38 int main(void){ 39 while(~scanf("%lld%lld",&n,&m)){ 40 T++; 41 for(int i=0;i<n;++i) 42 scanf("%lld%lld%lld%lld",&a[i],&b[i],&c[i],&d[i]); 43 solve(0,n-1,1,m); 44 printf("Case #%lld ",T); 45 for(int i=0;i<n;++i) 46 printf("%lld ",ans[i]); 47 } 48 }