您的位置:首页 > 其它

poj 1006 中国剩余定理模板

2017-08-05 19:13 645 查看
传送门

问题描述:

     人自出生起就有体力,情感和智力三个生理周期,分别为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);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: