1862. 向下取整数对和

先从小到大排序

对每个nums[i],sum += 1,表示自己除自己为1

一、

令p = i + 1,q = 第一个大于等于nums[i]的数的下标,则q - p为与nums[i]相等的数的个数,

sum += (q - p)* 2,因为我们只考虑 5 / 2,而不用考虑2 / 5,但若有两个5,则必须考虑$5_1 / 5_2,5_2 / 5_1$

所以要*2

二、

之后令q = p,令ans = 1,每次令q = 第一个大于等于nums[i] * (ans + 1)的数的下标,则(q - p)即为有(q - p)个数除nums[i] = ans

sum += (q - p)* ans;

ans++;

直到ans * nums[i] 大于 最大值,则i++,继续下一个nums

 

每次记录一中的值和二中的值,如果第i + 1个数与第i个相同,则可以重复使用

class Solution {
public:
    int vis[100010];
    bool vis1[100010];
    set<int> ss;
    int mod = 1e9 + 7;
    int sumOfFlooredPairs(vector<int>& nums) {
        memset(vis, 0, sizeof(vis));
        memset(vis1, 0, sizeof(vis1));
        // vector<int> NUM;
        int n = nums.size();
        int max_v = -1;
        for(int i = 0; i < n; i++)
        {
            vis[nums[i]]++;
            max_v = max(max_v, nums[i]);
            // ss.insert(nums[i]);
        }
        sort(nums.begin(), nums.end());
        int sum = 0, cnt = 0, pre_same, pre_nosame;
        
        for(int i = 0; i < n; i++)
        {
            sum = (sum + 1) % mod;
            if(i > 0 && nums[i] == nums[i - 1])
            {
                pre_same--;
                sum = (sum + pre_same * 2 % mod) % mod;
                sum = (sum + pre_nosame) % mod;
                continue;
            }
            pre_nosame = 0;
            int ans = 1, p = i + 1, q;
            q = upper_bound(nums.begin(), nums.end(), nums[i]) - nums.begin();
            sum  = (sum + (q - p) * 2 % mod) % mod;
            pre_same = q - p;
            p = q;
            while(i < n - 1 && (nums[i]) * ans <= max_v)
            {
                q = lower_bound(nums.begin(), nums.end(), nums[i] * (ans + 1)) - nums.begin();
                sum = (sum + (((q - p) * ans) % mod) ) % mod;
                pre_nosame = (pre_nosame + (q - p) * ans % mod) % mod;
                ans++;
                p = q;
            }

        }


        return sum;



    }
};

 

posted @ 2021-11-21 18:17  WTSRUVF  阅读(37)  评论(0编辑  收藏  举报