题目链接:传送门
题目大意:给你a, b, c, d, p and m(0 <= a <= b <= 109, 0 <=c <= d <= 109, 0 <= m < p <= 109).让你从 [a,
b] 中取出一个x,从[c, d] 中取出一个y,使得(x+y)(mod p)=m,求一共有多少种可能。
看见题目就想到了用构造的想法,讲解构造成二维坐标系,x+y=k*p+m是一条线,求这条线与构造的矩形(由点组成)一共有几个交点,这个矩阵也是有一定的规律的,虽然说数据量很大,但是其实就是三个数列,一个递增的一个相等的一个递减的,最后求出这三个数列的和即可。
根据上面的abcd所组成的矩形,其l1l2l3l4其实是一个递增的数列,直到等于b -a 递减也是一个道理。
很多细节处理的难点,本来说十分钟敲好的题目花了两小时+ 坑队友了,其实是这样的,k1 k2 k3 k4 把这个图形分为三个部分,原来我都是一遍处理,k2就是k2,其实这样就出现很多难点,我们这样来想,k1k2在算第一段的时候算一次,k2k3在算第二段的时候算一次,k3k4在算第三段的时候算一次。这样就不会出现错误,还有就是最开始的时候,构造最初,我们把躺着的矩形也立起来,这样减少了要考虑的情况,使运算减少。
贴代码:
#include<queue> #include<map> #include<set> #include<vector> #include<stack> #include<ctime> #include<stdio.h> #include<cstdlib> #include<functional> #include<cmath> using namespace std; #define PI acos(-1.0) #define MAXN 110 #define eps 1e-7 #define INF 0x7FFFFFFF #define seed 131 #define ll long long #define ull unsigned ll #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 ll gcd (ll a,ll b) { if(b==0) return a; else return gcd(b,a%b); } int main() { ll a,b,c,d,p,m; int T; scanf("%d",&T); for(int ii=1; ii<=T; ii++) { scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&p,&m); ll ans=0; if(b-a > d-c) { ll tem; tem=a;a=c;c=tem; tem=b;b=d;d=tem; } ll t1,t2,add,sub,k1,k2,k3,k4; t1 =(a+c)%p; add=(m-t1+p)%p; k1 =(a+c+add-m)/p; t2 =(b+c-1)%p; sub=(t2-m+p)%p; k2 =(b+c-1-sub-m)/p; ans+=(k2-k1+1)*(1+add)+(k2-k1+1)*(k2-k1)/2*p; //printf("%I64d\n",ans); t1 =(b+c)%p; add =(m-t1+p)%p; k2 =(b+c+add-m)/p; t2 =(a+d)%p; sub =(t2-m+p)%p; k3 =(a+d-sub-m)/p; ans+=(k3-k2+1)*(b-a+1); //printf("%I64d\n",ans); t1 =(a+d+1)%p; add =(m-t1+p)%p; k3 =(a+d+1+add-m)/p; t2 =(b+d)%p; sub =(t2-m+p)%p; k4 =(b+d-sub-m)/p; ans+=(k4-k3+1)*(1+sub) + (k4-k3+1)*(k4-k3)/2*p; //printf("%I64d\n",ans); ll sum=(b-a+1)*(d-c+1); ll G = gcd(ans,sum); ans /= G; sum /= G; printf("Case #%d: %I64d/%I64d\n",ii,ans,sum); } return 0; }
赛后看了看有一种方法也挺好,用了容斥的原理,ans = gt(b, d) - gt(a - 1, d) - gt(b, c - 1) + gt(a - 1, c - 1);
gt(a, b)表示的是0-a, 和0-b两个区间中满足题意的解的对数。
HDU 4790 Just Random 【构造】
时间: 2024-12-23 14:44:05