HDU 5032 Always Cook Mushroom (2014年北京赛区现场赛A题)

来源:互联网 发布:雅思写作8分 知乎 编辑:程序博客网 时间:2024/05/22 00:33

1.题目描述:点击打开链接

2.解题思路:本题利用极角排序+BIT解决。不过这种思路实在是不容易想到。首选把(1,1)~(1000,1000)都存入数组,并按照他们的斜率排序,然后对输入的m条询问也当做点来看待,当然,这些“点”不能和前面预处理的那些点混淆,这些点表示的是询问点,需要保存询问点的信息有:直角顶点(x,0),斜率(b/a),答案(ans),询问的id(i)。对这些询问也按照斜率由小到大排序,这样,在当前点的斜率值小于询问点的斜率时,执行add(xi,val)操作,最后的答案就是query(xi)。其实这里是一个非常微妙而精彩的做法。虽然题目中说的是第(i,j)处的val是(i+A)*(j+B),但是由于最后是一个求和的过程,因此可以等效理解成所有x值相同的val都加到x轴对应的点上,(这和《概率论》中的二维随机变量概率分布和它的边缘分布非常类似),然后,对xi求前缀和就是整个三角形的val值之和。找下一个点的答案时,直接在现有的x轴基础上继续操作即可。

3.代码:

#include<iostream>#include<algorithm>#include<cassert>#include<string>#include<sstream>#include<set>#include<bitset>#include<vector>#include<stack>#include<map>#include<queue>#include<deque>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<cctype>#include<complex>#include<functional>#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;#define me(s)  memset(s,0,sizeof(s))#define rep(i,n) for(int i=0;i<(n);i++)typedef long long ll;typedef unsigned int uint;typedef unsigned long long ull;typedef pair <int, int> P;const int N=1000005;int A,B,m;struct Point{    int x,y;    ll ans;    double p;}s[N],sc[N];bool cmpp(Point a,Point b){return a.p<b.p;}bool cmpid(Point a,Point b){return a.y<b.y;}ll bit[1005]; //x轴的最大范围只有1000int lowbit(int x){return x&-x;}void add(int x,ll v){    while(x<=1000)    {        bit[x]+=v;        x+=lowbit(x);    }}ll query(int x){    ll ans=0;    while(x>0)    {        ans+=bit[x];        x-=lowbit(x);    }    return ans;}int main(){    int T;    int cnt=0;    scanf("%d",&T);    for(int i=1;i<=1000;i++)        for(int j=1;j<=1000;j++)            s[cnt++]=Point{i,j,0,1.0*j/i};    sort(s,s+cnt,cmpp);    for(int kase=1;kase<=T;kase++)    {        scanf("%d%d",&A,&B);        scanf("%d",&m);        int a,b,x;        for(int i=0;i<m;i++)        {            scanf("%d%d",&a,&b);            scanf("%d",&x);            sc[i]=Point{x,i,0,1.0*b/a};        }        sort(sc,sc+m,cmpp);        me(bit);        int now=0;        for(int i=0;i<m;i++)        {            while(s[now].p<=sc[i].p)//只要斜率小于当前询问点的斜率,就继续执行add操作            {                add(s[now].x,(ll)(s[now].x+A)*(s[now].y+B));                now++;            }            sc[i].ans=query(sc[i].x);        }        sort(sc,sc+m,cmpid);//所有询问点的答案都得到后,还按照它们的id排序        printf("Case #%d:\n",kase);        for(int i=0;i<m;i++)            printf("%I64d\n",sc[i].ans);    }}

0 0
原创粉丝点击