分治之替换

总时间限制: 
1000ms
内存限制: 
65536kB
描述

对于一个大于1的整数X,,你可以进行以下替换操作:

删掉它,把它换成三个数:⌊X/2⌋,X%2,⌊X/2⌋。

现在给你一个数列,开始数列只有一个整数N,你每次可以在数列中选择一个大于1的整数进行上述操作,直到这个数列最后全是1或0为止。

接下来,在最后的数列中查询区间[L,R]中有多少个1。输出1的个数。

0<N<=250,0<=R-L<=100000,并保证R不超过最终数列的长度。

输入
一行三个整数,分别表示N,L,R。
输出
一个整数,表示[L,R]区间有多少个1。
样例输入
10 3 10
样例输出
5
提示
【样例说明】
{10}→
{5 0 5}→
{2 1 2 0 5}→
{1 0 1 1 2 0 5}→
{1 0 1 1 1 0 1 0 5}→
{1 0 1 1 1 0 1 0 2 1 2}→
{1 0 1 1 1 0 1 0 1 0 1 1 2}→

{1 0 1 1 1 0 1 0 1 0 1 1 1 0 1}

解题思路: 

    这道题的数据范围为2^50,显然不能够使用整型数组来存放分解后所有的数字。观察一下规律,每一个数字都会被分解成三个数字,且最终都会被分解成0或1,所以可以考虑使用分治递归的方法来做,每个数字都会被一直分解成三个数字,一直分解到0或1.

    虽然说无法使用数组来存放所有的数字,但是我们是可以算出这个数列的长度的。观察一下上面分解10的时候的规律{10}->{5,0,5}->{2,0,2,0,2,0,2}->{1,0,1,1,1,0,1,0,1,0,1,1,1,0,1},第1次长度为1,第2次长度为3,第3次长度为7,第4次长度为15,找到规律长度为2^(分解次数+z-1,分解次数就是n除以2最终得到1或者0的除的次数。可以计算出数列的长度len

    那么(1,len)就是分治递归的范围。因为每一个数都会被分解成三个数,所以可以这样写

     return dg(n/2,l,mid-1)+dg(n%2,mid,mid)+dg(n/2,mid+1,r);

参考程序

#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;
LL n,L,R,len=1,x;
int tot;
int dg(LL n,LL l,LL r)
{
    if(R<l||L>r||n==0)//在区间(L,R)之外或者为0(出口1)
        return 0;
    if(n==1)//为1且在区间内就返回1(出口2)
        return 1;
    LL mid=(l+r)/2;//分治
    return dg(n/2,l,mid-1)+dg(n%2,mid,mid)+dg(n/2,mid+1,r);
}

int main()
{
    cin>>n>>L>>R;//输入区间(L,R)
    x=n;
    while(x>1)//计算出最后数组的长度len
    {
        x/=2;
        tot++;
    }
    len=pow(2,tot+1)-1;
    printf("%d",dg(n,1,len));//分治区间为(1,len)
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用分治算法来解决平面凸包问题,可以按照以下步骤进行: 1. 将给定的点集按照 x 坐标进行排序,如果 x 坐标相同,则按照 y 坐标排序。 2. 将点集分成两个子集,每个子集包含大约一半的点。可以选择一个 x 坐标值作为分割线,将点集分成左右两个子集,或者选择中间的点作为分割线。 3. 对左右两个子集分别进行递归处理,得到左右两个子集的凸包。 4. 合并左右两个子集的凸包,得到整个点集的凸包。 在每一次递归中,可以使用 Graham 扫描算法或者快速凸包算法来求解子集的凸包。 以下是一个用 C++ 实现的示例代码: ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; struct Point { int x, y; }; // 按照 x 坐标进行排序,如果 x 坐标相同,则按照 y 坐标排序 bool compareX(Point p1, Point p2) { if (p1.x == p2.x) return p1.y < p2.y; return p1.x < p2.x; } // 按照极角排序,极角相同则按照距离原点的距离排序 bool compareAngle(Point p1, Point p2) { int cross = (p1.x - p[0].x) * (p2.y - p[0].y) - (p2.x - p[0].x) * (p1.y - p[0].y); if (cross == 0) return (p1.x - p[0].x) * (p1.x - p[0].x) + (p1.y - p[0].y) * (p1.y - p[0].y) < (p2.x - p[0].x) * (p2.x - p[0].x) + (p2.y - p[0].y) * (p2.y - p[0].y); return cross > 0; } // 计算凸包 vector<Point> convexHull(vector<Point>& points, int left, int right) { if (left == right) { vector<Point> hull; hull.push_back(points[left]); return hull; } int mid = (left + right) / 2; vector<Point> hullLeft = convexHull(points, left, mid); vector<Point> hullRight = convexHull(points, mid + 1, right); int sizeLeft = hullLeft.size(); int sizeRight = hullRight.size(); // 合并左右凸包 int leftmost = 0, rightmost = 0; for (int i = 1; i < sizeLeft; i++) { if (hullLeft[i].x < hullLeft[leftmost].x) leftmost = i; } for (int i = 1; i < sizeRight; i++) { if (hullRight[i].x > hullRight[rightmost].x) rightmost = i; } int lowerLeft = leftmost, lowerRight = rightmost; while (true) { int newLowerLeft = (lowerLeft + sizeLeft - 1) % sizeLeft; int cross = (hullLeft[lowerLeft].x - hullLeft[newLowerLeft].x) * (hullRight[lowerRight].y - hullLeft[newLowerLeft].y) - (hullRight[lowerRight].x - hullLeft[newLowerLeft].x) * (hullLeft[lowerLeft].y - hullLeft[newLowerLeft].y); if (cross < 0) break; lowerLeft = newLowerLeft; } while (true) { int newLowerRight = (lowerRight + 1) % sizeRight; int cross = (hullRight[lowerRight].x - hullLeft[lowerLeft].x) * (hullRight[newLowerRight].y - hullLeft[lowerLeft].y) - (hullRight[newLowerRight].x - hullLeft[lowerLeft].x) * (hullRight[lowerRight].y - hullLeft[lowerLeft].y); if (cross < 0) break; lowerRight = newLowerRight; } vector<Point> hull; int current = lowerLeft; while (current != lowerRight) { hull.push_back(hullLeft[current]); current = (current + 1) % sizeLeft; } hull.push_back(hullLeft[current]); current = lowerRight; while (current != lowerLeft) { hull.push_back(hullRight[current]); current = (current + 1) % sizeRight; } hull.push_back(hullRight[current]); return hull; } vector<Point> convexHull(vector<Point>& points) { int n = points.size(); if (n < 3) { return points; } sort(points.begin(), points.end(), compareX); return convexHull(points, 0, n - 1); } int main() { vector<Point> points = { {0, 3}, {1, 1}, {2, 2}, {4, 4}, {0, 0}, {1, 2}, {3, 1}, {3, 3} }; vector<Point> hull = convexHull(points); for (int i = 0; i < hull.size(); i++) { cout << "(" << hull[i].x << ", " << hull[i].y << ")" << endl; } return 0; } ``` 这段代码使用分治算法来解决平面凸包问题,其中 `convexHull` 函数实现了分治过程,`compareX` 和 `compareAngle` 函数用于排序,`main` 函数中的示例展示了如何使用该函数来求解平面凸包问题。你可以将自己的点集替换到 `points` 数组中进行测试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值