[KSN2021] Binary Land题解(位运算应用)

P7973 [KSN2021] Binary Land

[KSN2021] Binary Land

题目描述

给定一张 N N N 个点的图,每个点有权值 A i A_i Ai 和价值 B i B_i Bi

两个点 x , y x,y x,y 之间存在一条无向边当且仅当 A x  xor  A y > max ⁡ ( A x , A y ) A_x\text{ xor }A_y>\max(A_x,A_y) Ax xor Ay>max(Ax,Ay)

你需要对于 i = 1 , 2 , ⋯ n i=1,2,\cdots n i=1,2,n 依次求出点 i i i 所在连通块中所有点的价值和。

输入格式

第一行输入一个正整数 N N N

第二行输入 N N N 个正整数 A i A_i Ai

第三行输入 N N N 个正整数 B i B_i Bi

输出格式

输出 N N N 行,第 i i i 行包含一个整数,代表点 i i i 所在连通块中所有点的价值和。

样例 #1

样例输入 #1

3
2 1 1
20 30 10

样例输出 #1

60
60
60

样例 #2

样例输入 #2

4
5 4 4 5
10 20 30 40

样例输出 #2

10
20
30
40

样例 #3

样例输入 #3

5
1 2 1 7 11
20 10 30 100 100

样例输出 #3

60
60
60
200
200

提示

【数据范围】

本题采用捆绑测试。

  • Subtask 1(8 points):只存在一组数据,满足 N = 8 N=8 N=8 A = [ 6 , 39 , 11 , 63 , 3 , 39 , 1 , 43 ] A=[6,39,11,63,3,39,1,43] A=[6,39,11,63,3,39,1,43] B = [ 4 , 8 , 3 , 7 , 9 , 1 , 2 , 2 ] B=[4,8,3,7,9,1,2,2] B=[4,8,3,7,9,1,2,2]
  • Subtask 2(13 points):保证 N ≤ 200 N \leq 200 N200
  • Subtask 3(10 points):保证 N ≤ 2000 N \leq 2000 N2000
  • Subtask 4(4 points):保证 A 1 = A 2 = ⋯ = A n A_1=A_2=\cdots=A_n A1=A2==An
  • Subtask 5(7 points):保证存在非负整数 k k k 使得 A i = 2 k A_i=2^k Ai=2k
  • Subtask 6(19 points): A i ≤ 2 12 − 1 A_i\leq 2^{12}-1 Ai2121
  • Subtask 7(39 points):无特殊限制。

对于所有数据, 1 ≤ N ≤ 1 0 5 1 \leq N \leq 10^5 1N105 1 ≤ A i ≤ 2 30 − 1 1 \leq A_i \leq 2^{30}-1 1Ai2301 1 ≤ B i ≤ 1 0 9 1 \leq B_i \leq 10^9 1Bi109

#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <cmath>
#define ll long long 
using namespace std;
const int maxn=1e6+10;
ll f[maxn],sum[maxn],a[maxn];
bool vis1[maxn],vis2[maxn];
int n;
int find(int x)
{
    if(x!=f[x]) f[x]=find(f[x]);
    return f[x];
}
void merge(int u,int v)
{
    int x,y;
    x=find(u),y=find(v);
    if (x==y) return ;
    f[x]=y;//把x街道以y为根的树上去
    sum[y]+=sum[x];//值也要加到根上去,后面查询每个联通量,就直接查询根的值即可
    return ;
}
int main ()
{
    scanf ("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf ("%lld",&a[i]);
    }
    for (int i=1;i<=n;i++)
    {
        scanf ("%lld",&sum[i]);
    }
    for (int i=1;i<=n*2;i++)//注意,是1到n*2,因为它后面会用到tmp+n+1,它肯定比n大
    {
        f[i]=i;
    }
    for (int i=1;i<=n;i++)
    {
        int tmp=(int)log2(a[i]);
        vis1[tmp]=true;
        for (int j=tmp-1;j>=0;j--)
        {
            if (!(a[i]>>j&1))
            {
                vis2[j]=true;
            }
        }
    }
   for (int i=1;i<=n;i++)
    {
        int tmp=(int)log2(a[i]);
        if (!vis1[tmp])
        {
            continue;
        }
        merge(tmp+n+1,i);//让第个作为那个较小的,tmp+n+1,是为了不让干扰后面可能会出现的以为他们已经并在一起了,下同
    }
      for (int i=1;i<=n;i++)//让第i个作为那个较大的
    {
        int tmp=(int)log2(a[i]);
        for (int j=tmp-1;j>=0;j--)
        {
             if (!(a[i]>>j&1))//有情况
             {
                 if (!vis1[j])//看有没有在较大的1后面的位置为第一个1的数,如果没有,continue
                 {
                     continue;//不存在符合这个条件的,下一个
                 }
                 merge(j+1+n,i);//如果较大的数绑上了第j位,并且还有较小的数绑上了第j位,那么较大的数就是和较小的数绑在一起了
             }
        }
    }
    for (int i=1;i<=n;i++)
    {
        printf ("%lld\n",sum[find(i)]);
    }
    system("pause");
    return 0;
}

在这里插入图片描述
本人还是个小蒟蒻,如有问题,请斧正!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
As an AI language model, I don't have access to examples of keys or sensitive information. However, I can provide you with the general steps for generating an IPEK using BouncyCastle: 1. Generate a random 16-byte key, called the "Key Encryption Key" (KEK). 2. Using the KEK and the BDK (Base Derivation Key), generate a 16-byte key called the "Initial PIN Encryption Key" (IPEK). 3. XOR the IPEK with the first 8 bytes of the KSN (Key Serial Number) to generate the "PIN Encryption Key" (PEK). 4. XOR the IPEK with the second 8 bytes of the KSN to generate the "Data Encryption Key" (DEK). Here's the Java code using BouncyCastle: ``` import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.util.encoders.Hex; public class IpekGenerator { private static final byte[] BDK = Hex.decode("0123456789ABCDEFFEDCBA9876543210"); private static final byte[] KSN = Hex.decode("FFFF9876543210E00001"); public static void main(String[] args) { // Generate KEK byte[] kek = new byte[16]; new SecureRandom().nextBytes(kek); // Generate IPEK byte[] ipek = generateIpek(BDK, kek); System.out.println("IPEK: " + Hex.toHexString(ipek)); // Generate PEK and DEK byte[] pek = generatePek(ipek, KSN); byte[] dek = generateDek(ipek, KSN); System.out.println("PEK: " + Hex.toHexString(pek)); System.out.println("DEK: " + Hex.toHexString(dek)); } private static byte[] generateIpek(byte[] bdk, byte[] kek) { byte[] data = new byte[16]; System.arraycopy(kek, 0, data, 0, 8); System.arraycopy(bdk, 0, data, 8, 8); CBCBlockCipher cipher = new CBCBlockCipher(new AESEngine()); ParametersWithIV params = new ParametersWithIV(new KeyParameter(bdk), new byte[16]); cipher.init(true, params); byte[] ipek = new byte[16]; cipher.processBlock(data, 0, ipek, 0); return ipek; } private static byte[] generatePek(byte[] ipek, byte[] ksn) { byte[] pek = new byte[8]; for (int i = 0; i < 8; i++) { pek[i] = (byte) (ipek[i] ^ ksn[i]); } return pek; } private static byte[] generateDek(byte[] ipek, byte[] ksn) { byte[] dek = new byte[8]; for (int i = 0; i < 8; i++) { dek[i] = (byte) (ipek[i + 8] ^ ksn[i]); } return dek; } } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值