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;
}