涵盖知识点:数学
比赛链接:传送门
A - Orac and Factors
题意: 规定(f(n))是(n)的除(1)外最小因子。现在给定(n),求执行(k)次(n+f(n))后的结果
题解: 偶数一直加2,奇数扫一遍最小因子后会加一个奇数,然后一直加2
Accept Code:
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;cin>>t;
while(t--){
int n,k;
cin>>n>>k;
if(n&1){
int p=2;
for(int i=2;i<=n;i++){
if(n%i==0){p=i;break;}
}
cout<<n+p+2*(k-1)<<"
";
}
else cout<<n+2*k<<"
";
}
return 0;
}
B - Orac and Models
题意: 给定原序列(s),要找到最长子序列满足(i|j)且(s_i<s_j),求长度。
题解: dp暴力转移求每一位为终点的最大长度。
Accept Code:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int s[maxn],dp[maxn];
int main(){
int t;cin>>t;
while(t--){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>s[i],dp[i]=1;
for(int i=1;i<=n;i++){
for(int j=i*2;j<=n;j+=i){
if(s[i]<s[j])dp[j]=max(dp[j],dp[i]+1);
}
}
int ans=0;
for(int i=1;i<=n;i++)ans=max(ans,dp[i]);
cout<<ans<<"
";
}
return 0;
}
C - Orac and LCM
题意: 给定序列(a),求(gcd({ extrm{lcm}({a_i,a_j}) | i<j}))
题解: 先给结论:(gcd( extrm{lcm} (a,b), extrm{lcm}(a,c) ) = extrm{lcm}( a, gcd(b, c) ))。很明显我们只要对每一个数和其后缀的(gcd)求( extrm{lcm})所得的结果再求一遍(gcd)即可。
证明:
[gcd( extrm{lcm} (a,b), extrm{lcm}(a,c) )=gcd(frac{ab}{gcd(a,b)},frac{ac}{gcd(a,c)})
]
[=a imes gcd(frac{b}{gcd(a,b)},frac{c}{gcd(a,c)})=a imesfrac{gcd(b,c)}{gcd(a,b,c)}= extrm{lcm}( a, gcd(b, c) )
]
Accept Code:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
ll a[maxn],suf[maxn];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
suf[n]=a[n];
for(int i=n-1;i>=1;i--){
suf[i]=__gcd(suf[i+1],a[i]);
}
ll ans=a[1]*suf[2]/__gcd(a[1],suf[2]);
for(int i=2;i<=n-1;i++)ans=__gcd(ans,a[i]*suf[i+1]/__gcd(a[i],suf[i+1]));
cout<<ans<<"
";
return 0;
}
D - Orac and Medians
题意: 给定序列,每次可以选定一个区间将其所有数都变为该区间的中位数(偶数偏左,即取下整)。求能否将整个数组变为恒等于(k)。
题解:
- 仅1个数,yes
- 没有任何数等于(k),no
- 所有大于等于(k)的数中间都含有两个小于(k)的数,no
- 其余情况,yes
充分必要性证明见中文官方题解
Accept Code:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
int a[maxn];
int n,k;
bool check(){
bool flag=false;
for(int i=1;i<=n;i++){
if(a[i]<k)a[i]=0;
else if(a[i]==k)a[i]=1,flag=true;
else a[i]=2;
}
if(!flag)return false;
if(n==1)return true;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n&&j-i<=2;j++){
if(a[i]&&a[j])return true;
}
}
return false;
}
int main(){
int t;cin>>t;
while(t--){
//int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
puts(check()?"yes":"no");
}
return 0;
}
E - Orac and Game of Life
题意: 称一个方格 ((i,j)) 是好的,当且仅当至少有一个与 ((i,j)) 相邻的方格颜色与 ((i,j)) 相同。则经过一个回合后,好方格的颜色改变而不好的方格的颜色不变。多次询问,某个点经过(p)回合后的颜色。
题解: 好的点一定不会变为不好的点,而若一个不好的点周围有一个颜色与其不同的好的点,那么下一回合这个不好的点就会变为一个好的点。所以我们只需要求每一个不好的点距离其最近的好的点的曼哈顿距离即可。特殊的,若所有点都是不好的点,那么所有点的颜色都不变。
Accept Code:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1010;
int n,m,t;
int a[maxn][maxn];
char str[maxn];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
typedef pair<int,int> pii;
typedef long long ll;
bool vis[maxn][maxn];
int dis[maxn][maxn];
bool check(int x,int y){
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(a[nx][ny]==a[x][y])return true;
}
return false;
}
void bfs(){
queue<pii> q;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(check(i,j)){
dis[i][j]=0;
vis[i][j]=true;
q.push({i,j});
}
}
}
while(!q.empty()){
auto tmp=q.front();
q.pop();
for(int i=0;i<4;i++){
int nx=tmp.first+dx[i],ny=tmp.second+dy[i];
if(nx<1||ny<1||nx>n||ny>m||vis[nx][ny])continue;
dis[nx][ny]=dis[tmp.first][tmp.second]+1;
vis[nx][ny]=true;
q.push({nx, ny});
}
}
}
int main(){
cin>>n>>m>>t;
memset(a,-1,sizeof a);
for(int i=1;i<=n;i++){
cin>>(str+1);
for(int j=1;j<=m;j++){
a[i][j]=str[j]-'0';
}
}
bfs();
while(t--){
int x,y;
ll p;
cin>>x>>y>>p;
if(vis[x][y])cout<<(a[x][y]^(max(0ll,p-dis[x][y])&1))<<"
";
else cout<<a[x][y]<<"
";
}
return 0;
}