1 条题解

  • 2
    @ 2023-10-21 14:27:03

    本题题面很长,仔细读题后提取有用信息:

    • ( 1)近似度:需要输出的这个数所对应的二进制与所给的n个整数所对应的二进制每一位上相同数字的数量。
    • (2)给定一个整数k,用来规定标准十进制所对应的二进制的长度。不足m位用零补齐。
    • (3)若有多种答案,需要输出二进制1最多的一种答案
    1. 解题思路:
      • 很容易想到的是暴力,直接枚举每一个整数,转化成二进制,遍历n个数对应的二进制,求出相似度再取最大值,但是本题数据范围,二进制长度最大为31,遍历整数的范围为2^31,会TLE,不可行。
      • 仔细观察样例,单独拆开每一位,我们可以考虑所求答案的十进制对应的二进制要想相似度最大,那么每一位都要尽可能与n个整数所对应的十进制的二进制每一位一样。从全局最优推到了局部最优,也就转化成了贪心思想。
    • 贪心策略的证明在次不在赘述......
    • 所以每一位的构造方法为max(n个整数这一位的0的数量累加,n个整数这一位的1的数量累加),如果0多这一位就是0,如果1多这一位就是1,如果0与1相等这一位也是1(需要满足(3))。
    1. tips:
    • 答案会爆int,需要开long long
    • 在求十进制数用pow也会爆int,需要强制类型转 化成long long。
    • 时间复杂度O(Tn31),最坏在O(31*10^4),可以通过本题。 AC代码如下:
    // Problem: 杨京昊的相亲计划
    // URL: https://acm.nyist.edu.cn/p/900
    // Memory Limit: 1 MB
    // Time Limit: 2000 ms
    // Date: 2023-10-21 14:01:32
    // Author: XuJin
    // Motto:Thanks to time never giving up, give me a path of thorns
    // 看到你时总是感觉清风徐徐
    // 本以为和你相识不会是偶遇
    // 奈何你犹如过客、化作秋雨
    // 只是经过我生命的一瓢柳絮
    // 从不会真正有童话似的结局
    // 我静静地写尽这些躁言丑句
    // 本以为可以稍稍地缓解抑郁
    // 却是徒增一场悲伤的脑补剧
    // 你问我为什么说这么多?
    // 因为这题是杨京昊的相亲计划
    //
    //
    // Powered by CP Editor (https://cpeditor.org)
    
    #include <bits/stdc++.h>
    #define xx first
    #define yy second
    #define I __int128
    const int INF = 0x3f3f3f3f;
    const int N = 1e6 + 10;
    #define debug(x) cout << #x << "=" << x << '\n';
    #define IOS                    \
    	ios::sync_with_stdio(false); \
    	cin.tie(0);                  \
    	cout.tie(0);
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> PII;
    int xx[] = {0, 0, 1, -1};
    int yy[] = {1, -1, 0, 0};
    int gcd(int a, int b) {
    	return b ? gcd(b, a % b) : a;  //求最大公约数
    }
    ll yinshu(ll x) {  //快速求一个数的因数个数
    	ll ans = 0;
    	for (ll i = 2; i <= sqrt(x); i++) {
    		if (x % i == 0) ans += 2;
    		if (i * i == x) ans--;
    	}
    	return ans;
    }
    int a[N];
    int cnt[N];
    int t = 0;
    int ans1[N];
    int ans2[N];
    string cn[11000];
    void erjin(int x) {
    	t = 0;
    	while (x) {
    		cnt[++t] = x % 2;
    		x /= 2;
    	}
    }
    void solve() {
    	/*给你 n个十进制数字 xi,你需要转化成长度为 ℓ的二进制数字(长度不够前边补 0
    	二进制数长度不会长于 ℓ,并且找到一个数字 y ,使得所有 xi与y的相似度和最大。
    	*/
    	//----------------初始化-------------------
    	memset(ans1, 0, sizeof(ans1));
    	memset(ans2, 0, sizeof(ans2));
    	int n, m;
    	cin >> n >> m;
    	for (int i = 1; i <= n; i++) {
    		cin >> a[i];
    	}
    	string x = "";
    	//-----------存取每个十进制对应的二进制------------
    	for (int i = 1; i <= n; i++) {
    		erjin(a[i]);
    		for (int s = 1; s <= m - t; s++) {
    			x += '0';
    		}
    		for (int j = t; j >= 1; j--) {
    			x += cnt[j] + '0';
    		}
    		cn[i] = x;
    		x = "";
    	}
    	//--------------------贪心策略---------------------------
    	for (int i = 1; i <= n; i++) {
    		string x1 = cn[i];
    		for (int j = 0; j < x1.size(); j++) {
    			if (x1[j] == '0') {
    				ans1[j]++;
    			} else {
    				ans2[j]++;
    			}
    		}
    	}
    	//---------------------构造字符串---------------------------
    	x = "";
    	for (int i = 0; i < m; i++) {
    		if (ans1[i] <= ans2[i]) {
    			x += '1';
    		} else {
    			x += '0';
    		}
    	}
    	//------------------检查构造是否正确----------------
    	//	cout<<x<<endl;
    	//-----------------转化成十进制输出------------------------------
    	ll ans = 0;
    	for (int i = x.size() - 1, k = 0; i >= 0; i--, k++) {
    		ans += (ll)pow(2, k) * (x[i] - '0');
    	}
    	cout << ans << endl;
    }
    int main() {
    	IOS;
    	int t;
    	cin >> t;
    	while (t--) {
    		solve();
    	}
    }
    
    • 1

    信息

    ID
    900
    时间
    1000ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    54
    已通过
    21
    上传者