A. Orac and Factors
题意:定义 f [ n ] f[n] f[n] = n n n的最小因数,有q次操作,每次操作让n加上 f [ n ] f[n] f[n],问q次操作后n的值为多少。
思路:
- 对于偶数来说,输出 n + q ∗ 2 n+q*2 n+q∗2。
- 对于奇数来说,找到最小因数(必然是个奇数),然后加上这个奇数之后,n就会变成偶数,然后就是偶数的情况了。
#include<bits/stdc++.h>
#define ll long long
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define pp pop_back
using namespace std;
int main()
{
int T;
cin >> T;
while(T--)
{
ll n,k;
cin >> n >> k;
ll tmp = n;
if(n%2 == 0)
{
cout<<n+2*k<<'\n';
continue;
}
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
tmp = i;
break;
}
}
if(n&1)
{
n+=tmp;
k--;
}
cout<<n+2*k<<'\n';
}
return 0;
}
B. Orac and Models
题意:求带条件的最长上升子序列,条件是: i < j i<j i<j && a [ i ] < a [ j ] a[i] < a[j] a[i]<a[j] && j j j是 i i i的倍数。
题解:设 d p [ i ] dp[i] dp[i]为包括 i i i在内的最长合法上升子序列,那么 d p [ i ] dp[i] dp[i]肯定是由 d p [ j ] dp[j] dp[j]( j < i j<i j<i && i i i是 j j j的倍数)转移,枚举一下 j j j即可。比 i i i小的数的dp值一定在 i i i直接求出来了。时间复杂度是o( n n n* n \sqrt n n)。
#include<bits/stdc++.h>
#define ll long long
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define pp pop_back
using namespace std;
const int maxn = 1e5+100;
int a[100005],dp[100005];
int main()
{
int T;
cin >> T;
while(T--)
{
int n;
cin >> n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
{
dp[i] = 1;
for(int j=1;j<=sqrt(i);j++)
{
if(i%j == 0)
{
if(a[i] > a[j])dp[i] = max(dp[i],dp[j] + 1);
}
if(i%(i/j) == 0)
{
if(a[i] > a[i/j])dp[i] = max(dp[i],dp[i/j]+1);
}
}
}
int ans = 0;
for(int i=1;i<=n;i++)ans = max(ans,dp[i]);
// cout<<dp[i]<<' ';
// puts("");
cout<<ans<<'\n';
}
return 0;
}
C. Orac and LCM
题意:给你一个数组,问这个数组中满足 i < j i<j i<j的数对的 l c m lcm lcm组成新的数组 的gcd是多少。
思路:
-
首先:对于新组成的数组的每一项我们都可以写出 l c m ( a [ i ] , a [ j ] ) lcm(a[i],a[j]) lcm(a[i],a[j]) = a [ i ] ∗ a [ j ] g c d ( a [ i ] , a [ j ] ) \frac{a[i]*a[j]}{gcd(a[i],a[j])} gcd(a[i],a[j])a[i]∗a[j]。
-
当 i i i等于 1 1 1时,j可取2~n,我们可以推导公式:
g c d gcd gcd( a [ 1 ] ∗ a [ 2 ] g c d ( a [ 1 ] , a [ 2 ] ) \frac{a[1]*a[2]}{gcd(a[1],a[2])} gcd(a[1],a[2])a[1]∗a[2], a [ 1 ] ∗ a [ 3 ] g c d ( a [ 1 ] , a [ 3 ] ) \frac{a[1]*a[3]}{gcd(a[1],a[3])} gcd(a[1],a[3])a[1]∗a[3],…)= a [ 1 ] a[1] a[1] * gcd( a [ 2 ] g c d ( a [ 1 ] , a [ 2 ] ) \frac{a[2]}{gcd(a[1],a[2])} gcd(a[1],a[2])a[2], a [ 3 ] g c d ( a [ 1 ] , a [ 3 ] ) \frac{a[3]}{gcd(a[1],a[3])} gcd(a[1],a[3])a[3],…) = a [ 1 ] a[1] a[1] * g c d ( a [ 2 ] , . . . . ) g c d ( a [ 1 ] , a [ 2 ] , . . . . ) \frac{ {gcd(a[2],\ ....)}}{gcd(a[1],a[2],\ ....)} gcd(a[1],a[2], ....)gcd(a[2], ....) = a [ 1 ] ∗ g c d ( a [ 2 ] , . . . . ) g c d ( a [ 1 ] , g c d ( a [ 2 ] , . . . . ) ) \frac{ {a[1] \ *\ gcd(a[2],\ ....)}}{gcd(a[1] \ , \ gcd(a[2],\ ....))} gcd(a[1] , gcd(a[2], ....))a[1] ∗ gcd(a[2], ....) = l c m ( a [ 1 ] , g c d ( a [ 2 ] . . . . . ) lcm(a[1],gcd(a[2].....) lcm(a[1],gcd(a[2].....); -
对于所有的数来说,设 p [ i ] p[i] p[i]等于 a [ i ] a[i] a[i]乘以位于 i i i后面的数的gcd,那么答案就是p数组的gcd,这个数后面的gcd,可以像前缀和一样预处理,也可以线段树。
#include<bits/stdc++.h>
#define ll long long
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define pp pop_back
using namespace std;
const int maxn = 1e5+10;
int tr[maxn * 4],a[maxn];
#define ls o<<1
#define rs o<<1|1
#define mid (l+r)/2
void up(int o,int l,int r,int p,int val)
{
if(l == r)
{
tr[o] += val;
return ;
}
if(p <= mid)up(ls,l,mid,p,val);
else up(rs,mid+1,r,p,val);
tr[o] = __gcd(tr[ls],tr[rs]);
}
int qu(int o,int l,int r,int L,int R)
{
if(l>=L && r<=R)return tr[o];
if(R <= mid)return qu(ls,l,mid,L,R);
else if(L > mid)return qu(rs,mid+1,r,L,R);
else return __gcd(qu(ls,l,mid,L,R),qu(rs,mid+1,r,L,R));
}
int main()
{
int n;
cin >> n;
for(int i=1;i<=n;i++)
{
cin >> a[i];
up(1,1,n,i,a[i]);
}
ll ans = 1000000009;
int tmp;
for(int i=1;i<n;i++)
{
if(i == 1)
{
tmp = qu(1,1,n,i+1,n);
ans = 1ll*tmp*a[i]/__gcd(tmp,a[i]);
}
else
{
tmp = qu(1,1,n,i+1,n);
ans = __gcd(ans,1ll*tmp*a[i]/__gcd(tmp,a[i]));
}
}
cout<<ans<<'\n';
return 0;
}
D. Orac and Medians
题意:给你一个数组,你可以对这个数组进行有限次操作,使得这个数组中所有的元素的值都等于k,这个操作定义如下,我们可以任意选择一个区间,把这个区间的数都变成他的中位数(如果这个区间长度为偶数,中间偏小的那个数)。如果能全部变成k输出yes,否则输出no。
思路:通过观察我们可以得到结论
- 当 n = 1 n=1 n=1时,答案取决于 a [ 1 ] = = k ? a[1]==k? a[1]==k?;
- 当 n ! = 1 n!=1 n!=1时 && 数组没有 k k k,输出 n o no no;
- 当 n ! = 1 n!=1 n!=1 && 数组中有k时,如果数组中存在两个连续的大于k的数,输出yes;或者,存在数组中某个数左右两边的数都大于k时,输出yes;
- 其他情况都是no;
#include<bits/stdc++.h>
#define ll long long
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define pp pop_back
using namespace std;
int a[100005];
int main()
{
int T;
cin >> T;
while(T--)
{
int n,k;
cin >> n >> k;
int flag = 0,tmp = 0;
for(int i=1;i<=n;i++)
{
cin >> a[i];
if(n == 1 && a[i] == k)flag = 1;
if(a[i] == k)tmp = 1;
}
if(!tmp)
{
puts("no");
continue;
}
for(int i=2;i<=n;i++) {
if(a[i-1]>=k && a[i] >= k)flag = 1;
}
for(int i=2;i<n;i++) {
if(a[i-1] >= k && a[i+1] >= k)flag = 1;
}
if(flag)puts("yes");
else puts("no");
}
return 0;
}
E. Orac and Game of Life
题意及题解:连接
#include<bits/stdc++.h>
#define ll long long
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define pp pop_back
using namespace std;
int a[1005][1005],vis[1005][1005],f[1005][1005];
int x[5] = {
-1,1,0,0};
int y[5] = {
0,0,-1,1};
int n,m,q;
bool ok(int xo,int yo)
{
for(int i=0;i<4;i++)
{
int tx = xo + x[i];
int ty = yo + y[i];
if(tx < 1 || tx > n || ty < 1 || ty > m)continue;
if(a[xo][yo] == a[tx][ty])return true;
}
return false;
}
void bfs()
{
queue<pi>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(ok(i,j))
{
q.push(mk(i,j));
vis[i][j] = 1;
}
}
while(!q.empty())
{
int xo = q.front().first;
int yo = q.front().second;
q.pop();
for(int i=0;i<4;i++)
{
int tx = xo + x[i];
int ty = yo + y[i];
if(tx < 1 || tx > n || ty < 1 || ty > m)continue;
if(vis[tx][ty])continue;
vis[tx][ty] = 1;
f[tx][ty] = f[xo][yo] + 1;
q.push(mk(tx,ty));
}
}
}
int main()
{
cin >> n >> m >> q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)scanf("%1d",&a[i][j]);
bfs();
while(q--)
{
int i,j;
ll t;
cin >> i >> j >> t;
if(vis[i][j])
{
if(t > f[i][j])printf("%d\n",a[i][j] ^ ((t - f[i][j])&1));
else printf("%d\n",a[i][j]);
}
else printf("%d\n",a[i][j]);
}
return 0;
}