Codeforces Round #797 (Div. 3)

F. Shifting String

思路

不难想到,从循环节下手。我们可以发现,字符串可以拆成一些子序列,这些子序列经过乘p后,有限次内会变回原串。

则我们的解题思路就为,我们将字符串拆分为不同的子序列,来判断这些子序列各需要多少次才会变回原串。对这些子序列需要的次数求lcm即可得到答案。

AC_CODE

#include <bits/stdc++.h>
#define fi first    
#define se second    
#define debug(x) cout<<#x" ----> "<<x<<endl
#define endl '\n'
#define fix(a) fixed << setprecision(a)
#define rep(i, b, s) for(int i = (b); i <= (s); ++i)
#define pre(i, b, s) for(int i = (b); i >= (s); --i)
#define TASK int _; read(_); while(--_)
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
#define all(v) (v).begin(),(v).end()
#define pb push_back
#define mk make_pair
using namespace std;
 
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII ;
typedef pair<int, PII> PIII ;
typedef pair<double,double> PDD;
const double eps = 1e-10;
const double pi = acos(-1.0);
const LL LINF = INT64_MAX;
const int INF = INT_MAX,mod = 1e9 + 7,MOD = 998244353;
template <typename T> T lowbit(T &x) { return x & (-x);}
template <typename T> T gcd(T a, T b) {return b ? gcd(b, a%b) : a;}
LL ksm(LL a,LL b,LL p = mod) {LL res = 1;a%=p;while(b){ if(b&1) res = res*a%p; a=a*a%p;b>>=1;} return res%p;}
template <typename T> T lcm(T a, T b) {return a / gcd(a, b) * b;}
inline bool valid(char c) { return 33<=c&&c<=126; }
template < typename T >
inline void read(T &x)
{
x = 0; bool f = 0; char ch = getchar();
while(!isdigit(ch)){f ^= !(ch ^ 45);ch=getchar();}
while(isdigit(ch)) x= (x<<1)+(x<<3)+(ch&15),ch=getchar();
x = f ? -x : x;
}
template<typename T,typename ...Args>void read(T &x, Args &...args)
{ read(x),read(args...); }
template <typename T> void read(vector<T> &A) { for(T &x: A) read(x);};
inline void reads(char *s) {
int l=0;char c;
while(!valid(s[0]=getchar()));
while(valid(s[++l]=getchar()));
}
//分类讨论时,不要跳步,一步步把不同类框架写好,再进行内部的算法实现,不然层级关系就搞错了。
const int N = 1e5 + 10,M = 2e5 + 10;
   
void solve() {
    int n;string s;
    cin>>n>>s;
    vector<int> p(n);
    for(int i=0;i<n;i++)
    {
        cin>>p[i];
        p[i]--;
    }
    LL ans = 1;
    vector<bool> v(n,0);
    for(int i=0;i<n;i++)
    {
        if(v[i]) continue;
        vector<int> a;
        int j = i;
        while(!v[j]){
            a.push_back(j);
            v[j] = 1;
            j = p[j];
        }
        LL c = 0;
        string t = s;
        do
        {
            ++c;string tmp = t;
            for(auto x:a) t[x] = tmp[p[x]];
        }while(t!=s);
        ans = lcm(ans,c);
    }
    cout<<ans<<endl;
}
 
int main() 
{
    ios;
    int T=1;
    cin>>T;
 
    while(T -- ) {
        solve();
    }
 
    return 0;
}

G. Count the Trains

题目大意

\(给定一个长度为n的数组a,还有m次操作(x_i,d_i),每次令a_{x_i}=a_{x_i}−d_i。\)

\(要求每次操作过后输出a的前缀最小值数组中有多少个不同的值。\)

\(其中1≤n,m≤10^5,0≤a_i≤10^9。\)

思路

看到一个题解写的是线段树的做法,但也不用那么麻烦。

我们可以利用单调队列类似的思路。

我们着重说一下add就可以理解整个思路。

我们每次修改第i个位置时,我们只需要考虑的是

  • 如果此时i的值大于等于i前的前缀最小值,那第i个值就没有必要存在了,因为前缀最小值的种类一定不会变了。
  • 如果此时i的值比i前的前缀最小值还小,则将会改变从i到n的第一个大于此时i的值的位置(该位置不改变)中的每一个值都删去

我们来解释一下时间复杂度的问题,我们可以发现这样做,时间复杂度是\(O((n+m)logn)\)

AC_CODE

#include <bits/stdc++.h>
#define fi first    
#define se second    
#define debug(x) cout<<#x" ----> "<<x<<endl
#define endl '\n'
#define fix(a) fixed << setprecision(a)
#define rep(i, b, s) for(int i = (b); i <= (s); ++i)
#define pre(i, b, s) for(int i = (b); i >= (s); --i)
#define TASK int _; read(_); while(--_)
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
#define all(v) (v).begin(),(v).end()
#define pb push_back
#define mk make_pair
using namespace std;
 
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII ;
typedef pair<int, PII> PIII ;
typedef pair<double,double> PDD;
const double eps = 1e-10;
const double pi = acos(-1.0);
const LL LINF = INT64_MAX;
const int INF = INT_MAX,mod = 1e9 + 7,MOD = 998244353;
template <typename T> T lowbit(T &x) { return x & (-x);}
template <typename T> T gcd(T a, T b) {return b ? gcd(b, a%b) : a;}
LL ksm(LL a,LL b,LL p = mod) {LL res = 1;a%=p;while(b){ if(b&1) res = res*a%p; a=a*a%p;b>>=1;} return res%p;}
template <typename T> T lcm(T a, T b) {return a / gcd(a, b) * b;}
inline bool valid(char c) { return 33<=c&&c<=126; }
template < typename T >
inline void read(T &x)
{
x = 0; bool f = 0; char ch = getchar();
while(!isdigit(ch)){f ^= !(ch ^ 45);ch=getchar();}
while(isdigit(ch)) x= (x<<1)+(x<<3)+(ch&15),ch=getchar();
x = f ? -x : x;
}
template<typename T,typename ...Args>void read(T &x, Args &...args)
{ read(x),read(args...); }
template <typename T> void read(vector<T> &A) { for(T &x: A) read(x);};
inline void reads(char *s) {
int l=0;char c;
while(!valid(s[0]=getchar()));
while(valid(s[++l]=getchar()));
}
//分类讨论时,不要跳步,一步步把不同类框架写好,再进行内部的算法实现,不然层级关系就搞错了。
const int N = 1e5 + 10,M = 2e5 + 10;
   
map<int,int> mp;
void add(int i,int x)
{
    mp[i] = x;
    auto it = mp.find(i);
    if(it!=mp.begin()&&x>=prev(it)->second)
    {
        mp.erase(it);
        return ;
    }
    while(next(it)!=mp.end()&&x<=next(it)->second)
        mp.erase(next(it));
}

void solve() {
    int n,m;
    cin>>n>>m;
    vector<int> a(n);
    mp.clear();
    for(int i=0;i<n;i++) cin>>a[i],add(i,a[i]);
    for(int i=0;i<m;i++)
    {
        int k,d;cin>>k>>d;
        k--;a[k]-=d;
        add(k,a[k]);
        cout<<mp.size()<<" \n"[i==m-1];
    }
}
 
int main() 
{
    ios;
    int T=1;
    cin>>T;
 
    while(T -- ) {
        solve();
    }
 
    return 0;
}
posted @ 2022-06-08 22:34  艾特玖  阅读(147)  评论(0)    收藏  举报