hdu4790Just Random

来源:互联网 发布:苹果手机微信数据恢复 编辑:程序博客网 时间:2024/06/05 09:06

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4790

题意:给定两个区间[a,b]和[c,d]和两个数p,m,0<=m<p。求多少对数对x,y满足a<=x<=b,c<=y<=d并且(x+y)%p=m。

分析:因为数据范围都是10^9,如果直接暴力是不行的。我们先用容斥原理将x和y的范围变成[0,a']和[0,b']且a'<b'的这种,那么我们将x+y当x轴x当y轴画出这个可行区间可以观察到一个平行四边形的可行区间。令x+y=p*k+m,k的取值为非负整数。那么我们根据不同的k的取值会发现会将可行区间变成3段,首尾两段是p为等差的等差数列,中间是一段都为a'+1的的值。

代码:

#include<map>#include<set>#include<cmath>#include<queue>#include<bitset>#include<math.h>#include<vector>#include<string>#include<stdio.h>#include<cstring>#include<iostream>#include<algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int N=40010;const int mod=100000000;const int MOD1=1000000007;const int MOD2=1000000009;const double EPS=0.00000001;typedef long long ll;const ll MOD=1000000007;const int MAX=2000000010;const ll INF=1ll<<55;const double pi=acos(-1.0);typedef double db;typedef unsigned long long ull;ll gcd(ll a,ll b) {    return b==0 ? a:gcd(b,a%b);}ll suan(ll s,ll t,ll x) {    return (s+t)*x/2;}ll get(ll a,ll b,ll p,ll m) {    ll ret=0;    if (a>b) swap(a,b);    if (a<0||a+b<m) return 0;    ll k1,k2,k=(a+b-m)/p;    if (a<m) k1=-1;    else k1=(a-m)/p;    if (b<m) k2=-1;    else k2=(b-m)/p;    if (k1>=0&&a>=m) ret=suan(m+1,p*k1+m+1,k1+1);    if (k2>k1) ret+=(k2-k1)*(a+1);    if (k>k2) ret+=suan(a+b+1-p*(k2+1)-m,a+b+1-p*k-m,k-k2);    return ret;}int main(){    int i,a,b,c,d,p,m,t,ca;    ll P,Q,G;    scanf("%d", &t);    for (ca=1;ca<=t;ca++) {        scanf("%d%d%d%d%d%d", &a, &b, &c, &d, &p, &m);        P=get(b,d,p,m)-get(a-1,d,p,m)-get(b,c-1,p,m)+get(a-1,c-1,p,m);        Q=1ll*(b-a+1)*(d-c+1);        G=gcd(P,Q);        printf("Case #%d: %I64d/%I64d\n", ca, P/G, Q/G);    }    return 0;}



0 0
原创粉丝点击