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; }