zoukankan      html  css  js  c++  java
  • codeforces 1323D 题解(数学)

    codeforces 1323D 题解

    UPD1: 应为(0leq a_i,a_j<2^{p+1})而不是(0leq a_i,a_j<2^p),与之相关的错误也已修正,如果还有错请直接评论区开喷。

    题意:给(n)个数(a_1,a_2,...,a_n),计算(mathop{oplus}limits_{i<j}(a_i+a_j))(oplus)是异或。

    (nleq 400000,1leq a_ileq 10^7)

    按二进制位考虑,从低位往高位看,最低位记作第(0)位,以此往上。考虑第(p)位是(0)还是(1):第(p)位是(1),当且仅当有奇数对(i,j)使得(a_i+a_j)的第(p)位是(1)。由于加法运算的高位不会影响低位,那就干脆忽视高位,只看第(p)位及以下的位。忽视高位后(也就是把数都(\%2^{p+1})后),显然有(0leq a_i,a_j<2^{p+1}),那么(0leq a_i+a_j<2^{p+2})。因此(a_i+a_j)的第(p)位是(1),当且仅当(2^pleq a_i+a_j<2^{p+1})(2^{p+1}+2^pleq a_i+a_j)

    那么可以枚举(i),查询有多少个(j)使得(2^pleq a_i+a_j<2^{p+1})(2^{p+1}+2^pleq a_i+a_j)。换句话说,查询有多少个(a_jin[2^p-a_i,2^{p+1}-a_i)cup[2^{p+1}+2^p-a_i,+infin))

    那么把数组排序,二分找到这些端点的位置就可以轻松统计出个数了。当然,还有一些细节,比如(i eq j),还有每对数被算了两遍什么的,要慢慢去处理。

    (A=mathop{max}limits_{i=1}^n(a_i)),时间复杂度(O(n logn logA))。如果用双指针(当然这里有好多指针),能降低到(O(n logA))。(我没有实际写这个双指针代码,如果无法做到请直接评论区开喷(

    PS:我在赛中写的是(O((n+2A) log2A))的,因为我没想到排序二分,就直接(O(2A))打前缀和表了,但还是1400ms过了。。。感谢出题人爸爸不杀之恩

    //O(n+2A log2A)的
    #include <bits/stdc++.h>
    #define LL long long
    #define pb push_back
    #define eb emplace_back
    #define pii pair<int,int>
    #define pll pair<LL,LL>
    using namespace std;
    
    int n, a[400008], cnt[20000008], v[400008];
    int ans[32];
    int fans = 0;
    int main()
    {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; ++i)
    	{
    		scanf("%d", &a[i]);
    	}
    	for (int i = 0; i < 25; ++i)
    	{
    		//cout << "i = " << i << endl;
    		for (int j = 1; j <= n; ++j)
    		{
    			v[j] += (a[j] & (1 << i));
    		}
    		memset(cnt, 0, sizeof(cnt));
    		for (int j = 1; j <= n; ++j)
    		{
    			cnt[v[j]]++;
    		}
    		for (int val = 1; val <= 20000000; ++val)
    		{
    			cnt[val] += cnt[val - 1];
    		}
    		for (int j = 1; j <= n; ++j)
    		{
    			//cout << "j = " << j << endl;
    			int l = ((1 << i) - v[j]), r = ((1 << (i + 1)) - 1 - v[j]);
    			int l2 = (1 << (i + 1)) + (1 << i) - v[j];
    			//cout << l << "  " << r << endl;
    			if (l - 1 >= 0)
    				ans[i] += cnt[min(r, 20000000)] - cnt[l - 1] - (v[j] >= l && v[j] <= r);
    			else
    				ans[i] += cnt[min(r, 20000000)] - (v[j] >= l && v[j] <= r);
    			/*if (l - 1 >= 0)
    				cout << cnt[min(r, 20000000)] - cnt[l - 1] - (v[j] >= l && v[j] <= r) << endl;
    			else
    				cout << cnt[min(r, 20000000)] - (v[j] >= l && v[j] <= r) << endl;*/
    			if (l2 >= r + 1)
    				ans[i] += n - cnt[min(r + (1 << i), 20000000)] - (v[j] >= l2);
    		}
    		ans[i] /= 2;
    		//cout << ans[i] << endl;
    		if (ans[i] % 2)
    			fans += (1 << i);
    	}
    	cout << fans << endl;
    }
    

    后记

    感觉自己很无敌,但其实看来这题放在真的现场赛中也就是个银牌题中比较简单的题目,不知道为什么cf div2比赛中只有几十个人过,大概年轻人还是要多学习一个

  • 相关阅读:
    生成一个uuid字符串,并去除多余的符号
    Jackson错误:Can not deserialize instance of java.lang.String out of START_OBJECT token
    jdk1.8换成11,启动项目报错java.net.MalformedURLException: unknown protocol: jrt
    RSA算法
    springboot集成thymeleaf中遇到不能反悔页面,只能反悔字符串
    Caused by: java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [VCodeModel]
    [08001] Could not create connection to database server. Attempted reconnect 3 times. Giving up.
    Caused by: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Out of range value for column 'phone' at row 1
    jstl是自动就有的吗,不是的Unknown tag (c:if).
    mysql 设置编码 Incorrect string value: 'xE9x98xBFxE4xB8x89...' for column 'cont,mysql乱码
  • 原文地址:https://www.cnblogs.com/zhugezy/p/12484180.html
Copyright © 2011-2022 走看看