(CF1367E)《》

· · 题解

Preface

好吧这题我早就做过了,现在又做到了,结果不会(?)

更好的阅读体验

::::info[关于下文中的“重复段”和“极大重复段”]

Problem

见洛谷题面和原题面。

Solution

我们发现极大重复段的段长一定是 k 的因数。

当然极大重复段的段长也一定是项链长度(设其为 i)的因数。显然项链长度也是可以枚举的。

所以我们可以设整条项链的某个重复段的长度 d\gcd(k,i),然后计算这个重复段的长度合不合法。

具体的,我们尽可能多的往每个重复段里平均分配珠子,也就是对于某种有 x 个的珠子,往每个重复段里分配 \lfloor x/\frac{i}{d} \rfloor 个珠子,然后计算珠子的数量能否凑出 d 个。

至于为什么我们设 d 为最大的合法的 d(即 \gcd(k,i)),可以看下面的解释。

::::info[解释]

a = m b,其中 m 为正整数。对任意正整数 c,由带余除法可得:

c = q a + r_a,\quad 0 \le r_a < a c = p b + r_b,\quad 0 \le r_b < b

这里 r_a = c \bmod ar_b = c \bmod b

a = m b 代入第一个等式:

c = qm b + r_a
根据带余除法的性质,\forall qm\le p,所以 \forall r_a\ge r_b。证毕。
::::

Code

::::success[代码在这里喵]

#include<bits/stdc++.h>
using namespace std;
int n,K;
string s;
int cnt[26];
void man(){
    memset(cnt,0,sizeof cnt);
    cin>>n>>K;
    cin>>s;
    for(int i=1;i<=n;i++){
        int k=s[i-1]-'a';
        cnt[k]++;
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        int d=__gcd(i,K);
        int res=0;
        for(int j=0;j<26;j++){
            res+=cnt[j]/(i/d);
        }
        if(res>=d) ans=i;
    }
    cout<<ans<<'\n';
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T;cin>>T;
    while(T--) man();
    return 0;
}

::::

Postscript

写题解不易喵,点个赞好不好喵~