[Codeforces799F] [哈希] Beautiful fountains rows

本文介绍了一种通过随机分配权值并利用前缀和及映射表来解决区间覆盖问题的方法,通过计算区间权值的异或值来快速判断哪些区间符合特定条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

%%%Manchery

给每个区间随机一个权值,这样每个位置被哪些区间覆盖奇数次就可以用区间权值的xor值表示,假设为x,一个区间被哪些区间覆盖也可以用xor值表示,假设为y
那么满足x=y的区间就是符合条件的区间

前缀和搞一搞,map记一记就好啦

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#define N 200010

using namespace std;

typedef unsigned long long ull;
typedef pair<ull,ull> paru;

int n,m;
long long ans;
int l[N],r[N],num[N];
ull p1[N],p2[N];
vector<ull> s1[N],t1[N],s2[N],t2[N];
map<paru,long long> M,S;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void rea(int &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

inline long long calc(int x){
  return 1ll*(x+1)*x*x/2-1ll*(x-1)*x/2-1ll*x*(x-1)*(2*x-1)/6;
}

int main(){
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  rea(n); rea(m);
  for(int i=1;i<=n;i++){
    rea(l[i]); rea(r[i]);
    ull hash1=1ULL*rand()*rand()*rand(),hash2=1ULL*rand()*rand()*rand();
    s1[l[i]].push_back(hash1); s2[l[i]].push_back(hash2);
    t1[r[i]].push_back(hash1); t2[r[i]].push_back(hash2);
    p1[l[i]]^=hash1; p1[r[i]+1]^=hash1;
    p2[l[i]]^=hash2; p2[r[i]+1]^=hash2;
    num[l[i]]++; num[r[i]+1]--;
  }
  for(int i=1;i<=m;i++) p1[i]^=p1[i-1],p2[i]^=p2[i-1];
  for(int i=1;i<=m;i++) p1[i]^=p1[i-1],p2[i]^=p2[i-1];
  ull a1=0,b1=0,a2=0,b2=0;
  M[paru(0,0)]=1;
  for(int i=1;i<=m;i++){
    for(int x=0;x<s1[i].size();x++) a1^=s1[i][x],a2^=s2[i][x];
    ans+=M[paru(a1^p1[i],a2^p2[i])]*i-S[paru(a1^p1[i],a2^p2[i])];
    for(int x=0;x<t1[i].size();x++) b1^=t1[i][x],b2^=t2[i][x];
    M[paru(b1^p1[i],b2^p2[i])]++; S[paru(b1^p1[i],b2^p2[i])]+=i;
  }
  for(int i=1;i<=m;i++) num[i]+=num[i-1];
  for(int i=1,j;i<=m;i=j+1){
    j=i;
    while(j<=m&&num[j]==0) j++;
    j--;
    if(j<i) j=i;
    else ans-=calc(j-i+1);
  }
  printf("%I64d\n",ans);
  return 0;
}
Codeforces 2123F 问中,目标是通过重新排列数组 $ a $ 来最小化不动点的数量。所谓“不动点”是指在重新排列后的数组中满足 $ a_i = i $ 的位置。该问要求设计一种策略,以最优方式重新排列数组元素,使得这样的不动点数量最少。 为了解决这个问,可以采用贪心算法和图论思想相结合的策略: - 首先,观察到如果某个值 $ i $ 出现了多次(即 $ a_i = i $),那么这些重复的值必须被移动到其他位置,以消除不动点。 - 对于那些没有出现在其索引上的值(例如 $ a_i \neq i $),可以通过交换操作将其移动到合适的位置,从而避免产生新的不动点。 一个有效的解决方案可以基于以下步骤: 1. 构建一个映射表,记录每个值出现的位置。 2. 找出所有当前值等于其索引的位置(即当前的不动点)。 3. 尝试通过交换来消除这些不动点。优先考虑将这些值移动到未被占用的位置,并确保不会引入新的不动点。 4. 在无法完全消除所有不动点的情况下,选择最优的交换策略以尽可能减少不动点的数量。 以下是 Python 中的一个示例实现,用于解决此类问的基本思路: ```python def minimize_fixed_points(n, a): pos = {} fixed_points = [] # 记录每个值的出现位置,并找出初始的不动点 for i in range(n): if a[i] == i + 1: fixed_points.append(i) if a[i] not in pos: pos[a[i]] = [] pos[a[i]].append(i) # 如果没有重复的值,则可以直接交换以消除所有不动点 result = a[:] for i in fixed_points: found = False for val in pos: if val != i + 1 and len(pos[val]) > 0: j = pos[val].pop() result[i], result[j] = result[j], result[i] found = True break if not found: # 特殊情况处理:当只剩下一个值时 for j in range(n): if j != i and result[j] != j + 1: result[i], result[j] = result[j], result[i] break return result # 示例输入 n = int(input()) a = list(map(int, input().split())) result = minimize_fixed_points(n, a) print(' '.join(map(str, result))) ``` 此代码实现了上述逻辑,并尝试通过交换来最小化不动点的数量。对于大多数情况,它能够有效消除所有不动点;在某些特殊情况下(例如所有值都唯一且存在多个不动点),则需要特别处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值