2021CCPC网络赛第一场 1002 Time-division Multiplexing

博客主要讨论了一道编程竞赛题目,涉及到字符串处理和寻找包含指定字母集最短子串的问题。通过求解字符串的最小公倍数来构造无限循环字符串,并使用双指针方法解决最短子串问题。代码实现中使用了动态规划和循环节的概念。
摘要由CSDN通过智能技术生成

比赛的时候连题意都没看懂,雀氏菜。
题目
题意理解以后,就转换成了求一个字符串s中包含涵盖指定字母集的最短子串的长度的题。比如在abbcde中求abc的最短子串,abbc。
首先求出最小公倍数,然后通过输入的字符串求出字符串s。他是一个无限循环的字符串的循环节。
所以要求最短只要两个s拼接在一起,就转变成了上述问题。上述问题可以采用双指针解决。
l = 0,r = 0.
r右移,直到合法。
l左移,直到不合法。
在过程中维护r-l的最小值即可。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<complex>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<unordered_map>
#include<list>
#include<set>
#include<queue>
#include<stack>
#define OldTomato ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define fir(i,a,b) for(int i=a;i<=b;++i) 
#define mem(a,x) memset(a,x,sizeof(a))
#define p_ priority_queue
// round() 四舍五入 ceil() 向上取整 floor() 向下取整
// lower_bound(a.begin(),a.end(),tmp,greater<ll>()) 第一个小于等于的
// #define int long long //QAQ
using namespace std;
typedef complex<double> CP;
typedef pair<int,int> PII;
typedef long long ll;
// typedef __int128 it;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll inf = 1e18;
const int N = 2e5+10;
const int M = 1e6+10;
const int mod = 1e9+7;
const double eps = 1e-6;
inline int lowbit(int x){ return x&(-x);}
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
#define int long long
int n,m,k,T;
string ss[102];
int vis[30];
int cnt[30];
int a[102];
int idx[102];
int gcd(int a,int b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}
void solve()
{
   mem(vis,0);
   mem(idx,0);
   mem(cnt,0);
   cin>>n;
   int tmp = -1;
   for(int i=1;i<=n;++i)
   {
        cin>>ss[i];
        a[i] = ss[i].length();
        for(int j=0;j<ss[i].length();++j) vis[ss[i][j]-'a'] = 1;
        if(tmp == -1) tmp = a[i];
        else tmp = tmp/gcd(tmp,a[i]) * a[i];
   }
   string s = "";
   int now = 1;
   for(int k=1;k<=tmp*n;++k)
   {
        s += ss[now][idx[now]];
        idx[now] = (idx[now] + 1) % a[now];
        now ++ ; if(now == n+1) now = 1;
   }
   s += s;
   int all = 0;
   for(int i=0;i<26;++i) if(vis[i]) all ++ ; //所有种类的字母
   int len = s.length();
   // cout<<s.length()<<" "<<len<<endl;
   int l = 0,r = 0;
   now = 0;
   int ans = 1e12;
   while(l < len && r < len)
   {
        if(now < all)
        {
            cnt[s[r]-'a'] ++ ;
            if(cnt[s[r]-'a'] == 1) now ++ ;
            r ++ ;
        }
        else 
        {
            ans = min(ans,r-l);
            if(ans <= all)
            {
                write(ans); puts(""); return ;
            }
            cnt[s[l]-'a'] -- ;
            if(cnt[s[l]-'a'] == 0) now -- ;
            l ++ ;
        }
   }
   write(ans); puts("");
}
signed main(void)
{  
   // T = 1;
   OldTomato; cin>>T;
   // read(T);
   while(T--)
   {
        solve();
   }
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值