Educational Codeforces Round 103 (Rated for Div. 2)

比賽地址c++

A(水題)

題目連接
數組

題目:
給出\(n\)\(k\)詢問,若\(k\)能整除\(n\)個數累加和,問這\(n\)個數中最大值最小化時值爲多少app

解析:
由題目條件知\(n\ge 1\),若是\(n\le k\),則每一個元素至少爲1,那麼這樣狀況下平均分配能讓最大值最小化,同理\(n>k\)時,則使得\(n\le dk\),且\(dk\%n<k\)也就是讓這個\(dk\)越小越好編碼

注:\(\lceil\frac{a}{b}\rceil=\lfloor\frac{a+b-1}{b}\rfloor\)spa

#include<bits/stdc++.h>
using namespace std;
/*===========================================*/
int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int n, k;
		scanf("%d%d", &n, &k);
		k *= (n + k - 1) / k;
		printf("%d\n", (k + n - 1) / n);
	}
}

B(貪心)

題目連接
code

題目:
給出\(p\)數組,公式\(k_i=\frac{p[i]}{\sum_{j=0}^{i-1}p[j]}\),要求\(k_i\)均小於等於指定數值\(k\%\),如今若是要知足這個要求,可能須要對數組\(p\)部分元素進行增長,則總增長量最小是多少遞歸

解析:
不難發現對於當前\(i\)來講,增長本身或者增長\(j(j>0)\),是充滿不肯定性的,由於這樣的操做可能會使得\(k_i>k\%\),因此若是增長值所有匯聚在\(p_0\)是最好的(\(k_0\)與題目要求無關),那麼只須要找到使得每一個元素符合要求的最小增長量便可字符串

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

int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		LL sum, t;
		LL ret = 0;
		int n, k;
		scanf("%d%d", &n, &k);
		scanf("%lld", &sum);
		rep(i, 1, n)
		{
			scanf("%lld", &t);
			if (100 * t > k * sum)
			{
				LL tmp = (100 * t + k - 1) / k;
				ret += tmp - sum;
				sum = tmp;
			}
			sum += t;
		}
		printf("%lld\n", ret);
	}
}

C(思惟)

題目連接
⭐⭐⭐get

題目:
給出\(n\)條鏈長度爲\(c[i]\)\(a,b\)數組,數組表示第\(i\)條鏈的「1」端鏈接至第\(i-1\)條鏈的\(a[i]\)處,「\(c[i]\)」端鏈接至第\(i-1\)條鏈的\(b[i]\)處,假設每一個鏈接的長度爲單位長度,求這個圖中的最大環it

解析:

  1. 因爲兩兩鏈之間只能靠\(a[i],b[i]\)決定的邊相連,因此這個最大環的求解是一個線性遞推的過程
  2. 假設當前下標爲\(i\),能夠將環的構造抽象爲爲2種可能性:①以第\(i-1\)條鏈爲圈的邊界 ②不以第\(i-1\)條鏈爲圈的邊界,兩種狀況下所獲得的最大值加上當前\(c[i]\)鏈長度(即將環封閉),更新最大值便可
  3. 對於①的狀況,則爲\(2+|a[i]-b[i]|\)
  4. 對於②的狀況,爲避免點的重複通過,此時新增的長度爲\(2+(c[i-1]-\max(a[i],b[i]))(距離右端點)+(\min(a[i],b[i])-1)(距離左端點)\)

注意:

  1. 處於第\(1\)條鏈時,只能以第\(0\)條鏈爲邊界,因此只能考慮①的狀況
  2. 注意開\(long\ long\)
#include<bits/stdc++.h>
#define rep(i,a,b) for(int  i=a;i<b;++i)
typedef long long LL;
using namespace std;
/*===========================================*/

const int maxn = 1e5 + 5;
int a[maxn], b[maxn], c[maxn];
LL ret, now;


int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int n;
		scanf("%d", &n);
		rep(i, 0, n)
			scanf("%d", &c[i]);
		rep(i, 0, n)
			scanf("%d", &a[i]);
		rep(i, 0, n)
			scanf("%d", &b[i]);
		now = ret = 0;
		rep(i, 1, n)
		{
			if (i != 1)
			{
				if (a[i] == b[i])
					now = 2;
				else
					now += 2LL + min(a[i], b[i]) - 1 + c[i - 1] - max(a[i], b[i]);
			}
			now = max(now, 2LL + abs(a[i] - b[i]));
			ret = max(ret, now + c[i] - 1);
		}
		printf("%lld\n", ret);
	}
}

D(思惟)

題目連接
⭐⭐

題目:
給出一個字符串,若是第\(i\)個字符爲\(L\)則表明存在通路\(i-1\rightarrow i\)\(R\)表明存在通路\(i-1\leftarrow i\),且每使用一次道路,全部道路方向反向,那麼求出起始點在第\(i\)點可以途徑點數的最大值

解析:

  1. 假設從\(i\)點出發,能夠向某個方向前進,那麼,在朝那個方向前進後,因爲道路的轉向可使得按照原線路返回,且因爲一來一回確定使用了偶數次道路,那麼回到起始點時,道路狀態與初始時相同,那麼即求從\(i\)點向左向右能行進的最大距離之和
  2. 而行進距離則就是看左右兩邊各有多少個交替的\(RL\)序列,求左邊的序列長度能夠正序遍歷字符串,右邊的序列長度能夠倒序遍歷字符串
#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)
#define rrep(i,a,b) for(int i=b-1;i>=a;--i)
#define rrep1(i,a,b) for(int i=b;i>=a;--i)
using namespace std;
/*===========================================*/

const int maxn = 3e5 + 5;
char s[maxn];
int l[maxn], r[maxn];

int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int n;
		scanf("%d%s", &n, s + 1);
		l[0] = r[n] = 0;
		int cnt = 0;
		rep1(i, 1, n)
		{
			if (s[i] != s[i - 1])
				++cnt;
			else
				cnt = 1;
			if (s[i] == 'L')
				l[i] = cnt;
			else
				l[i] = 0;
		}
		cnt = 0;
		rrep1(i, 1, n)
		{
			if (s[i] != s[i + 1])
				++cnt;
			else
				cnt = 1;
			if (s[i] == 'R')
				r[i - 1] = cnt;
			else
				r[i - 1] = 0;
		}
		rep1(i, 0, n)
			printf("%d ", l[i] + r[i] + 1);
		printf("\n");
	}
}

E(狀壓+拓撲序)

題目連接
⭐⭐⭐

題目:
給出\(n\)個模式串和\(m\)個待匹配串,且每一個待匹配串有一個指望值\(mt\),詢問是否能夠將模式串從新排列,使得第一個遇到的成功匹配的模式串是第\(mt\)個串
字符串長度\(k(1\le k\le4)\)

解析:

  1. 若存在某個待匹配串能夠匹配多個模式串時,要求第\(mt\)串必須排列在前,這是一個很明顯的拓撲序關係
  2. 那麼只須要將\(mt\)與其餘能夠匹配的串連邊,並記錄好入度,輸出拓撲序便可
  3. 因爲字符串長度很小,並且出現字符只有\(a-z,\_\)(27),\(27^4\approx5\times10^5\),因此能夠進行狀壓,\(O(1)\)查詢
  4. 能夠遞歸的將待匹配串的字符改爲「_」,查詢對應的狀壓編碼是否存在過,以此找到模式串

注意: 對於給出\(mt\)模式串自己,沒法與對應的字符串進行匹配的狀況須要特殊處理

#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)
using namespace std;
/*===========================================*/
 
const int maxn = 27 * 27 * 27 * 27;
char s[5];
int vis[maxn];
int d[maxn];
vector<int> e[maxn];
int n, m, k, mt;
int dat[100005];
int Pow[4] = { 1,27,27 * 27,27 * 27 * 27 };
 
void check(int x)
{
	if (vis[x])
	{
		++d[vis[x]];
		if (vis[x] != mt)
			e[mt].push_back(vis[x]);
	}
}
 
void fill(int now, int x)
{
	if (x == k)
		check(now);
	else
	{
		fill(now, x + 1);
		fill(now + (26 - s[x] + 'a') * Pow[k - x - 1], x + 1);
	}
}
 
int main()
{
	scanf("%d%d%d", &n, &m, &k);
	rep1(i, 1, n)
	{
		scanf("%s", s);
		int t = 0;
		rep(j, 0, k)
		{
			t *= 27;
			t += s[j] == '_' ? 26 : s[j] - 'a';
		}
		vis[t] = i;
	}
	rep(i, 0, m)
	{
		scanf("%s%d", s, &mt);
		int t = 0;
		rep(j, 0, k)
		{
			t *= 27;
			t += s[j] - 'a';
		}
		fill(t, 0);
		--d[mt];
	}
	queue<int> q;
	rep1(i, 1, n)
	{
		if (!d[i])
			q.push(i);
	}
	int cnt = 0;
	while (!q.empty())
	{
		int t = q.front();
		q.pop();
		dat[++cnt] = t;
		for (auto& i : e[t]) {
			if (--d[i] == 0)
				q.push(i);
		}
	}
	if (cnt == n)
	{
		printf("YES\n");
		rep1(i, 1, n)
			printf("%d ", dat[i]);
	}
	else
		printf("NO");
}
相關文章
相關標籤/搜索