Codeforces Round #694 (Div. 2)

比賽地址c++

A(水題)

題目連接
數組

題目:
給出\(n\)\(x\),對一個長度爲\(n\)的數組\(b\),能夠進行若干次合併任意兩個元素,問對於最後數組中的剩餘元素\(\sum \lceil\frac{b[i]}{x}\rceil\)的最小值和最大值分別是多少?編碼

解析:spa

  • 最小值:很顯然,讓全部元素所有合併成一個元素,這樣就能把向上取整所製造的空缺儘量地填補
  • 最大值:與最小值相反,不填不空缺,即讓數組保持原樣能夠達成目的
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n;

LL a[100005];

int main()
{
	LL r;
	int T;
	LL n, x;
	LL mx, mn;
	scanf("%d", &T);
	while (T--)
	{
		mx = 0, mn = 0;
		scanf("%lld%lld", &n, &x);
		for (int i = 0; i < n; ++i)
			scanf("%lld", &a[i]), mn += a[i], mx += (a[i] + x - 1) / x;
		printf("%lld %lld\n", (mn + x - 1) / x, mx);
	}
}

B(思惟)

題目連接
⭐⭐code

題目:
給出\(n\)\(x\),對一個長度爲\(n\)的數組\(a\),順序遍歷它的元素,若是遇到的元素能夠被\(x\)整除,則添加\(x\)\(\frac{a[i]}{x}\)到數組末尾,反之則使這個功能永久禁用,問遍歷過的元素和是多少?get

解析:it

  1. 能夠發現,添加\(x\)\(\frac{a[i]}{x}\)的操做其實遍歷了以後,新增元素的和仍是\(a[i]\),那麼問題就轉化爲數組中每一個元素的值出現過幾回,也就是在反覆循環遍歷這個數組。
  2. 須要求得循環遍歷數組的次數,設遇到的第一個不被\(x\)整除的數的祖先是\(a[q]\),那麼他必定是全部元素中擁有最小的\(x^{min}\)的冪次方做爲因子

\[a[0],a[1]\dots a[n-1],\underbrace{\frac{a[0]}{x}\dots}_{x},\underbrace{\frac{a[1]}{x}\dots}_{x}\underbrace{\frac{a[0]}{x^{min}}\dots}_{x^{min}}\ ,\dots,\underbrace{\frac{a[q]}{x^{min}}\dots}_{x^{min}} \]

  1. 這樣就能夠得知數組循環訪問了\(min\)次,且要注意在原數組中下標在\(q\)以前的數仍然被統計了
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n;

LL dat[100005];
LL sum;

int main()
{
	int T;
	LL n, x, t;
	int mn;
	scanf("%d", &T);
	while (T--)
	{
		mn = 0x3f3f3f3f;
		sum = 0;
		scanf("%lld%lld", &n, &x);
		for (int i = 0; i < n; ++i)
		{
			scanf("%lld", &dat[i]);
			sum += dat[i];
			int b = 0;
			LL j = 1;
			while (dat[i] % j == 0)
				j *= x, ++b;
			if (mn > b)
			{
				mn = b;
				t = i;
			}
		}
		LL ret = sum * mn;
		for (int i = 0; i < t; ++i)
			ret += dat[i];
		printf("%lld\n", ret);
	}
}

C (貪心)

題目連接
⭐⭐class

題目:
\(n\)我的,以及\(m\)個禮物,每一個人都只能買編號在\(a[i]\)以前的禮物,或者直接給\(a[i]\)對應的錢代替,每一個禮物只能被買一次,求給全部人送達禮物的最小金額(所給禮物序列按金額升序)test

解析:循環

  1. 因爲禮物愈來愈貴,因此編號靠後的人越應該早早拿到編號靠前的禮物,這樣就不用必須交靠後的禮物的錢了
  2. 那這樣即可以將人的需求編號從大到小遍歷,而且定義一個下標表明此時能夠送的禮物的最小下標,若是編號大於這個下標,那麼就能夠送禮物給他,不然由於編號以前的禮物已經被送過了,因此只能給對應的錢

兩者相等的狀況其實不須要考慮,由於即便選擇了購買禮物,下一我的的下標必定是小於等於當前的下標的,因此是確定用不到 (禮物金額<必交金額)這個貪心條件的

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n;
const int maxn = 3e5 + 5;
int k[maxn], c[maxn];

int main()
{
	int T;
	int n, x, t;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d", &n, &x);
		for (int i = 0; i < n; ++i)
			scanf("%d", &k[i]);
		sort(k, k + n);
		for (int i = 1; i <= x; ++i)
			scanf("%d", &c[i]);
		t = 1;
		LL ret = 0;
		for (int i = n - 1; i >= 0; --i)
			if (k[i] > t)
				ret += c[t++];
			else
				ret += c[k[i]];
		printf("%lld\n", ret);
	}
}

D(公式推導+質因數分解+哈希)

題目連接
⭐⭐⭐⭐

題目:
定義對於任意兩個元素知足\(\frac{lcm(a,b)}{gcd(a,b)}=x^2\)那麼認爲這兩個元素是相鄰的。如今給出一個數組,將彼此相鄰的元素當作一個組,每秒組內各元素都會被組的卷積所代替,那麼給出\(q\)次查詢,問每秒對應的組內元素個數的最大值是多少?

解析:

  1. 因爲\(lcm(a,b)=\frac{a\times b}{gcd(a,b)}\),因此\(a\times b=(x\times gcd(a,b)^2)\),所以能夠獲得\(\frac{lcm(a,b)}{gcd(a,b)}=x^2\Leftrightarrow a\times b=y^2\)\(a\times b\)也是一個徹底平方數
  2. 若是\(a\times b\)是一個徹底平方數,那麼對於\(a\)\(b\)來講,他們質因數分解後每一個質因子的指數的奇偶性相同,因而能夠用質因數分解判斷是否屬於同一組(用01表明每個質因數有偶數個或奇數個,哈希編碼)
  3. 同時能夠發現除第0s外,在之後的元素替換中,若是初始組內元素有偶數個或者質因數的指數均爲偶數,那麼在之後合成後的元素必定質因數的指數均爲偶數,同理若是初始組內元素有奇數各且存在質因數的指數不爲偶數,那麼會一直保持着這個狀態,因而能夠得出結論第\(0\)s爲一個狀態,第\(1\sim\infin\)爲另外一個狀態

注意:1s 的答案記得要在 0s 和 1s 中取最大值

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
/*===========================================*/

const int maxn = 1000;
const int base = 19260817;
bool vis[maxn];
int prime[500];
map<int, int> m;
int T, t, n, q, cnt;


int main()
{
	scanf("%d", &T);
	for (int i = 2; i < maxn; ++i) {
		if (!vis[i]) prime[cnt++] = i;
		for (int j = 0; j < cnt && i * prime[j] < maxn; ++j) {
			vis[i * prime[j]] = true;
			if (i % prime[j] == 0) break;
		}
	}
	while (T--) {
		m.clear();
		scanf("%d", &n);
		while (n--) {
			int tt = 0;
			scanf("%d", &t);
			for (int i = 0; i < cnt && t != 1; ++i) {
				if (t % prime[i] == 0) {
					int c = 0;
					while (t % prime[i] == 0) {
						t /= prime[i], ++c;
					}
					if (c & 1) tt = base * tt + prime[i];
				}
			}
			if (t != 1) tt = base * tt + t;
			++m[tt];
		}
		int ans[2] = { 0 };
		for (auto& i : m) {
			ans[0] = max(ans[0], i.second);
			if (!i.first || i.second % 2 == 0) ans[1] += i.second;
		}
		ans[1] = max(ans[0], ans[1]);
		scanf("%d", &q);
		while (q--)
		{
			scanf("%d", &t);
			printf("%d\n", ans[(bool)t]);
		}
	}
}
相關文章
相關標籤/搜索