CF1891B Deja Vu 題解

心海秋的墨木仄發表於2024-04-10

建議憑橙,思路橙,碼量紅到橙。

題面

思路

一,暴力

直接依照題意模擬,複雜度 \(O(tqn^2)\),看一眼資料範圍,妥妥 T 飛,倒在第三個點。

二,逐步最佳化

看一眼資料發現,雖然 \(q\) 很大,但實際上 \(x\) 只有三十個值,因此首先預處理出從 \(2^1\)\(2^{30}\) 的所有值,摘掉一個 \(n\),複雜度 \(O(tqn)\)

接下來不管怎樣,即使把複雜度最佳化到 \(O(tq)\),複雜度依舊非常的高。\(t\) 組資料是不可能去掉的,因此考慮去掉 \(q\)。使複雜度變為 \(O(tn)\) 或者 \(O(tn)\) 的近似值。

考慮到對於每一個 \(a_i\),當它滿足某一個 \(a_i \bmod 2^x=0\) 時。則 \((a_i+2^{x-1}) \bmod 2^x\) 此時一定不為 \(0\)。說人話就是當一個數被 \(2^x\) 整除過後,它就不會再能夠整除這個 \(2^x\)

簡單證明一下,當 \(a_i \bmod 2^x=0\) 時,對於 \((a_i+2^{x-1}) \bmod 2^x\),等價於 \(a_i \bmod 2^x+2^{x-1} \bmod 2^x\)。很明顯 \(a_i \bmod 2^x=0\)\(2^{x-1} \bmod 2^x \ne 0\) 恆成立。即使在經過多個不同的 \(2^x\) 的處理後,這個結論依舊成立。

所以在 \(\text{AC}\) 程式碼中,對於每組資料,用一個陣列 \(\text{book}\) 記錄 \(x\) 是否出現過,複雜度 \(O(tn)\)

程式碼

#include<bits/stdc++.h>
#define ll long long
#define fr(i , a , b) for(ll i = a ; i <= b ; ++i)
#define fo(i , a , b) for(ll i = a ; i >= b ; --i)
using namespace std;
ll t , n , a[100005] , q , x;
ll qp[31] = {1 , 2 , 4 , 8 , 16 , 32 , 64 , 128 , 256 , 512 , 1024 , 2048 , 4096 , 8192 , 16384 , 32768 , 65536 , 131072 , 262144 , 524288 , 1048576 , 2097152 , 4194304 , 8388608 , 16777216 , 33554432 , 67108864 , 134217728 , 268435456 , 536870912 , 1073741824};
ll book[31];
//priority_queue<ll> q;
//priority_queue <ll , vector<ll> , greater<ll> > q;
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> t;
	while(t--)
	{
		cin >> n >> q;
		fr(i , 1 , n)
		{
			cin >> a[i];
		}
		while(q--)
		{
			cin >> x;
			if(book[x])
			{
				continue;
			}
			book[x] = 1;
			fr(i , 1 , n)
			{
				if(a[i] % qp[x] == 0)
				{
					a[i] += qp[x - 1];
				}
			}
		}
		memset(book , 0 , sizeof(book));
		fr(i , 1 , n)
		{
			cout << a[i] << ' ';
		}
		cout << '\n';
	}
 	return 0;
}