Educational Codeforces Round 89 (Rated for Div. 2)A、B、C、D、E
[题目](https://codeforces.ml/contest/1366/problem/A)
A题意:两个数a和b,两种操作:1、a减2和b减1。2、a减1和b减2.问最多可以进行多少次操作。
解法:1、如果a>=2b,此时一直进行1操作,最多可操作b次。
2、如果a<2b,a>b,此时1和2操作配合进行,一定可以达到a+b<3的状态,此时结果就为\(\frac{a+b}{3}\)
void solve(){
int a , b ;
cin >> a >> b;
if(a < b) swap(a,b);
if(a >= 2*b){
cout << b << endl;
return ;
}
cout << (a+b)/3 << endl;
}
B题意:给出n个数,初始都为0,只有下标x为1,进行m次操作,每次操作在[l,r]区间内选择两个数交换,问最终状态最多有多少个不同下标位置为1.
解法:如果第x+1次操作区间[q,w]和[l,r]有交集
那么我们的1一定可以从交集处换到[q,w]的每一点去
所以取并集即可
void solve(){
int n , x , m ;
cin >> n >> x >> m ;
int l = x , r = x ;
rep(i , 1 , m){
int u , v ;
cin >> u >> v ;
if(r < u || l > v) continue;
l = min(l , u);
r = max(r , v);
}
cout << r - l + 1 << endl;
}
C题意:给出n*m矩阵,矩阵元素为0或1,要求从(1,1)走到(n,m)的所有路径都是对称路径,比如(10101就是对称路径),问最少需要更改几个值。
解法:思路就是所有第k步的值与n+m-k的值相等,所以最小值就是要么将所有0变1.要么所有1变0,min(cnt[k][0]+cnt[n+m-k][0] , cnt[k][1]+cnt[n+m-k][1])。
可以将对称的步数的统计到一边答案直接为min(cnt[k][0] , cnt[k][1]).
const int maxn = 30+9;
int p[maxn<<1][2];
void solve(){
int n , m ;
cin >> n >> m ;
int s = n+m-2;//0-n+m-2共n+m-2步,n-m+1个值(路径长度)
ME(p , 0);
rep(i , 0 , n-1){
rep(j , 0 , m-1){
int x ;
cin >> x ;
if(i+j == (s-i-j)) continue;//对称轴上的值不管
int r = min(i+j , s-i-j);
p[r][x]++;
}
}
int ans = 0 ;
rep(i , 0 , (s+1)/2-1){
ans += min(p[i][0] , p[i][1]);
}
cout << ans << endl;
}
D题意:给出n个数,问每个数是否存在\(d_1|a_i,d_2|a_i,(d_1>1,d_2>1) , gcd(d_1+d_2,a_i)=1\)存在就输出\(d_1,d_2\),否则输出-1,-1.
解法:分析可知\(gcd(d_1,d_2)=1\)(互质),因为如果\(d_1,d_2\)不互质,又有\(d_1|a_i,d_2|a_i\),那么一定\(gcd(d_1+d_2,a_i)!=1\)。
埃氏筛法筛出所有数1e7的最小质因子p,如果\(a_i\)只有一个质因子则一定不存在,反则一定存在。
\(d_1 = p, d_2= n除去所有p因子后的值\)。
const int N = 1e7+7;
const int maxn = 1e5+9;
int sp[N];
int a[maxn];
void init(){
sp[1] = 1 ;
rep(i , 1 , N){
if(!sp[i]){
sp[i] = i ;
for(int j = i*i ; j <= N ; j += i){
if(!sp[j]) sp[j] = i ;
}
}
}
}
void solve(){
init();
int n ;
cin >> n ;
vector<int>v1 ,v2;
rep(i , 1 , n){
int x ;
cin >> x;
int di = sp[x];//d1 = p
int g = x ;
while(g%di==0){//将n除去所有p因子
g/=di;
}
if(g!=1){//如果n存在不止一个质因子
v1.pb(g) , v2.pb(di);//d2 = g
}else{
v1.pb(-1) , v2.pb(-1);
}
}
for(auto i : v1){
cout << i << " " ;
}
cout << endl;
for(auto i : v2){
cout << i << " " ;
}
cout << endl;
}
E题意:给出两个数组a(1e5)和b,b是递增的给出,问将a分成连续的m段,每一段的最小值等于bi,有多少种分发.
解法:求出a数组的后缀最小值,统计每一个后缀值在所在段,根据分步原理,将段的值依次累乘起来。
const int maxn = 2e5+9;
int a[maxn] , b[maxn] , suf[maxn] , cnt[maxn];
void solve(){
int n , m ;
cin >> n >> m ;
rep(i , 1 , n) cin >> a[i];
rep(i , 1 , m) cin >> b[i];
suf[n+1] = 1e9+10;
red(i , n , 1) suf[i] = min(suf[i+1] , a[i]);
if(suf[1] != b[1]){
cout << 0 << endl;
return ;
}
rep(i , 2 , n){
int p = suf[i];
int pos = lower_bound(b+1 , b+1+m , p) - b ;
if(b[pos] == p) cnt[pos]++;//在b数组找到合法段
}
int ans = 1 ;
rep(i , 2 , m){
ans = ans * cnt[i]%mod;
}
cout << ans << endl;
}