Educational Codeforces Round 173 (Rated for Div. 2) - Codeforces
Problem - A - Codeforces
签到题目
Problem - B - Codeforces
数学
被小学奥数薄纱力…
给出一个由 n ! n! n!个 d d d组成的整数,看他能否被十以内的奇数整除
1 1 1肯定是答案
一个数能被
3
3
3整除,那么它的数位之和为一定可以被
3
3
3整除,简单证明一下,设一个
k
k
k位数,每个位数为
x
i
x_i
xi
n
=
x
k
∗
1
0
k
+
x
k
−
1
∗
1
0
k
−
1
+
.
.
.
x
2
∗
10
+
x
1
(
x
k
+
x
k
−
1
+
.
.
x
2
+
x
1
)
m
o
d
3
=
0
n
m
o
d
3
=
∑
i
=
1
k
(
(
x
i
m
o
d
3
)
∗
(
1
0
i
m
o
d
3
)
)
=
∑
i
=
1
k
(
x
i
m
o
d
3
)
=
0
n=x_k*10^k+x_{k-1}*10^{k-1}+...x2*10+x_1\\ (x_k+x_{k-1}+..x_2+x_1)\mod 3=0\\ n\mod3=\sum_{i=1}^{k}((x_i\mod 3)*(10^i\mod 3))=\sum_{i=1}^{k}(x_i\mod 3)=0
n=xk∗10k+xk−1∗10k−1+...x2∗10+x1(xk+xk−1+..x2+x1)mod3=0nmod3=i=1∑k((ximod3)∗(10imod3))=i=1∑k(ximod3)=0
同理可以得出,一个数能被
9
9
9整除,那么它的数位之和一定能被
9
9
9整除
一个数能被 5 5 5整除,它的末尾一定是 0 0 0或 5 5 5
最后是 7 7 7有点麻烦,得找找规律,发现题中 n = 111..111 ∗ d n=111..111*d n=111..111∗d,由 1 1 1构成的 n n n中最小的能被 7 7 7整除的为 111111 111111 111111
所以只要 n ! m o d 6 = = 0 n!\mod6==0 n!mod6==0即 n > = 3 n>=3 n>=3, n n n一定可以表示为 111111 ∗ a + 111111 ∗ b + . . . 111111*a+111111*b+... 111111∗a+111111∗b+...
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
map<int,int>mp;
int n;int a[N];
int l[N],r[N];
long long gcd(long long a,long long b)
{
return b? gcd(b,a%b):a;
}
void solve()
{
int n,d;cin>>n>>d;
cout<<"1 ";
if(n>=3||d%3==0)cout<<"3 ";
if(d==5)cout<<"5 ";
if(n>=3||d==7)cout<<"7 ";
if(n>=6||(n>=3&&d%3==0)||d==9)cout<<"9 ";
cout<<endl;
}
int main()
{
int t;cin>>t;
while(t--)solve();
}
Problem - C - Codeforces
dp 数学
给出一个整数数组,数组最多有一个数 x x x不是 − 1 , 1 -1,1 −1,1
问数组的一个连续段的和最多有几种不同结果,考虑空段
观察题目显然想到要把数组分为 x x x左边和 x x x右边,独立来看
对于一个只有 − 1 , 1 -1,1 −1,1的序列,假设它的连续段和最大为 x x x,最小为 y y y,可以证明它的连续段和肯定可以取满 [ y , x ] [y,x] [y,x]内的值
证明:对于最大值 x x x,由于它是由一个连续段相加得来,那么肯定可以将这个连续段分为若干个和为 1 1 1的更小的段,从两端开始移去子段,得到的连续段和为 x − 1 , x − 2...0 x-1,x-2...0 x−1,x−2...0,所以肯定可以取满 [ 0 , x ] [0,x] [0,x],同理可得取满 [ y , 0 ] [y,0] [y,0]
对于求最大最小值就是简单的 d p dp dp问题了
设已经求出的左边范围是 [ a , b ] [a,b] [a,b],右边为 [ c , d ] [c,d] [c,d],(由于肯定包含 0 0 0,两者肯定有交集)将其合并为 [ x , y ] [x,y] [x,y],那么答案至少是 y − x + 1 y-x+1 y−x+1
再考虑 x x x,设它的坐标是 i n d ind ind,只用求出 [ i n d + 1 , n ] [ind+1,n] [ind+1,n]的前缀和与 [ 1 , i n d − 1 ] [1,ind-1] [1,ind−1]的后缀和,将他们的范围(最大值大于等于 0 0 0,最小值小于等于 0 0 0)相加得到 [ x 1 , y 1 ] [x_1,y_1] [x1,y1]
遍历这个区间加上 x x x看看有没有新的值加入即可
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
map<int,int>mp;
int n;int a[N];
int l[N],r[N];
void solve()
{
mp.clear();int ind=-1;int ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
l[i]=r[i]=0;
scanf("%d",&a[i]);
if(a[i]<-1||a[i]>1||a[i]==0)ind=i;
}
int aa=0,b=0,c=0,d=0;
if(ind==-1)ind=n+1;
for(int i=1;i<ind;i++)
{
l[i]=max(a[i],l[i-1]+a[i]);
r[i]=min(a[i],r[i-1]+a[i]);
aa=max(aa,l[i]);
b=min(b,r[i]);
}
for(int i=ind+1;i<=n;i++)
{
l[i]=max(a[i],l[i-1]+a[i]);
r[i]=min(a[i],r[i-1]+a[i]);
c=max(c,l[i]);
d=min(d,r[i]);
}
b=min(b,d);aa=max(aa,c);ans=aa-b+1;
for(int i=b;i<=aa;i++)mp[i]++;
if(ind!=n+1)
{
if(!mp[a[ind]])
{
mp[a[ind]]++;
ans++;
}
int sum=0;
int x1=0,x2=0,y1=0,y2=0;
for(int i=ind+1;i<=n;i++)
{
sum+=a[i];x1=min(x1,sum);x2=max(x2,sum);
}
sum=0;
for(int i=ind-1;i;i--)
{
sum+=a[i];y1=min(y1,sum);y2=max(y2,sum);
}
int ll=x1+y1,rr=x2+y2;
for(int i=ll;i<=rr;i++)
{
if(!mp[a[ind]+i])
{
mp[a[ind]+i]++;ans++;
}
}
}
cout<<ans<<endl;
for(auto x:mp)
{
cout<<x.first<<' ';
}
cout<<endl;
}
int main()
{
int t;cin>>t;
while(t--)solve();
}
Problem - D - Codeforces
质数 数学
给出 l , r , g l,r,g l,r,g,求 l ≤ a ≤ b ≤ r , g c d ( a , b ) = g l\leq a\leq b \leq r ,gcd(a,b)=g l≤a≤b≤r,gcd(a,b)=g的,满足 ∣ a − b ∣ |a-b| ∣a−b∣最大的 a , b a,b a,b
模板题,需要一个转化,对于 x = g ∗ a , y = g ∗ b x=g*a\ , y=g*b x=g∗a ,y=g∗b,如果 g c d ( x , y ) = g gcd(x,y)=g gcd(x,y)=g,那么一定有 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1
那么题目就转化为了找到 [ ( l + g − 1 ) / g , r / g ] [(l+g-1)/g,r/g] [(l+g−1)/g,r/g]之间的最大互质对
要根据质数的性质,在题目给的 1 0 18 10^{18} 1018的范围下,相邻质数的距离最大不会超过 1500 1500 1500
其实,设 g n g_n gn为在小于等于 n n n的范围内相邻质数的最大距离, g 1 0 18 = 1442 g_{10^{18}}=1442 g1018=1442
考虑 l l l的下一个质数为 q q q,考虑 r r r的上一个质数为 p p p,两个不相等的质数一定互质,所以答案最坏也要是 ( q , p ) (q,p) (q,p)
在最差的情况下要遍历 g n 2 ∗ l g ( r ) g_n^2*lg(r) gn2∗lg(r),时间是足够的
从大到小枚举长度即可,看似时间复杂度是 n 2 n^2 n2,,其实很快就可以在两端找到答案
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
map<int,int>mp;
int n;int a[N];
int l[N],r[N];
long long gcd(long long a,long long b)
{
return b? gcd(b,a%b):a;
}
void solve()
{
long long x,y,g;cin>>x>>y>>g;
long long l=(x+g-1)/g,r=y/g;
for(long long len=r-l;len>=0;len--)
{
for(long long i=l;i+len<=r;i++)
{
if(gcd(i,i+len)==1)
{
cout<<g*i<<' '<<g*(i+len)<<endl;return ;
}
}
}
cout<<"-1 -1"<<endl;
}
int main()
{
int t;cin>>t;
while(t--)solve();
}
可以得到求 [ l , r ] [l,r] [l,r]内的最大互质对的模板
void getprime(long long a, long long b)
{
for(long long len=r-l;len>=0;len--)
{
for(long long i=l;i+len<=r;i++)
{
if(gcd(i,i+len)==1)
{
cout<<i<<' '<<i+len<<endl;return ;
}
}
}
}