lc2867
先标记出非质数,再构建树的结构
(DFS)统计每个由非质数组成的连通块大小
计算满足恰好含一个质数节点的合法路径数量。
const int MX = 1e5;
bool npMX + 1; // 质数=false 非质数=true
int init = \[\]() {
np1 = true;
for (int i = 2; i * i <= MX; i++) {
if (!npi) {
for (int j = i * i; j <= MX; j += i) {
npj = true;
}
}
}
return 0;
}();
class Solution {
public:
long long countPaths(int n, vector<vector<int>> &edges) {
vector<vector<int>> g(n + 1);
for (auto &e: edges) {
int x = e0, y = e1;
gx.push_back(y);
gy.push_back(x);
}
vector<int> size(n + 1);
vector<int> nodes;
function<void(int, int)> dfs = \&(int x, int fa) {
nodes.push_back(x);
for (int y: gx) {
if (y != fa && npy) {
dfs(y, x);
}
}
};
long long ans = 0;
for (int x = 1; x <= n; x++) {
if (npx) continue; // 跳过非质数
int sum = 0;
for (int y: gx) { // 质数 x 把这棵树分成了若干个连通块
if (!npy) continue;
if (sizey == 0) { // 尚未计算过
nodes.clear();
dfs(y, -1); // 遍历 y 所在连通块,在不经过质数的前提下,统计有多少个非质数
for (int z: nodes) {
sizez = nodes.size();
}
}
// 这 sizey 个非质数与之前遍历到的 sum 个非质数,两两之间的路径只包含质数 x
ans += (long long) sizey * sum;
sum += sizey;
}
ans += sum; // 从 x 出发的路径
}
return ans;
}
};
lc2242
先构建图,把每个点连接的点按分数排序并保留前3个
if (vs.size() > 3)
++nth_element(vs.begin(), vs.begin() + 3, vs.end());++
vs.resize(3);
然后枚举中间边(x-y) a-x-y-b
找边两端点各自连接的点中合适的(除环),计算能组成的最大得分
if (a != y && b != x && a != b)
++ans = max(ans, -score_a + scoresx + scoresy - score_b);++
返回最大得分(没有符合的就返回-1)

class Solution {
public:
int maximumScore(vector<int> &scores, vector<vector<int>> &edges)
{
int n = scores.size();
vector<vector<pair<int, int>>> g(n);
for (auto &e : edges) {
int x = e0, y = e1;
gx.emplace_back(-scoresy, y);
gy.emplace_back(-scoresx, x);
}
for (auto &vs : g)
if (vs.size() > 3) {
++nth_element(vs.begin(), vs.begin() + 3, vs.end());++
vs.resize(3);
}
int ans = -1;
for (auto &e : edges) {
int x = e0, y = e1;
for (auto &score_a, a : gx)
for (auto &score_b, b : gy)
if (a != y && b != x && a != b)
++ans = max(ans, -score_a + scoresx + scoresy - score_b);++
}
return ans;
}
};
为了对图中每个节点,只保留与它相连的、分数最大的前三个节点
if (vs.size() > 3)
++nth_element(vs.begin(), vs.begin() + 3, vs.end());++
vs.resize(3);
-
首先遍历图 g 中的每个节点的邻接列表 vs 。
-
如果邻接列表的长度超过3,就使用 nth_element 函数,++把第3大的元素放到 vs.begin() + 3 的位置,这样前3个元素就是最大的三个。++
-
然后通过 vs.resize(3) ,将邻接列表的长度调整为3,从而只保留分数最大的前三个相邻节点
思考枚举点还是边
将问题放小,假设三个点怎么办
三个点则枚举中间点,再枚举两边最优
优化,++贪心每次选最大的权值
则一个点最多往外连三个点++
写的时候可以借助提供的边一下子确定两个点,灵活运用点和边的关系
(这样就不用写四个循环和一堆判断了)
lc2874
预处理+单调性
class Solution {
public:
long long maximumTripletValue(vector<int>& nums)
{
//dan diao xin
int n=nums.size();
vector<int> max_left(n,0);
vector<int> max_right(n,0);
long long ret=LONG_MIN;
for(int i=1;i<n-1;i++)
{
max_lefti=max(max_lefti-1,numsi-1);
}
for(int i=n-2;i>0;i--)
{
max_righti=max(max_righti+1,numsi+1);
}
for(int i=1;i<n-1;i++)
{
ret=max(ret,(long long)(max_lefti-numsi)*max_righti);
}
return ret<0?0:ret;
}
};
lc2909
枚举j,记忆mn i &预处理mn k
class Solution {
public:
int minimumSum(vector<int>& nums)
{
int n=nums.size();
int mnl=nums0;
vector<int> pmn(n,INT_MAX);
pmnn-1=numsn-1;
for(int a=n-2;a>=0;a--)
{
pmna=min(pmna+1,numsa+1);
//not include 0
}
int ret=INT_MAX;
for(int j=1;j<n;j++)
{
if(mnl<numsj && pmnj<numsj)
{
ret=min(mnl+numsj+pmnj,ret);
}
mnl=min(mnl,numsj);
}
return ret==INT_MAX?-1:ret;
}
};
lc447
hash
遍历每个点,计算它与其他点的距离
用hash统计各距离出现次数
再根据次数算出能组成的回旋镖数量并累加,最终得到所有回旋镖的总数

class Solution {
public:
int numberOfBoomerangs(vector<vector<int>>& points) {
int ans = 0;
unordered_map<int, int> cnt;
for (auto& p1 : points) {
cnt.clear();
for (auto& p2 : points) {
int d2 = (p10 - p20) * (p10 - p20) + (p11 - p21) * (p11 - p21);
++ans += cntd2++ * 2;++
}
}
return ans;
}
};