poj 1006 中国剩余定理模板

传送门

问题描述:

     人自出生起就有体力,情感和智力三个生理周期,分别为23,28和33天。一个周期内有一天为峰值,在这一天,人在对应的方面(体力,情感或智力)表现最好。通常这三个周期的峰值不会是同一天。现在给出三个日期,分别对应于体力,情感,智力出现峰值的日期。然后再给出一个起始日期,要求从这一天开始,算出最少再过多少天后三个峰值同时出现。

分析:

因为23 = 23

28 = 2*2*7

33 = 3*11

满足两两互质关系,所以直接套模板就好了

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;

#define pi acos(-1)
#define endl '\n'
#define srand() srand(time(0));
#define me(x,y) memset(x,y,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
#define close() ios::sync_with_stdio(0); cin.tie(0);
#define FOR(x,n,i) for(int i=x;i<=n;i++)
#define FOr(x,n,i) for(int i=x;i<n;i++)
#define W while
#define sgn(x) ((x) < 0 ? -1 : (x) > 0)
#define bug printf("***********\n");
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL LINF=1e18+7;
const int dx[]= {-1,0,1,0,1,-1,-1,1};
const int dy[]= {0,1,0,-1,-1,1,-1,1};
const int maxn=2005;
const int maxx=1e5+100;
const double EPS=1e-7;
const int mod=998244353;
template<class T>inline T min(T a,T b,T c)
{
	return min(min(a,b),c);
}
template<class T>inline T max(T a,T b,T c)
{
	return max(max(a,b),c);
}
template<class T>inline T min(T a,T b,T c,T d)
{
	return min(min(a,b),min(c,d));
}
template<class T>inline T max(T a,T b,T c,T d)
{
	return max(max(a,b),max(c,d));
}
inline LL Scan()
{
	LL Res=0,ch,Flag=0;
	if((ch=getchar())=='-')Flag=1;
	else if(ch>='0' && ch<='9')Res=ch-'0';
	while((ch=getchar())>='0'&&ch<='9')Res=Res*10+ch-'0';
	return Flag ? -Res : Res;
}

typedef pair<LL, LL> PLL;
LL a[100000], b[100000], m[100000],d;
LL gcd(LL a, LL b)
{
	return b ? gcd(b, a%b) : a;
}
void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d)
{
	if (!b)
	{
		d = a, x = 1, y = 0;
	}
	else
	{
		ex_gcd(b, a % b, y, x, d);
		y -= x * (a / b);
	}
}
LL inv(LL t, LL p) //如果不存在,返回-1
{
	LL d, x, y;
	ex_gcd(t, p, x, y, d);
	return d == 1 ? (x % p + p) % p : -1;
}
PLL linear(LL A[], LL B[], LL M[], int n)  //求解A[i]x = B[i] (mod M[i]),总共n个线性方程组
{
	LL x = 0, m = 1;
	for(int i = 0; i < n; i ++)
	{
		LL a = A[i] * m, b = B[i] - A[i]*x, d = gcd(M[i], a);
		if(b % d != 0)  return PLL(0, -1);//答案,不存在,返回-1
		LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
		x = x + m*t;
		m *= M[i]/d;
	}
	x = (x % m + m ) % m;
	return PLL(x, m);//返回的x就是答案,m是最后的lcm值
}
//X==b[i] (mod m[i])
int main()
{
//	freopen( "in.txt" , "r" , stdin );
	LL mod=21252;
	m[0]=23,m[1]=28,m[2]=33;
	int n=3,cas=1;
	while(~scanf("%lld%lld%lld%lld",&b[0],&b[1],&b[2],&d))
	{
		for(int i=0;i<n;i++)
			a[i]=1;
 		if(b[0]==-1&&b[1]==-1&&b[2]==-1) break;
		PLL ans=linear(a,b,m,n);
		LL val=ans.first-d;
		val=(val%mod+mod)%mod;
		if(val==0) val=mod;
		printf("Case %d: the next triple peak occurs in %lld days.\n",cas++,val);
	}
}


#include<cstdio>  
typedef long long LL;  
const int N = 100000 + 5;  
void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d)  
{  
    if (!b)  
    {  
        d = a, x = 1, y = 0;  
    }  
    else  
    {  
        ex_gcd(b, a % b, y, x, d);  
        y -= x * (a / b);  
    }  
}  
LL inv(LL t, LL p) //如果不存在,返回-1  
{  
    LL d, x, y;  
    ex_gcd(t, p, x, y, d);  
    return d == 1 ? (x % p + p) % p : -1;  
}  
LL mult(LL a, LL k, LL m)
{
    LL res = 0;
    while(k)
	{
        if(k & 1LL)
            res = (res + a) % m;
        k >>= 1;
        a = (a << 1) % m;
    }
    return res;
}
LL china(int n, LL *a, LL *m) //中国剩余定理  
{  
    LL M = 1, ret = 0;  
    for(int i = 0; i < n; i ++) M *= m[i];  
    for(int i = 0; i < n; i ++)  
    {  
        LL w = M / m[i];  
        ret = (ret + mult(w,inv(w, m[i]) * a[i],M)) % M;  
    }  
    return (ret + M) % M;  
}  
int main()  
{  
    LL p[3], r[3], d, ans, MOD = 21252;  
    int cas = 0;  
    p[0] = 23;  
    p[1] = 28;  
    p[2] = 33;  
    while(~scanf("%I64d%I64d%I64d%I64d", &r[0], &r[1], &r[2], &d) && (~r[0] || ~r[1] || ~r[2] || ~d))  
    {  
        ans = ((china(3, r, p) - d) % MOD + MOD) % MOD;  
        printf("Case %d: the next triple peak occurs in %I64d days.\n", ++cas, ans ? ans : 21252);  
    }  
  
}  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值