考场碰见原题???
上午刚作的 下午就\(T3\)考到了\(2333\)
然而仍是由于忘了取模挂了28分html
数据太水输出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; }
做为一个熟练的算法竞赛选手,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; }
昨天刚写了博客,直接看吧。
code festival 2016 qual C E题 順列辞書spa