HDU 4790 Just Random

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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值