首页 > 其他分享 >luogu2119题解

luogu2119题解

时间:2024-02-18 09:23:11浏览次数:19  
标签:luogu2119 题解 dcd bucket pb int 枚举 mina

本题考察对于枚举的方式对程序的性能的提升。

有一个小的优化,\(n\) 的范围比 \(m\) 的范围小,由于我们不关心顺序,我们既可以在值域上枚举也可以在物品上枚举,这里为了优化在值域上枚举更好。

最简单的枚举是直接枚举 \(a,b,c,d\) 或是枚举其中三个数枚举另一个,时间复杂度为 \(O(n^4)\) 或 \(O(n^3)\),显然不能通过。

简单的枚举并没有完全利用题中的物品的关系。
如果枚举 \(X_d-X_c\) 的值可以得到 \(X_b-X_a\) 和 \(X_c-X_b\) 的下限。
此时枚举 \(d\) 可以确定 \(c\),进而确定 \(b\) 的范围,然后通过 \(b\) 的范围确定 \(a\) 的范围。

在求作为 \(c,d\) 物品出现次数时我们并不需要知道 \(a,b\) 的具体的值,我们只需要知道有多少对 \(a,b\) 即可。
同时我们求作为 \(a,b\) 物品出现次数时我们也不关心 \(c,d\) 具体的值。
我们可以统计符合条件的 \(a,b\) 有多少对,在枚举 \(d\) 的过程中把不符合要求的 \(a,b\) 丢掉,计算 \(c,d\) 的出现次数,同时统计 \(c,d\) 的对数,累加 \(a,b\) 的答案,最后再一起输出即可。

代码如下。

#include<bits/stdc++.h>
using namespace std;
constexpr int MAXN=15000+10,MAXM=4e4+10;
int a[MAXM],bucket[MAXN],n,m,ans[MAXN][4],maxa=-114514,mina=114514;
namespace sol{
    void solve(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;++i){scanf("%d",&a[i]);++bucket[a[i]];maxa=max(maxa,a[i]);mina=min(mina,a[i]);}
        for(int dcd=1;dcd*9<maxa-mina;++dcd){
            //dab=dcd*2,dbc>dcd*6
            int pab=0,pb=maxa,pcd=0;
            for(int a1=mina;a1+(dcd<<1)<=maxa;++a1){
                pab+=bucket[a1]*bucket[a1+(dcd<<1)];
            }
            for(int d=maxa;d-dcd*9>mina;--d){
                //c=d-dcd
                while(pb>=d-dcd*7){
                    ans[pb][1]+=pcd*bucket[pb-(dcd<<1)];
                    ans[pb-(dcd<<1)][0]+=pcd*bucket[pb];
                    pab-=bucket[pb-dcd*2]*bucket[pb];
                    --pb;
                }
                ans[d][3]+=pab*bucket[d-dcd];
                ans[d-dcd][2]+=pab*bucket[d];
                pcd+=bucket[d-dcd]*bucket[d];
            }
            while(pb-(dcd<<1)>=mina){
                ans[pb][1]+=pcd*bucket[pb-(dcd<<1)];
                ans[pb-(dcd<<1)][0]+=pcd*bucket[pb];
                --pb;
            }
        }
        for(int i=1;i<=m;++i){
            for(int j=0;j<4;++j){
                printf("%d ",ans[a[i]][j]);
            }
            puts("");
        }
    }
}
int main(){
    sol::solve();
    return 0;
}

标签:luogu2119,题解,dcd,bucket,pb,int,枚举,mina
From: https://www.cnblogs.com/LiJoQiao/p/18018762

相关文章

  • P10171题解
    P10171[DTCPC2024]取模题目传送门题解不会多项式导致的,赛后秒过。一个显然的结论:如果原序列有相等的数答案为\(0\),其次大于\(4\times10^5\)的\(k\)均符合要求。问题在于小于\(4\times10^5\)的答案。赛时想了很多奇妙的算法,诸如根号分治、线段树维护余数等等。其......
  • CF1472C Long Jumps题解
    【题目分析】本题有两个方法,方法一:每一个位置可得的分分别求出,打擂找出最大(可得部分分)方法二:从后往前求可得的分数,以避免一些不必要的重复。【设计程序】方法一:#include<bits/stdc++.h>#include<iostream>#include<stdio.h>#include<cstdio>#include<queue>usingnames......
  • CF1196B Odd Sum Segments题解
    【问题分析】本题考了奇数。由此想到以下定律:奇数+偶数=奇数;奇数+奇数=偶数;偶数+偶数=偶数;所以偶数可以忽略不计,只有奇数可以对结果产生影响,所以我们只要注意奇数即可。经过思考可得奇数的个数至少为$k$个且比$k$多的个数为偶数,此时多出的奇数可组成偶数,对结果不产生......
  • P2036 [COCI2008-2009#2] PERKET题解
    【问题分析】分析题目可得此问题为01背包问题因此题数据较小所以可用枚举每一样物品选或不选的方法来写【设计程序】#include<bits/stdc++.h>#include<iostream>#include<stdio.h>#include<cstdio>#include<queue>usingnamespacestd;constintN=10+5;struct......
  • P1162 填涂颜色题解
    【问题分析】分析题目可得此问题为连通块问题因此题枚举被包围的‘0’较难所以可用枚举每一个不被包围的‘0’【设计程序】#include<bits/stdc++.h>#include<iostream>#include<stdio.h>#include<cstdio>#include<queue>usingnamespacestd;constintN=30+5;i......
  • P2249 【深基13.例1】查找题解
    【问题分析】本题有n个数(n>10^6)n很大,查找m个数(m≤10^5),数最大为(10^9)方法一:用顺序查找的话时间复杂度为:O(n*m)会超时,只能得部分分;方法二:用桶排时间复杂度为O(n)+O(m),但是因为数最大为(109)空间复杂度为:O(109);方法三:用二分查找,时间复杂度为:O(m*logn),空间复杂度为O(n)。综合以......
  • P8248 简单数列 题解
    首先,圈重点:$1\len\le500$所有元素在$1\sim4$之间任意连续的连续子串不相同只要输出一种答案即可于是我们可以得到的是:由第一点和第二点可以看出此题可以写搜索解决。由第三点我们可以得到一种剪枝方式,就是如果目前数字放入后会产生相同的连续的连续子串。由第四点......
  • P1380 T型骨牌 题解
    本题每个位置有$5$种可能,据题中$n,m$均小于五,所以可以用搜索直接过。上代码#include<cstdio>usingnamespacestd;boolmp[15][15];intn,m,ans;intdt[4][5][2]={{{-1,-1},{0,-1},{1,-1},{0,0},{0,1}},{{-1,0},{0,0},{1,-1},{1,0},{1,1}},{{0,......
  • P1686 挑战 题解
    本题就是要找到最短的捷径。注意事项:捷径必须是直线。要求捷径最短而非总路程最短。捷径不与原有的路重合既然在同一直线上,则该捷径的起点与终点的横坐标或纵坐标相等。要把横坐标或纵坐标相同的聚在一起只需要排个序即可。捷径最短的话(以横坐标相等举例),只需要以$x$为第......
  • P1541 [NOIP2010 提高组] 乌龟棋题解
    有两种方法,代码注释都很详细了直接上代码一:记忆化搜索#include<bits/stdc++.h>usingnamespacestd;intt[15];intn,m;inta[400];intmp[45][45][45][45];//mp[i][j][k][l]表示1号用i张,2号用j张,3号用k张,4号用l张的情况下,最多能拿多少分intdfs(intstep,intw)//step......