2016陕西省省赛 ACM Rui and her functions B 二分

Rui and her functions

发布时间: 2017年3月27日 15:45   最后更新: 2017年3月28日 12:43   时间限制: 10000ms   内存限制: 256M

描述

Rui is magnificently gifted. Why does she not play with me tonight? Oh, she is obsessing

about n functions with n quartette of positive coefficients, denoted by ai,bi,ci,di(1in)

respectively.

The i-th function fi is defined as fi(x)=(ai×bxi+ci)moddi. She asked Doc to find the

smallest xi in [1,m] for each function such that fi(xi) achieves the minimum of fi in [1,m].

That is say: fi(xi)=min{x[1,m]|fi(x)=mint[1,m]{fi(t)}}.

However n is large and Doc told her that possible xi for each function is unique (and Rui

is unique as well), and x1x2x3xn (and that is as amazing as Rui).

Now she needs to find xi by herself.

输入

There are several test cases (no more than 64) and please process till EOF.
The first line in each case contains two integers n and m1n,m100000. Each of the
following n lines contains four integers ai,bi,ci,di respectively, where 0<ai,bi,cidi109.

输出

For each test case, print first the identifier of the test case, then n lines follow. The i-th
line contains the number xi for i-th function fi.

样例输入1  复制
3 5
373911025 1525760443 652804587 1767005941
120055457 159868670 59429374 196292251
1200581 955324 141748 2705431
样例输出1
Case #1
1
2
4
总感觉这道题目描述的不好,或者是我一直没有理解好。这个题目说的是每个f函数,x在[1,m]区间上的取值,f(x)都是不同的

然后让你求出每个f(x)取得最小值情况下的x,这个题有点特殊,数据保证了x1<=x2<=...<=xn我觉得这个数据不是随机出的,而是故意满足了这个条件。

由于x的单调性,我们可以这样考虑,如果我们先求出了下标n/2对应的函数对应的x,那么对于所有下标小于n/2的f函数,就只需要考虑[1,x[n/2]]之内的数就可以了,因为这些函数

的最小值对应的x不可能大于x[n/2]了,这样的话,再判断左右两边的f函数对应的x时,要检索的范围就缩小了一半。

因此,上来就用二分

void solve(int lp,int rp,int l,int r)//左闭右开 
表示的是要求区间[lp,rp)内的函数对应的最小值,这些最小值的取值再[l,r)里面

那么我们先求pos = (lp+rp)/2位置的函数,假设求得了x的下标为under

那么下一次分治的时候,

左边的区间变成了[lp,pos) 定义域变成了[l,under+1)因为x之间可以相等

右边的函数下标区间变成了[pos+1,rp),定义域变成了[under,r)


注意!!!!!

快速幂不能一直使用,否则会TTTTTTT,555555555我在这地方T了20次!!!归根到底还是菜啊

解决方案是,在定义域内检索最小值的时候,先用快速幂求出第一项,然后递归得到以后的

#include 
#include  
#include 
using namespace std;
typedef long long LL;
const int MAX = 100009;
const LL INF = 1e18;
LL a[MAX],b[MAX],c[MAX],d[MAX],ans[MAX];
int n,m;
LL mod_pow(LL x,LL n,LL mod)
{
	LL res = 1;
	while(n > 0)
	{
		if(n&1) res = res*x%mod;
		x = x*x%mod;
		n >>= 1;
	}
	return res;
}
/* 
LL calc(int x,int i)
{
	LL mod = d[i];
	return ((a[i]%mod*mod_pow(b[i],x,mod))%mod + c[i]%mod) % mod;
}
*/
void solve(int lp,int rp,int l,int r)//左闭右开 
{
	//返回中间位置
	if(lp >= rp) return ;
	int pos = (lp + rp) / 2;
	LL sm = INF;
	int under;
	int lb = l;
	int up = r;
	LL tmp = mod_pow(b[pos],lb,d[pos]);
	for(int i = lb;i < up;i++){
		if(i != lb) tmp = tmp*b[pos]%d[pos];
		LL cc = ((a[pos]%d[pos]*tmp)%d[pos] + c[pos]%d[pos]) % d[pos];
		if(sm > cc)
			sm = cc,under = i;
	}
  	ans[pos] = under;
	solve(lp,pos,l,under+1);
	solve(pos+1,rp,under,r);
}
main()
{
	int cas = 0;
	while(~scanf("%d%d",&n,&m))
	{
		for(int i = 0;i < n;i++)
			scanf("%lld%lld%lld%lld",a+i,b+i,c+i,d+i);
		LL sm = INF;
		printf("Case #%d\n",++cas);
		solve(0,n,1,m+1);
		for(int i = 0;i < n;i++) printf("%lld\n",ans[i]);
	} 
	return 0;
 } 
 /*
1 1
373911025 1525760443 652804587 1767005941
 */



你可能感兴趣的:(ACM-ICPC训练题解)