2019.10.31模擬賽

說在前面

考場碰見原題???
上午剛作的 下午就\(T3\)考到了\(2333\)
然而仍是由於忘了取模掛了28分html

T1 Dove下跳棋

數據太水輸出n-1可得90
Dove 喜好下跳棋,在傳統的跳棋基礎之上,Dove 又延伸出了許多別的玩法。Dove 以一個一維數軸爲棋盤下跳棋,總共會移動棋子𝑛 − 1 次。由於討厭沒有規律,因此Dove 每次只會剛好把棋子向右移動𝑘 個格子。
Cicada 送給了Dove 一個長度爲𝑛 的數列{𝑎},爲了表示感謝,Dove 打算以Cicada
送給他的序列{𝑎} 爲基礎下跳棋。具體的,Dove 將會把棋子從編號爲𝑎1 的格子出發,在第𝑖 次移動後,把棋子移動到編號爲𝑎𝑖+1 的格子。顯然Cicada 送給他的{𝑎} 有可能不知足Dove 要求的條件,Dove 想知道,最少須要修改多少個𝑎𝑖 的值,才能使得這個數列{𝑎} 是知足Dove 須要的移動棋子的要求的。c++

你覺得從\(a1\)開始直接計算?不這是錯的。\(a1\)是能夠修改的。
正解:咱們推一波式子:
\(a_i + (j - i) * k = a_j\)
\(a_i - k * i = a_j - k * j\)
因此只要把這個數扔進map,相同的就是能夠到達的。
找到最多的能夠到的數,其他的就是要修改的。
這場比賽開c++11, unordered_map快到飛起。算法

unordered_map<int,int> mp;  
signed main()
{
	freopen("chess.in", "r", stdin);
	freopen("chess.out", "w", stdout);
	poread(n), poread(k);
	for(register int i = 1; i <= n; ++i) poread(a[i]);
	for(register int i = 1; i <= n; ++i) ++mp[a[i] - k * i]; 
	register int ans = INT_MAX;
	for(register int i = 1; i <= n; ++i) ans = min(n - mp[a[i] - k * i],ans);
	printf("%lld\n", ans);
	return 0;
}

T2 Cicada愛子串

做爲一個熟練的算法競賽選手,Cicada 喜好研究字符串問題。特別的,他尤爲喜好研究字符串中的子串問題。
某日,Cicada 在研究這樣一道題目。首先對於一個字符串𝑠,咱們定義其第𝑙 個字符到第𝑟 個字符構成的子串爲𝑠𝑙,𝑟。同時咱們定義函數𝑓(𝑠, 𝑙, 𝑟) 表示將字符串𝑠 的第𝑙 到第𝑟個字符刪去後構成的字符串,𝑔(𝑠, 𝑚, 𝑡) 表示將𝑡 插入𝑠 的第𝑚 個字符以後構成的字符串。
Cicada 想知道,對於一個給定的長度爲𝑛 的字符串𝑠,有多少個三元組(𝑙, 𝑟, 𝑚),知足𝑠 = 𝑔(𝑓(𝑠, 𝑙, 𝑟), 𝑚, 𝑠𝑙,𝑟)。
這題考場失智少算了狀況。
正解:
找到字符串的循環節,每個基本序列能夠放到循環節的每一個地方,加起來就是答案。
\(f[l][r]\)表示\(l,r\)這段區間最小循環節的循環次數,考慮貢獻。
對於\(l,r\)這段區間,咱們能夠在\(f[l][r]-1\)個位置把區間斷成兩段,把左邊區間放到右邊區間的右側,或者把右邊區間放到左邊區間的左側,而且加上本身放到本身位置產生的\(1\)的貢獻。
這麼作不會記重由於更多的區間分割可能包含在了更小的區間裏。函數

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 6e3 + 5;
const int MOD = 1e9 + 7;
const int HS = 17171;
unsigned long long has[MAXN], sh[MAXN];
char s[MAXN];
int f[MAXN][MAXN], v[MAXN];
int n;
inline unsigned long long str(int l, int r)
{
	return has[r] - has[l - 1] * sh[r - l + 1];
}
int main()
{
	scanf("%s", s + 1);
	n = strlen(s + 1);
	sh[0] = 1;
	for(register int i = 1; i <= n; ++i)
		sh[i] = sh[i - 1] * HS;  
	for(register int i = 1; i <= n; ++i)
		has[i] = (has[i - 1] * HS + s[i]);
	for(register int len = 1; len <= n; ++len)
	{
		memset(v, 0, sizeof(v));
		for(register int r = len; r <= n; ++r)
		{
			v[r] = 1;
			if(r >= (len << 1))
				if(str(r - len + 1,r) == str(r - len - len + 1, r - len))
					v[r] += v[r - len];
			f[r - v[r] * len + 1][r] = max(f[r - v[r] * len + 1][r], v[r]);
		}
	}
	register long long ans = 0;
	for(register int l = 1; l <= n; ++l)
	{
		for(register int r = n; r >= l; --r)
		{
			f[l][r] = max(f[l][r], 1);
			register int len = (r - l + 1) / f[l][r];
			if(l + len <= r)
				f[l + len][r] = max(f[l + len][r], f[l][r] - 1);
			if(r - len >= l)
				f[l][r - len] = max(f[l][r - len], f[l][r] - 1);
			ans += 1 + ((f[l][r] - 1) << 1);
		}
	}
	cerr << ans << endl;
	cout << ans << endl;
	return 0;
}

T3

昨天剛寫了博客,直接看吧。
code festival 2016 qual C E題 順列辭書spa

相關文章
相關標籤/搜索