Codeforces Round #564(div2)
Posted wyxdrqc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #564(div2)相关的知识,希望对你有一定的参考价值。
Codeforces Round #564(div2)
本来以为是送分场,结果成了送命场.
菜是原罪
A
SB题,上来读不懂题就交WA了一发,代码就不粘了
B
简单构造
很明显,\(n*n\)的矩阵可以按照这个顺序排列
然后根据\(n\)的大小搞一搞就好了
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
using namespace std;
const int N = 1e5 + 3;
inline int read()
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch))
if(ch == '-') c = -1;
ch = getchar();
while(isdigit(ch))
v = v * 10 + ch - 48;
ch = getchar();
return v * c;
int n,m;
int aa[N];
int main()
n = read();
aa[1] = 1;
for(int i = 1;i <= 10000;++i) aa[i] = 2 * i - 1;
int now = 1;
while(aa[now] < n) now++;
printf("%d\n",now);
for(int i = 1;i <= now;++i)
printf("1 %d\n",i);
int cc = 2;
for(int i = now + 1;i <= n;++i)
printf("%d %d\n",cc,now),cc++;
return 0;
C
送命题,卡了一个多小时,非常思维的一道题目
首先,答案肯定不会超过\(2*n\),最坏情况我们将非空白牌都攒在手上然后一张一张打出
我们有两种策略
1:直接将手中的牌打出,这时需要满足队尾的一个\(1\)开头的连续字段的结尾的下一张牌在我们的手中,后者我们可以通过上一次摸到.所以如果队尾有连续子段,那么我们就判一下能否直接插入,若果可以,显然这是最优解
2:当队尾不符合上述条件,或者我们没办法接上连续字段时,我们就要一直攒牌,在某一时刻依次打出
我们设\(p_i\)表示\(i\)号牌在队列中的位置(不在队列视为\(0\)),接着,若果我们在\(p_i\)成为队头的时刻(设为\(t\))打出
首先需要满足\(\max_i = t^npi - (i - 1) == p_i-(i - 1)\)
\(p_i-(i - 1)\)是最难理解的地方.
我理解为我们插入了\(i - 1\)次时,还有要几步才可以将\(i\)给搞出来(此时我们已经默认我们有了\(1—i - 1\))
也就是说,我确保手里有\(1—i - 1\)并且至少再插完\(i - 1\)之前摸到\(i\)必须再插入\(p_i-(i - 1)\)次,因为我的手中有\(1—i- 1\),这个是不算贡献的(或者重叠部分只算一次)
但是如果这时我们手中没有\(i - 1\)该怎么办?
没关系,如果出现上述情况\(p_i - 1\)一定在\(p_i\)后面,我们取得是最大值,\(p_i + 1\)的贡献显然要大
所以答案就是\(n + max_i =1^np_i-i+1\)
#include<cstdio>
#include<cctype>
#include<iostream>
using namespace std;
const int N = 2e5 + 3;
int p[N];
int a[N];
int b[N];
int book[N];
int n;
inline bool check()
for(int i = 1;i <= n;++i) if(book[i] == 0) return false;
return true;
int main()
scanf("%d",&n);
for(int i = 1;i <= n;++i) scanf("%d",&a[i]),book[a[i]] = 1;
for(int i = 1;i <= n;++i) scanf("%d",&b[i]),p[b[i]] = i;
// bool flag = 0;
int now = n;
while(now >= 2 && b[now - 1] != 0 && b[now - 1] == b[now] - 1) now--;
// cout << now << endl;
int t = 1;
if(b[now] == 1)
for(int i = 1;i <= b[n];++i) book[i] = 1;
for(int i = b[n] + 1;i <= n;++i)
if(!book[i])break;
book[b[t]] = 1;
t++;
// cout << t << endl;
if(check())
printf("%d\n",now - 1);
return 0;
// cout << flag << endl;
// cout << t << endl;
// cout << "GG";
int ans = 0;
for(int i = 1;i <= n;++i)
ans = max(ans,p[i] - i + 1);
printf("%d\n",ans + n);
return 0;
D
首先,我们发现每一颗子树一定是连续的一段圆弧,所以每一颗子树互不影响,那么我们考虑\(DP\)求贡献
我们固定跟,设\(f_i\)表示以\(i\)为跟时的答案
\(f_i = (son_i + [i !=root])!\prod_j\in son_if_j\)
\(ans = nf_root\)
为什么呢
想一下,由于每颗子树是互不影响的所以总答案一定和子树答案的乘积有关,又因为他们的相对顺序没有限制
所以和儿子数量的阶乘有关系,但是当前父节点不为跟时,也要参与排列.
而跟有\(n\)个位置可以放
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
using namespace std;
const int N = 3e5 + 3;
const LL mod = 998244353;
vector <int> G[N];
LL ans = 0;
int son[N];
LL dp[N];
LL inv[N];
inline int read()
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch))
if(ch == '-') c = -1;
ch = getchar();
while(isdigit(ch))
v = v * 10 + ch - 48;
ch = getchar();
return v * c;
int n;
inline void dfs(int x,int f)
dp[x] = 1;
for(int i = 0;i < (int)G[x].size();++i)
int y = G[x][i];
if(y == f) continue;
dfs(y,x);
son[x]++;
int w = (x != 1) ? son[x] + 1: son[x];
for(int i = 0;i < (int)G[x].size();++i)
int y = G[x][i];
if(y == f) continue;
dp[x] = dp[x] * dp[y] % mod;
dp[x] = dp[x] * inv[w] % mod;
int main()
inv[0] = 1;
n = read();for(int i = 1;i <= n;++i) inv[i] = inv[i - 1] * i % mod;
for(int i = 1;i < n;++i)
int x = read(),y = read();
G[x].push_back(y);
G[y].push_back(x);
dfs(1,0);
printf("%I64d\n",dp[1] * n % mod);
return 0;
以上是关于Codeforces Round #564(div2)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #564 (div. 2)
Codeforces Round #705 (Div. 2)
Codeforces Round #774 (Div. 2)