A:Orac and Factors
题意:看题面吧,水题
题解:一次操作后就会有因子2,直接做就完了。
参考代码:
#include
typedef long long ll;
using namespace std;
const int maxn = 2e6 + 7;
int f[maxn];
int main(){
#ifndef ONLINE_JUDGE
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
memset(f, 0x3f, sizeof(f));
f[1] = 1;
for(int i = 2; i < maxn; ++i) {
for(int j = i; j < maxn; j += i) f[j] = min(f[j], i);
}
int t;
scanf("%d", &t);
while(t--) {
ll n, k;
scanf("%I64d%I64d", &n, &k);
while(k > 0 && f[n] > 2) {
n += f[n];
--k;
}
if(k) n += k * 2;
printf("%I64d\n", n);
}
return 0;
}
B:Orac and Models
题意:给定一个长度为的序列,求满足条件的最长上升子序列长度:序列中相邻元素下标大的能被下标小的整除。
题解:直接将下标因式分解,做dp。
参考代码:
#include
#define eb emplace_back
typedef long long ll;
using namespace std;
const int maxn = 1e5 + 7;
vector yz[maxn];
int n, f[maxn], a[maxn];
int main(){
#ifndef ONLINE_JUDGE
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
int t;
for(int i = 1; i < maxn; ++i) {
for(int j = i; j < maxn; j += i) {
yz[j].eb(i);
}
}
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
int ans = 0;
for(int i = 1; i <= n; ++i) {
scanf("%d", a + i);
f[i] = 1;
for(int p : yz[i]) {
if(a[p] < a[i]) f[i] = max(f[i], f[p] + 1);
}
ans = max(ans, f[i]);
}
printf("%d\n", ans);
}
return 0;
}
C:Orac and LCM
题意:给一个长度为序列,对序列中的每对数求得到序列,求序列的。
数据范围:。
题解:对于一对数,它们的就是将它们素因子分解后,对应的素因子指数取最大值得到的结果。由此,我们先对序列中的数进行素因子分解并将每个素因子的次数记录到对应的桶中。
对于一个素因子:
第一种情况:如果每个数都有素因子,那么其对结果的贡献由其第二小的出现次数决定。
第二种情况:如果只有1个数没有素因子,那么其对结果的贡献由第一小的出现次数决定。
第三种情况:如果有2个以上的数没有素因子,那么其对结果无贡献。
具体计算方法见代码实现。
参考代码:
#include
typedef long long ll;
using namespace std;
const int maxn = 2e5 + 7;
int n, x;
vector p[maxn];
ll quick_pow(ll x, ll y) {
// printf("x y --- %lld %lld\n", x, y);
ll res = 1;
for(; y > 0; x = x * x, y >>= 1) if(y & 1) res = res * x;
return res;
}
int main(){
#ifndef ONLINE_JUDGE
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &x);
for(int j = 2; 1LL * j * j <= x; ++j) {
if(x % j == 0) {
int cnt = 0;
while(x % j == 0) ++cnt, x /= j;
p[j].push_back(cnt);
}
}
if(x > 1) p[x].push_back(1);
}
ll ans = 1;
for(int i = 2; i < maxn; ++i) {
sort(p[i].begin(), p[i].end());
if(p[i].size() >= n) {
ans = ans * quick_pow(i, p[i][1]);
}
else if(p[i].size() == n - 1) {
ans = ans * quick_pow(i, p[i][0]);
}
}
printf("%I64d\n", ans);
return 0;
}
D:Orac and Medians
题意:给定一个长度为的 序列,定义一次操作为选定序列中的一个区间,将此区间中的数全都变为此区间的数排序后第的数,可以进行无限次操作,问能不能通过操作将所有数都变成。
数据范围:
题解:首先,要使所有数都变成,序列中必须有。有了之后分情况讨论一下:
第一种情况:存在相邻两个的数,那么一定能够通过操作使序列全变成。
第二种情况:不存在相邻两个的数,我们就找所有长度为3的区间,看能不能变出一个长度为3的的区间且其他位置还有或者当前的中位数是,如果能,则可以将序列都变成,否则不可以。
参考代码:
#include
#define pb push_back
#define eb emplace_back
#define sz(x) (int)(x).size()
typedef long long ll;
using namespace std;
const int maxn = 1e5 + 7;
int n, k, a[maxn], preh[maxn], sufh[maxn];
int main(){
#ifndef ONLINE_JUDGE
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
int t;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &k);
vector kpos;
for(int i = 1; i <= n; ++i) {
scanf("%d", a + i);
preh[i] = preh[i - 1];
if(a[i] == k) kpos.eb(i), preh[i] = 1;
}
sufh[n + 1] = 0;
for(int i = n; i >= 1; --i) {
sufh[i] = sufh[i + 1];
if(a[i] == k) sufh[i] = 1;
}
if(sz(kpos) == 0) {
puts("no");
continue;
}
if(n == sz(kpos)) {
puts("yes");
continue;
}
bool flag = false;
for(int i = 1; i < n; ++i) {
if(a[i] >= k && a[i + 1] >= k) flag = true;
}
if(flag) {
puts("yes");
continue;
}
for(int i = 2; i <= n - 1; ++i) {
vector b;
for(int j = i - 1; j <= i + 1; ++j) b.eb(a[j]);
sort(b.begin(), b.end());
if(b[1] == k) flag = true;
if(b[1] > k && (preh[i - 2] || sufh[i + 2])) flag = true;
}
puts(flag ? "yes" : "no");
}
return 0;
}
E:Orac and Game of Life
题意:给一个行列的01矩阵,每一轮每个格子会发生如下变化:
如果一个格子与其相邻格子没有一个是相同的,那么这个格子本轮不变。
否则,这个格子就会01反转。
给个询问,每次询问行列的元素在第轮是什么数字。
数据范围:,
题解:首先对于一个会反转的点,它反转以后的每一轮都会反转。对于第1轮就会反转的点将其加入起点,直接bfs求出每个点在第几轮后会跟着反转。询问时直接查询即可。
参考代码:
#include
typedef long long ll;
typedef std::pair pii;
using namespace std;
const int maxn = 1000 + 7, inf = 0x3f3f3f3f;
char mp[maxn][maxn];
int f[maxn][maxn];
int n, m, t;
int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
bool check(int x, int y) {
if(x < 1 || x > n || y < 1 || y > m) return false;
return true;
}
int main(){
#ifndef ONLINE_JUDGE
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
scanf("%d%d%d", &n, &m, &t);
memset(f, 0x3f, sizeof(f));
for(int i = 1; i <= n; ++i) {
scanf("%s", mp[i] + 1);
}
queue Q;
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
bool flag = false;
for(int k = 0; k < 4; ++k) {
int tx = i + dir[k][0], ty = j + dir[k][1];
if(check(tx, ty)) {
if(mp[tx][ty] == mp[i][j]) flag = true;
}
}
if(flag){
f[i][j] = 0;
Q.push(pii(i, j));
}
}
}
while(!Q.empty()) {
pii p = Q.front(); Q.pop();
for(int k = 0; k < 4; ++k) {
int tx = p.first + dir[k][0], ty = p.second + dir[k][1];
if(check(tx, ty)) {
if(f[tx][ty] == inf) {
f[tx][ty] = f[p.first][p.second] + 1;
Q.push(pii(tx, ty));
}
}
}
}
for(int q = 1; q <= t; ++q) {
int i, j;
ll p;
scanf("%d%d%I64d", &i, &j, &p);
int res = mp[i][j] - '0';
if(f[i][j] != inf && p > f[i][j]) {
p -= f[i][j];
p &= 1;
res ^= p;
}
printf("%d\n", res);
}
return 0;
}
F:Slime and Sequences (Easy Version)
题意:对于长度为的序列,定义好序列为:
对于每个出现在序列中的大于1的数,至少存在一对满足。
给定序列的长度,求所有长度为的好序列中每个数字的出现次数和。
数据范围:简单版, 困难版
题解:留坑