Educational Codeforces Round 81 Rated for Div. 2
比赛链接 https://codeforces.com/contest/1295
比赛记录 https://blog.youkuaiyun.com/cheng__yu_/article/details/105395197
B. Infinite Prefixes(前缀和)
链接:https://codeforces.com/contest/1295/problem/B
题意:给定一个长度为 n 的 01 串 s ,可以无限叠加。给定一个 x ,问 c n t 0 , i − c n t 1 , i = x cnt_{0,i}-cnt_{1,i}=x cnt0,i−cnt1,i=x 的位置个数。 c n t 0 , i cnt_{0,i} cnt0,i表示 [ 1 , i ] [1,i] [1,i] 中 0 的个数。 c n t 1 , i cnt_{1,i} cnt1,i表示 [ 1 , i ] [1,i] [1,i] 中 1 的个数。如果有无限个位置相等,输出 -1 ,否则输出个数。(注意空串也算一个)
思路:
- 首先想到一个串的累加量,也就是 pref[n] 。
- 如果累加量为 0,那么如果出现和 x 相等的 pref[i] ,那么就会出现无限个相等的位置。
- 如果累加量不为 0 ,那么 x x x 和 位置 i i i 的值 p r e f [ i ] pref[i] pref[i] 必须相隔了 正整数个 p r e f [ n ] pref[n] pref[n],才能不断累加从 p r e f [ i ] pref[i] pref[i] 变成 x x x 。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
int t,n,x;
int a[maxn],pref[maxn];
string s;
int main()
{
cin>>t;
while(t--)
{
cin>>n>>x>>s;
s="0"+s;
for(int i=1; i<=n; ++i)
pref[i]=pref[i-1]+(s[i]=='1'?-1:1);
if(pref[n]==0)
{
bool ok=1;
for(int i=1; i<=n; ++i)
if(pref[i]==x) ok=0;
puts(ok?"0":"-1");
}
else
{
int cnt=0;
if(x==0) cnt++;
for(int i=1; i<=n; ++i)
if((x-pref[i])%pref[n]==0&&(x-pref[i])/pref[n]>=0) cnt++;
printf("%d\n",cnt);
}
}
return 0;
}
C. Obtain The String(预处理)
题意:给定字符串 s 和 t 。问从 s 中选取子序列构造成 t 需要几次
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5,maxm=1e5+5;
const int mod=998244353,inf=0x7f7f7f7f;
int tt;
string s,t;
int nxt[maxn][30];
int main()
{
cin>>tt;
while(tt--)
{
cin>>s>>t;
int n=s.size(),m=t.size();
s="0"+s,t="0"+t;
for(int j=1;j<=26;++j)
nxt[n][j]=-1;
for(int i=n-1;i>=0;--i)
{
for(int j=1;j<=26;++j)
nxt[i][j]=nxt[i+1][j];
int x=s[i+1]-'a'+1;
nxt[i][x]=i+1;
}
int ans=1,pos=0;
bool ok=true;
for(int i=0;i<m;++i)
{
int x=t[i+1]-'a'+1;
if(nxt[pos][x]!=-1)
pos=nxt[pos][x];
else
{
ans++;
pos=0;
if(nxt[pos][x]==-1)
{
ok=false;
break;
}
pos=nxt[pos][x];
}
}
if(ok)
printf("%d\n",ans);
else
puts("-1");
}
return 0;
}
D. Same GCDs
链接:https://codeforces.com/contest/1295/problem/D
题意:给定 a、m ,计算 ∑ x = 1 m − 1 [ g c d ( a , m ) = g c d ( a + x , m ) ] \sum_{x=1}^{m-1} [gcd(a,m)=gcd(a+x,m)] ∑x=1m−1[gcd(a,m)=gcd(a+x,m)] 。 ( 1 ≤ a < ≤ m ≤ 1 0 10 ) (1\le a < \le m \le 10^{10}) (1≤a<≤m≤1010)
思路:
∑ x = 0 m − 1 [ g c d ( a , m ) = g c d ( a + x , m ) ] \sum_{x=0}^{m-1} [gcd(a,m)=gcd(a+x,m)] x=0∑m−1[gcd(a,m)=gcd(a+x,m)]
根据更相减损法有
∑
x
=
0
m
−
1
[
g
c
d
(
a
,
m
)
=
g
c
d
(
(
a
+
x
)
m
o
d
m
,
m
)
]
\sum_{x=0}^{m-1} [gcd(a,m)=gcd((a+x) mod~ m,m)]
x=0∑m−1[gcd(a,m)=gcd((a+x)mod m,m)]
这里相当于平移了一下
∑ i = 0 m − 1 [ g c d ( a , m ) = g c d ( i , m ) ] \sum_{i=0}^{m-1} [gcd(a,m)=gcd(i,m)] i=0∑m−1[gcd(a,m)=gcd(i,m)]
设 d = g c d ( a , m ) d=gcd(a,m) d=gcd(a,m)
∑ i = 0 m − 1 [ g c d ( i , m ) = d ] \sum_{i=0}^{m-1} [gcd(i,m)=d] i=0∑m−1[gcd(i,m)=d]
这里发现 i 、m 是在枚举 d 的倍数,因此化简为:
∑ i = 1 ⌊ m − 1 d ⌋ [ g c d ( i , m d ) = 1 ] \sum_{i=1}^{ \lfloor \frac {m-1}d \rfloor} [gcd(i,\frac md)=1] i=1∑⌊dm−1⌋[gcd(i,dm)=1]
因此这个式子就相当于 φ ( m d ) \varphi (\frac md) φ(dm)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
int t;
ll a,m;
int main()
{
cin>>t;
while(t--)
{
cin>>a>>m;
ll d=__gcd(a,m);
ll n=m/d;
ll ans=n;
for(ll i=2; i*i<=n; ++i)
{
if(n%i==0)
{
ans=ans/i*(i-1);
while(n%i==0) n/=i;
}
}
if(n>1) ans=ans/n*(n-1);
cout<<ans<<"\n";
}
return 0;
}