Educational Codeforces Round 84 (Rated for Div. 2)(A-E)

本文回顾了Educational Codeforces Round 84的比赛经验,详细解析了A到D题目的解题思路,强调了读题准确性和思维题的重要性,分享了D题使用置换群理论解决同色圆寻找问题的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Educational Codeforces Round 84 (Rated for Div. 2)

打爆的一场…


A
不写longlongWA3

B
写起来很恶心…题目还读错了…
考虑没有配对的公主和王子即可。

C
虽然知道是思维题但是就是想不到…淦!

题目允许移动2mn次,所以可以先花费至多m+n-2次将所有点堆叠在[1, 1]上,然后再用mn - 1次遍历所有方格,这样操作后每个点在遍历方格时一定会经过所需要经过的那个点。

很多时候题目做不出来要再读几遍题目…把一些关键的信息牢记于心…昨晚的[L, R]就是因为读题不慎而做不出来…

D
emm不算很难的题目,但是场上跟了风,没看D,去尝试做了E,但E也没做出来。。

之前在学习polya定理的时候稍微接触了一番置换群的有关概念,有了置换群的前置知识后这道题其实就没有什么难点了。

考虑k给定的情况,就是用步长k在置换群上造圆。题目要求找出最小的k,使得存在这样一个圆,圆上所有元素的颜色相同。

赛后补题自己写的时候用了素因子去划分每个小圆,但是这样的算法其实很假。尽管想到了暴力找所有的因子(而不仅仅是素因子),但是感觉时间复杂度撑不住,就没有写下去。

然而标答就是枚举所有可能的因子,对每个因子 O ( m ) O(m) O(m)的查询一次是否存在同色圆。事实上,这样做的时间复杂度并不很大: 找所有的因子是线性的,复杂度 O ( m ) O(m) O(m);对于每个因子的查询是遍历一次小圆,可以认为复杂度接近 O ( m ) O(m) O(m);而对于总和不超过2e5的一堆数字,如果某个数字本身不大,那么尽管它占用因子的效率更高,但是在 O ( m ) O(m) O(m)查询时也由于其本身不大所以总和也不会太大,如果某个数字本身较大,那么虽然这个数字需要花费更多的时间,但是其余剩余的数字就会更小;而且在2e5内,某个数最多有100小几个因子,最小的这样的数是50400,有108个因子,哪怕有4个50400,也只会花费410050400 = 2e7的时间;再加上我们在判断的时候加上了i < ans的最优性剪枝,所以这样暴力遍历是完全ok的。

代码

const int inf = 1 << 30;
const int maxn = 2e5 + 10;
int p[maxn], c[maxn];

int N, ans;
struct{
    vector<int> vec;
    int n;
    
    void solve(int p){
        int ok, OK = 0;
        //划分成了p个小圆
        for(int j = 0; j < p; j++){
            ok = 1;
            int k = j + p;
            while(k < n){
                if(c[vec[k]] != c[vec[k - p]]){
                    ok = 0;
                    break;
                }
                k += p;
            }
            OK |= ok;
        }
        if(OK) ans = min(ans, p);
    }
    
    void sove(){
        n = (int)vec.size();
        ans = min(ans, n);
        for(int i = 1; i < n && i < ans; i++) if(n % i == 0)
            solve(i);
    }
    
}circle[maxn];


int vis[maxn];
int main(){
//    Fast;
//    getprime();
    int t; scanf("%d", &t); while(t--){
        ans = inf; N = 0;
        int n; scanf("%d", &n);
        for(int i = 1; i <= n; i++){
            scanf("%d", p + i);
            vis[i] = 0;
        }
        for(int i = 1; i <= n; i++) scanf("%d", c + i);
        
        for(int i = 1; i <= n; i++) if(!vis[i]){
            int now  = i;
            circle[N].vec.clear();
            while(!vis[now]){
                circle[N].vec.push_back(now);
                vis[now] = 1;
                now = p[now];
            }
            N++;
        }
        for(int i = 0; i < N; i++) circle[i].sove();
        printf("%d\n", ans);
    }
    return 0;
}

E
组合数学学的太菜了…

直接用乘法原理考虑一个长度为d的块在整个序列中的某个位置时可能产生的所有种数;不需要考虑重复的情况是因为如果一个数字中出现了多个d块,每一个位置的d块我们都会进行一次以它为核心的计数,而这整个数字在每次计数中都只会贡献1次,所以总共来看这若干个d块恰贡献了这些d块的个数次,也就不重不漏的完成了计数工作。

组合数学不能再咕了!🐦要赶紧开始学习了qwq

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值