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_i}f_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;
}

原文地址:https://www.cnblogs.com/wyxdrqc/p/10990378.html

时间: 2024-10-03 22:29:51

Codeforces Round #564(div2)的相关文章

codeforces round #257 div2 C、D

本来应该认真做这场的,思路都是正确的. C题,是先该横切完或竖切完,无法满足刀数要求,再考虑横切+竖切(竖切+横切), 因为横切+竖切(或竖切+横切)会对切割的东西产生交叉份数,从而最小的部分不会尽可能的大. 代码如下,虽然比较长.比较乱,但完全可以压缩到几行,因为几乎是4小块重复的代码,自己也懒得压缩 注意一点,比如要判断最小块的时候,比如9行要分成2份,最小的剩下那份不是9取模2,而应该是4 m/(k+1)<=m-m/(k+1)*k          #include<bits/stdc+

codeforces Round #250 (div2)

a题,就不说了吧 b题,直接从大到小排序1-limit的所有数的lowbit,再从大到小贪心组成sum就行了 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #define N 200000 6 using namespace std; 7 int pos[N],a[N],s[N],f[N],la[N],b[N],i,j,k,ans,n,p

Codeforces Round#320 Div2 解题报告

Codeforces Round#320 Div2 先做个标题党,骗骗访问量,结束后再来写咯. codeforces 579A Raising Bacteria codeforces 579B Finding Team Member codeforces 579C A Problem about Polyline codeforces 579D "Or" Game codeforces 579E Weakness and Poorness codeforces 579F LCS Aga

Codeforces Round #254(div2)A

很有趣的题.想到了就非常简单,想不到就麻烦了. 其实就是一种逆向思维:最后结果肯定是这样子: WBWBWBWB... BWBWBWBW... WBWBWBWB... ... 里面有“-”的地方改成“-”就行了. 但是我开始是正着想的,想每个点怎么处理,这还要看它周围点的状态,越想越麻烦... 这题中体现的正难则反的逆向思维很值得学习. #include<iostream> #include<cstdio> #include<cstdlib> #include<cs

Codeforces Round #254(div2)B

就是看无向图有几个连通块,答案就是2n-num. 范围很小,就用矩阵来存图减少代码量. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<map> #include<set> #include<vector> #include<algorithm> #inc

Codeforces Round #260(div2)C(递推)

有明显的递推关系: f[i]表示i为数列中最大值时所求结果.num[i]表示数i在数列中出现了几次. 对于数i,要么删i,要么删i-1,只有这两种情况,且子问题还是一样的思路.那么很显然递推一下就行了:f[i]=max(f[i-1],f[i-2]+i*num[i]); 这里技巧在于:为了防止麻烦,干脆就所有数的出现次数都记录一下,然后直接从2推到100000(类似于下标排序),就不用排序了,也不用模拟删除操作了.这一技巧貌似简单,但实际上临场想出来也需要点水平. #include<iostrea

Codeforces Round #289 Div2 E

Problem 给一串长度为N的字符串,对于每个字符,若字符为元音,则权值为1,否则为0.一个子串的权值定义为该串所有字符权值之和除以字符个数,一个母串的权值定义为所有子串的权值之和.求母串的权值. Limits Time Limit(ms): 1000 Memory Limit(MB): 256 N: [1, 5*10^5] 字符集: 'A'-'Z' 元音: I E A O U Y Solution 考虑每个元音字符对母串的贡献,可以找出规律. More 举"ABCDOEFGHKMN"

Codeforces Round #403 div2 C. Andryusha and Colored Balloons

题目链接:Codeforces Round #403 div2 C. Andryusha and Colored Balloons 题意: 给你一棵n个节点的树,然后让你染色,规定相连的三个 节点不能同色,问需要的最少颜色,并输出其中一种方案. 题解: 因为只有相邻3个节点不同色. 所以直接DFS,每个节点都从1开始. 然后ans[v]!=ans[u]!=ans[fa]就行. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i&

CodeForces Round#229 DIV2 C 递推DP

对这道题目也只好说呵呵了,没注意k的范围最大才10,所以昨晚纠结了很久,没什么好的方法来处理,后来无奈想去翻翻题解,发现人家开头就来了句,因为k的范围比较小 所以.........我只好暂停马上回头看看题目,是的,k比较小所以完全可以先在询问前预处理DP一遍, DP就比较清晰了,dp[i][j]  (i>=0 && i<k,,,,j>=i && j <=n)代表意义呢 以i为开头的  区间[1,j]注意 是 1~j的 所需要的操作数,题目问的是最小操