Codeforces Round #698 (Div. 2)

比賽地址c++

A(水題)

題目連接
數組

題目:
給出一個非嚴格單調遞增的序列,分割成儘量少的嚴格單調遞增序列spa

解析:
因爲所給序列是非嚴格單調遞增的,因此假如對這個序列進行去重,那麼就已是一個嚴格單調遞增的序列了,那麼重複次數最多的元素,就決定了分割的最小數目3d

#include<bits/stdc++.h>
#define MEM(X,Y) memset(X,Y,sizeof(X))
typedef long long LL;
using namespace std;
/*===========================================*/

int vis[105];

int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		MEM(vis, 0);
		int ret = 0;
		int n;
		scanf("%d", &n);
		int t;
		for (int i = 0; i < n; ++i)
		{
			scanf("%d", &t);
			ret = max(ret, ++vis[t]);
		}
		printf("%d\n", ret);
	}
}

B(思惟)

題目連接
⭐⭐code

題目:
給出\(d(1\le d\le 9)\)\(k\),詢問是否能夠由若干個數中含有\(d\)的數累加得到\(k\)排序

解析:隊列

  1. 首先能夠肯定,對於\(d0\sim d9\)這些數確定能夠獲得,那麼這些數加上\(nd\)必定能夠得到以後的全部數
  2. 那如今考慮\(k< d0\)的狀況,這個時候必定是由\(1d,2d,3d,\dots ,(d-1)d,n\times d\),累加而成,那麼能夠確定\(k-n\times d(n\ge1)\)必定是\(10\)的倍數,且\(d\)不超過\(9\),保證了時間複雜度
#include<bits/stdc++.h>
using namespace std;

int main()
{
	int T;
	scanf("%d", &T);
	while (T--) {
		int q, t, d;
		scanf("%d%d", &q, &d);
		while (q--)
		{
			scanf("%d", &t);
			if (t >= d * 10)
				printf("YES\n");
			else
			{
				t -= d;
				while (t >= 0 && t % 10) t -= d;
				printf("%s\n", t < 0 ? "NO" : "YES");
			}
		}
	}

}

C(思惟)

題目連接
⭐⭐⭐get

題目:
給出一個長度爲\(2n\)序列,問是否存在另外一個序列\(dat\),使得每一個元素\(d[i]=\sum_{j=1}^n|dat[i]-dat[j]|\),且若存在\(dat[i]\)必有\(dat[i]+dat[j]=0\)\(dat\)中每一個元素互不相同it

解析:io

  1. 若是\(a>b\)那麼\(|a-b|+|a+b|=2|a|\),反之\(|a-b|+|a+b|=2|b|\)
  2. 假如將原數組\(dat\)中的數按絕對值從小到大排序,對於排名爲\(i_{th}\)\(dat[i]\),其對應的\(d[i]\)\(2\times(i\times dat[i]+dat[i+1]+\dots+dat[n])\),且其相反數對應的\(d[i]\)值應與之相同
  3. 那麼就能夠肯定\(d\)中的每一個數只能出現兩次(在\(dat\)中的對應位置元素爲某個絕對值對應的正值或負值),且必須均爲偶數
  4. 而且由\(d[i]\)的公式能夠知道,對於絕對值增大的序列,其對應的\(d\)也是逐漸增大的,那麼可使用優先隊列遞推求解出對應的原絕對值,若是出現小於等於0的或沒法整除剩餘個數時則判錯
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
/*===========================================*/

const int maxn = 1e5 + 5;

set<long long, greater<long long>> s;
unordered_map<long long, int> m;
LL cnt, sum;

int main()
{
	int T;
	LL t;
	scanf("%d", &T);
	while (T--)
	{
		m.clear();
		s.clear();
		int n;
		bool ok = true;
		sum = cnt = 0;
		scanf("%d", &n);
		for (int i = 0; i < 2 * n; ++i)
		{
			scanf("%lld", &t);
			if (t & 1 || m[t] == 2) ok = false;
			if (!ok) continue;
			if (m[t])
				++cnt;
			else
				s.insert(t);
			++m[t];
		}
		if (cnt != n || !ok)
		{
			printf("NO\n");
			continue;
		}
		while (!s.empty())
		{
			t = *s.begin() / 2;
			s.erase(s.begin());
			t -= sum;
			if (t <= 0 || t % cnt)
			{
				ok = false;
				break;
			}
			sum += t / cnt;
			--cnt;
		}
		if (ok)
			printf("YES\n");
		else
			printf("NO\n");
	}
}

D(裴蜀定理)

題目連接
⭐⭐⭐⭐

題目:
給出一個數組,每次抽取兩個數\(x,y\),將\(2x-y\)新增入數組,問這樣的操做容許進行若干次,能否得到目標數\(k\)

解析:

  1. 假設\(x\)爲任意\(dat\)中的元素,第一次進行操做\(2\times dat[i]-x\),第二次將這個數做爲新的\(y\),又挑選新的\(dat[j]\)\(\underbrace{2\times(dat[j]-dat[i])}_p+x=k\),若是下括號這部分記爲\(p\),顯然\(p=2\times\sum_{i=1}^n\sum_{j=1}^n(k_{j,i}\times(dat[j]-dat[i]))\)
  2. 由裴蜀定理能夠知道,\(p\)的結果必定爲\(d=2\times gcd(dat[j]-dat[i])\{i,j|i,j\in n\}=2\times gcd(dat[i]-dat[i-1])\{i|i>1\}\)的倍數
  3. 這樣能夠得到全部能表式出的\(k\)

\[\begin{cases} x+nd=k &\text{Number of operations is even}\\ 2\times dat[j]-dat[i]+nd=k &\text{Number of operations is odd} \end{cases} \]

#include<bits/stdc++.h>
#define rep(i,a,b) for(int  i=a;i<b;++i)
#define rep1(i,a,b) for(int  i=a;i<=b;++i)
typedef long long LL;
using namespace std;
/*===========================================*/

template<typename T>
T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }

const int maxn = 2e5 + 5;
LL dat[maxn];


int main()
{
	int T;
	int n;
	LL k;
	scanf("%d", &T);
	while (T--)
	{
		LL d = 0;
		scanf("%d%lld", &n, &k);
		rep(i, 0, n)
			scanf("%lld", &dat[i]);
		rep(i, 1, n)
			d = gcd(abs(dat[i] - dat[i - 1]), d);
		d *= 2;
		k = (k % d + d) % d;
		bool ok = false;
		rep(i,0,n)
			if ((dat[i] % d + d) % d == k || ((2 * dat[1] - dat[i]) % d + d) % d == k)
			{
				ok = true;
				break;
			}
		printf("%s\n", ok ? "YES" : "NO");
	}
}
相關文章
相關標籤/搜索