首页 > 代码库 > HDU 4790 Just Random
HDU 4790 Just Random
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4790
题目大意:给出a,b,c,d,p,m,在[a,b]和[c,d]中分别选一个数x,y。问满足(x+y)%p=m的(x,y)有多少组,求出占总组数的比例
首先,当然是想遍历一遍,统计满足的有多少点,如此便能轻松愉快的解出此题;但是,真的是这样吗?
我们看一下数据范围,范围是10^9,如果两个数加起来,便达到了2*10^9,如果我们遍历一遍,复杂度是o(k) k为10^9/p,这样的话,那一定会超时了。所以这题我们不能用暴力的方法。
那应该怎么做?我们再看一次题目,看起来好像是高中数学学过的几何概型啊!对,就是几何概型。
如果用一些数据测试一下就会发现,满足条件的点其实是分三段,第一段:一个单调递增的等差数列;第二段:一段数值相同的数列;第三段:一段单调递减的等差数列。
如此,我们只需要求出每一段的起点,终点,即可算出整段数列的和(利用等差数列的前n项和公式)。当然,其中免不了一些特例判断。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include <cmath> #define N 2000000 using namespace std; long long gcd(long long a,long long b) { return b==0?a:gcd(b,a%b); } int main() { #ifndef ONLINE_JUDGE freopen("D:/in.txt","r",stdin); freopen("D:/my.txt","w",stdout); #endif//ONLINE_JUDGE int T; scanf("%d",&T); for(int t=1;t<=T;t++) { long long a,b,c,d,m,p; scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&p,&m); //cin>>a>>b>>c>>d>>p>>m; long long k1=0,k2=0,k3=0,k4=0,k5=0,k6=0,sum1=0,sum2=0,sum3=0; long long s1=b-a+1,s2=d-c+1; if(s1>s2) { swap(s1,s2);swap(a,c);swap(b,d); } long long mot=s1*s2; long long ans=0; if(m<=b+d&&s1!=1&&s2!=1) { k6=(b+d-m)/p; k5=0; k2=k1-1; k4=k3-1; if(m<a+d) { k5=(a+d-m)/p+1; k4=k5-1; k3=0; } if(m<b+c) { k3=(b+c-m)/p+1; k2=k3-1; k1=0; } if(m<a+c) k1=ceil((a+c-m)*1.0/p*1.0); //if(k3>k4) k3=k4; sum1=(m+m+(k1+k2)*p-2*(a+c)+2)*(k2-k1+1)/2; sum2=(k4-k3+1)*(b-a+1); sum3=(2*(b+d)-(m+m+(k6+k5)*p)+2)*(k6-k5+1)/2; ans=sum1+sum2+sum3; } else if(s1==1&&s2==1) { if((a+c)%p==m) ans=1; } else if(s1==1) { if(m<=a+d) { k6=(a+d-m)/p; if(m<=a+c) k5=ceil((a+c-m)*1.0/p*1.0); else k5=0; ans=k6-k5+1; } else ans=0; } //cout<<"ans="<<ans<<endl; long long mygcd=gcd(ans,mot); ans/=mygcd; mot/=mygcd; //cout<<"myans::"<<ans<<endl; //cout<<"mymot::"<<mot<<endl; printf("Case #%d: %I64d/%I64d\n",t,ans,mot); //cout<<"Case #"<<t<<": "; //cout<<ans<<'/'<<mot<<'\n'; } return 0; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。