两道CF题。
CF483C
Description
构造一个长度为 $n$ 的排列,使得集合 $\{|p_i-p_{i+1}|\}$ 的大小为 $k$。$n\leq10^5$。
Solution
构造题,乱搞。
考虑大小是 $1$ 非常好构造,$1,2,3,4,…,n$。(似乎没啥用)
于是考虑构造集合中元素是 $1,2,…,k$ 的一个排列。注意到 $n$ 很大的时候可以让差全部为 $1$,所以在前面构造一下就行。
即前两个数差为 $k$,第二个和第三个差为 $k-1$,以此类推(
手算:大小是 $2$ 可以用以下方式简单构造 $1,3,2,4,5,6,…,n$,大小是 $3$ 也很简单:$1,4,2,3,5,6,…,n$。
然后构造一个 $1,k+1,2,k,3,k-1…$ 的排列就好了,具体实现还是用的差递减来构造。(话说这个构造很眼熟啊,似乎和洛谷上一道构造题的第一问很像)
Code
#include <algorithm>
#include <cstdio>
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
const int maxn = 1e5 + 10;
int n, k;
int a[maxn];
int main()
{
cin >> n >> k;
a[1] = 1;
int i;
for (i = 2; k >= 1; k--, i++)
{
if (i & 1)
a[i] = a[i - 1] - k;
else
a[i] = a[i - 1] + k;
}
for (; i <= n; i++)
a[i] = i;
for (int i = 1; i <= n; i++)
cout << a[i] << " ";
cout << endl;
}
CF508D
Description
给出 $n$ 个长度为 $3$ 的字符串,求一个长度为 $n+2$ 的字符串,使其所有长度为 $3$ 的子串能与给定串一一对应。$n\leq10^5$。
Solution
这个模型以前见过,只需要搞欧拉路即可。(已经当定理背下来了)
要硬说的话,会想到两种建模:每个单词作为顶点,然后在点之间连有向边,找哈密顿路。这显然不行。。。
然后就是很好的建模了,把每个字母作为点,单词作为有向边,这样就变成找欧拉路,能高效求解。。。
这个模型目前还没见到其他应用,不过也记下来,万一有用呢。。。
回到本题,把两个字符当成一个点就行。
坑点:这题有大小写字母,还有数字,注意 ASCII 码的顺序:数字<大写字母<小写字母。我懒得写正经哈希,就直接乱搞了,不注意 ASCII 码顺序就容易 RE。。。
Code
我代码又慢又丑。。。
#include <algorithm>
#include <iostream>
#include <stack>
#include <string>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::string;
const int maxn = 100000;
inline int change(char a, char b) { return (a - '0') * 100 + (b - '0'); }
inline string p(int x)
{
string s = " ";
s[1] = char(x % 100 + '0');
s[0] = char(x / 100 + '0');
return s;
}
int rd[maxn], cd[maxn];
std::vector<int> e[maxn];
inline void add_(int x, int y) { e[x].push_back(y), rd[y]++, cd[x]++; }
inline void add(const string &x) { add_(change(x[0], x[1]), change(x[1], x[2])); }
std::stack<int> ans;
int n;
void dfs(int x)
{
while (e[x].size())
{
int v = e[x].back();
e[x].pop_back();
dfs(v);
}
ans.push(x);
}
int main()
{
std::ios::sync_with_stdio(false);
cin >> n;
for (int i = 1; i <= n; i++)
{
string s;
cin >> s;
add(s);
}
int cnt1 = 0, cnt2 = 0, ok = 1;
int u = -1;
for (char c = '0'; c <= 'z'; c++)
for (char c2 = '0'; c2 <= 'z'; c2++)
{
int x = change(c, c2);
if (abs(rd[x] - cd[x]) > 1)
{
ok = 0;
break;
}
else if (cd[x] - rd[x] == 1)
cnt1++, u = x;
else if (rd[x] - cd[x] == 1)
cnt2++;
}
if (!(cnt1 + cnt2 == 0 || (cnt1 == 1 && cnt2 == 1)))
ok = 0;
if (!ok)
{
cout << "NO" << endl;
return 0;
}
if (u != -1)
dfs(u);
else
{
for (char c = '0'; c <= 'z'; c++)
for (char c2 = '0'; c2 <= 'z'; c2++)
if (cd[change(c, c2)])
u = change(c, c2);
dfs(u);
}
if (ans.size() != n + 1)
{
cout << "NO" << endl;
}
else
{
cout << "YES" << endl;
cout << p(ans.top())[0] << p(ans.top())[1];
ans.pop();
while (!ans.empty())
{
cout << p(ans.top())[1];
ans.pop();
}
cout << endl;
}
}