2013成都区域赛的题目
题意: 区间[a,b] [c,d]里各选一个数,加起来mod p=m
思路:
观察一下构成某个数x的情况:
x 0
.
.
3 x-3
2 x-2
1 x-1
0 x
左边的数从0到x,右边的x到0。它们的范围都是[0,x]
我们假定左边的数从区间[a,b]里选出来,右边的从[c,d]。
其实我们只要求一下三个区间的交集就可以了。
然后还有一些细节需要处理:
1.首先要把[a,b]区间都映射到[0,p)内,这样映射后的区间都带有表示重叠次数的权值。
2.对于[c,d]区间映射完后,我们还要把它反转一下,即[x-c',x-d'](c',d'是映射后的区间)。为什么要反转,因为从上面列的数字可以看出,右边区间的顺序是反过来的。
3.最后三个区间交完后,区间长度*权值就是答案了。但是仅仅求m是不够的,因为映射完后的数字在[0,p)以内,加起来还有可能达到m+p,但是达不到m+2*p了。所以还要对m+p再求一次。
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 1024
#define ll long long
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
#define bit(st,i) ((1ll<<i)&st)
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int MOD =1000003;
const double EPS=1e-7;
int a,b,c,d,p,m;
struct Node{
int l,r;
ll val;
Node(){}
Node(int l,int r,ll val):l(l),r(r),val(val){}
void reverse(int x){
l=x-l;
r=x-r;
if(l>r) swap(l,r);
}
};
vector<Node> x,y,z;
int upper_bound(int target){
int l=0,r=INF;
while(l<r){
int mid=(l+r)>>1;
if(1ll*p*mid<=target) l=mid+1;
else r=mid;
}
return r;
}
void solve(int L,int R,vector<Node> &a){
int l=upper_bound(L);
int r=upper_bound(R)-1;
if(r-l>=0){
a.push_back(Node(0,p-1,r-l));
a.push_back(Node(L%p,p-1,1));
a.push_back(Node(0,R%p,1));
}else{
a.push_back(Node(L%p,R%p,1));
}
}
void cross(vector<Node> &a,vector<Node> &b){
vector<Node> tmp;
for(int i=0;i<a.size();i++){
for(int j=0;j<b.size();j++){
int l=max(a[i].l,b[j].l);
int r=min(a[i].r,b[j].r);
if(r-l>=0) tmp.push_back(Node(l,r,a[i].val*b[j].val));
}
}
b=tmp;
}
ll gao(int n){
ll ans=0;
z.clear();
z.push_back(Node(0,n,1));
for(int i=0;i<y.size();i++) y[i].reverse(n);
cross(x,z);
cross(y,z);
for(int i=0;i<z.size();i++) ans+=z[i].val*(z[i].r-z[i].l+1);
return ans;
}
int main()
{
int Case=1,re;
scanf("%d",&re);
while(re--){
scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&p,&m);
x.clear(), y.clear();
solve(a,b,x);
solve(c,d,y);
vector<Node> bufy=y,bufx=x;
ll up=0,down=1ll*(b-a+1)*(d-c+1);
up+=gao(m);
y=bufy, x=bufx;
up+=gao(m+p); //最大能构造出m+p
ll gcd=__gcd(up,down);
printf("Case #%d: %I64d/%I64d\n",Case++,up/gcd,down/gcd);
}
return 0;
}