Educational Codeforces Round 84 (Rated for Div. 2)

Educational Codeforces Round 84 (Rated for Div. 2)

D: Infinite Path

【题意】:定义infinite path: i , p[i], p[p[i]], p[p[p[i]]] ......中所有颜色都相同,那么它就是一条infinite path。即c[i] = c[p[i]] = c[p[p[i]]] = ......。 定义:c = a × b,c[i] = b[a[i]]。求最小的k满足 \(p^k(p×...×p)\) 中存在至少一个infinite path。

分析:首先我们应该知道如果存在一个i = p[i]的话或者所有c[i]都相等的话是肯定满足的,那么k就等于1。否则的话它就是一个置换群。首先求出所有环的长度,可以用dfs处理。求出环的长度后,我们只需枚举环的因子,看看所有因子的倍数在环中的颜色是否相同,如果全都相同,那么就可以更新答案。

#include <bits/stdc++.h>
#define debug(x) cout << #x << " = " << x << endl; 

using namespace std;
typedef long long LL;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6, pi = acos(-1);
int gcd(int a,int b)    { return b == 0 ? a : gcd(b, a % b); }\

int p[maxn], c[maxn], n;
int vis[maxn];
vector<int> path;
void dfs(int now, int val)
{
    vis[val] = 1;
    if(now == val)  return;
    path.push_back(val);
    dfs(now, p[val]);
}

int main()
{
    int t; scanf("%d", &t);
    while(t--){
        scanf("%d", &n);
        int ok = 0, flag = 1;
        for(int i = 1; i <= n; ++i){
            vis[i] = 0;
            scanf("%d", &p[i]);
            if(i == p[i])   ok = 1;
        }
        for(int i = 1; i <= n; ++i){
            scanf("%d", &c[i]);
            if(i > 1 && c[i] != c[i-1]) flag = 0;
        }
        if(ok || flag)  puts("1");
        else{
            int ans = inf;
            for(int i = 1; i <= n; ++i){
                if(vis[i])  continue;
                vis[i] = 1;
                path.clear();   path.push_back(i);      //path记录一个置换群的长度
                dfs(i, p[i]);   
                for(int j = 1; j <= path.size(); ++j){  //枚举环的长度的因子
                    if(path.size() % j)     continue;
                    for(int k = 0; k < j; ++k){
                        int ok = 1;
                        for(int z = k; z < path.size(); z += j){
                            if(c[path[k]] != c[path[z]]){
                                ok = 0;
                                break;
                            }
                        }
                        if(ok)  ans = min(ans, j);
                    }
                }
            }
            printf("%d\n", ans);
        }
    }
}

E.Count The Blocks

【题意】:问$ 0 \ 到 \ 10 ^ n - 1$中有多少个连续相等长度为i的块。

【分析】:首先 i = n时,只有n个0到n个9符合。即答案为10。根据这个我们用组合数学的知识想一想,首先设相等的长度为i,那么它的值能取0 ~ 9中\(C_{10}^{1}\)个数,与他相邻的必须与他不同取\(C_{9}^{1}\)个数。如果那个块在数字的连个边缘,那么它的贡献就是:\(C_{10}^{1} * C_{9}^{1} * 10 ^ {n - i - 1} * 2\),如果在中间那么它的贡献就是:\(C_{10}^{1} * C_{9}^{1} * C_{9}^{1} * (n - i - 2 + 1) * 10 ^ {n - i - 2}\),其中(n - i - 2 + 1)表示在n - 2中取长度为 i 的连续长度的个数。

#include <bits/stdc++.h>
#define debug(x) cout << #x << " = " << x << endl; 

using namespace std;
typedef long long LL;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f, mod =  998244353;
const double eps = 1e-6, pi = acos(-1);
int gcd(int a,int b)    { return b == 0 ? a : gcd(b, a % b); }

int n;
LL qpow(LL a, LL b)
{
    //if(b < 0)   return 0;
    LL ans = 1;
    while(b){
        if(b & 1)   ans = (ans * a) % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}

int main()
{
    cin >> n;
    //只要那一段属于就可以了,不用管别的段是不是也有长度为i的段
    for(int i = 1; i <= n; ++i){
        if(i == n)  printf("10 ");
        else if(i == n-1)   printf("180 ");
        else{
            LL ans = (18 * qpow(10, n - i) % mod + 81 * qpow(10, n - i - 1) * (n - i - 1) % mod) % mod;
            printf("%lld ",ans);
        }
    }
    puts("");
    //system("pause");
}
posted @ 2020-03-25 10:02  StungYep  阅读(174)  评论(0编辑  收藏  举报