CF1516B AGAGA XOOORRR
题目大意:每次操作可以将相邻两个数异或起来变成一个数,问能否存在一种方案,将数列进行操作后所有剩下的数相等(至少剩下两项)。
每次只能操作相邻两项,最终剩下的数一定是原数列中的连续一段。考虑第一个数和后面哪些数一起,即可枚举出答案,每次找到能满足答案的分配的最远的即可。
最远是为了解决3 3 0这种情况, 0不能被很好的考虑进去
复杂度n ^ 2
#include<bits/stdc++.h>
#define ll long long
#define db double
using namespace std;
int readint() {
int rt = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
rt = (rt << 1) + (rt << 3) + ch - '0';
ch = getchar();
}
return rt * f;
}
ll readll() {
ll rt = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
rt = (rt << 1) + (rt << 3) + ch - '0';
ch = getchar();
}
return rt * f;
}
const int maxn = 2005;
int T, n, a[maxn], sum[maxn];
bool flag = 0;
void input() {
n = readint();
for (int i = 1; i <= n; i++) a[i] = readint(), sum[i] = sum[i - 1] ^ a[i];
flag = 0;
}
bool check(int s) {
int tmp = sum[s];
int lf = s;
while (1) {
bool f = 0;
for (int i = n; i >= lf + 1; i--) {
if ((sum[i] ^ sum[lf]) == tmp) {
lf = i;
f = 1;
break;
}
}
if (!f || lf == n) break;
}
return lf == n;
}
void solve() {
for (int i = 1; i <= n - 1; i++) {
if (check(i)) {
flag = 1;
break;
}
}
}
void output() {
if (flag) {
puts("YES");
} else {
puts("NO");
}
}
int main() {
T = readint();
while (T--) {
input();
solve();
output();
}
return 0;
}
CF1514C. Product 1 Modulo N
题目大意:有1 ~ (n - 1)的数,取出一个最长的子序列,让他们的乘积mod(n)为1
首先考虑最终答案中的数有什么特点, 比如有一个数x, 其他数的乘积为sum, x * sum % n = 1, sum为x在n下的逆元,有逆元的条件是gcd(x,n) = 1, 将这些数加进新数组中并求sum
考虑这个sum中怎么删去一个数让他变成合法答案, 考虑删除中间的一个数x后成立, x * 1 % n = sum, 即删除sum这个数后成立,特殊考虑一下sum = 1的情况
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n;
int a[maxn], sum, cnt;
int pos;
int gcd(int x, int y) {
if (!y) return x;
return gcd(y, x % y);
}
int main() {
scanf("%d", &n);
sum = 1;
for (int i = 1; i < n; i++) {
if (gcd(i, n) == 1) {
a[++cnt] = i;
sum = 1LL * sum * i % n;
}
}
if (sum == 1) {
printf("%d\n", cnt);
for (int i = 1; i <= cnt; i++) printf("%d ", a[i]);
} else {
for (int i = 1; i <= cnt; i++) {
if (a[i] % n == sum) {
pos = i;
break;
}
}
printf("%d\n", cnt - 1);
for (int i = 1; i <= cnt; i++) {
if (pos != i) printf("%d ", a[i]);
}
}
return 0;
}
CF1513C. Add One
题目大意:将一个数拆成单个的数字,每次将每个数字加1得到一个新的数,求操作m次之后的该数的长度
考虑到只有9在操作一次之后变成了10,可以拆分成1和0的贡献,考虑递推
dp[i][j]表示i这个数字操作了j次之后的长度
0 - 8正常转移,9的时候拆成1和0的贡献相加
#include<bits/stdc++.h>
#define ll long long
#define db double
using namespace std;
int readint() {
int rt = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
rt = (rt << 1) + (rt << 3) + ch - '0';
ch = getchar();
}
return rt * f;
}
ll readll() {
ll rt = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
rt = (rt << 1) + (rt << 3) + ch - '0';
ch = getchar();
}
return rt * f;
}
const int maxn = 2e5 + 5;
const int Mod = 1e9 + 7;
int T, n, m;
int f[10][maxn];
int ans = 0;
void input() {
n = readint(), m = readint();
ans = 0;
}
void solve() {
while (n) {
ans += f[n % 10][m];
ans %= Mod;
n /= 10;
}
}
void output() {
printf("%d\n", ans);
}
int main() {
T = readint();
for (int i = 0; i <= 9; i++) f[i][0] = 1;
for (int i = 1; i <= 2e5; i++) {
for (int j = 0; j <= 8; j++) f[j][i] = f[j + 1][i - 1];
f[9][i] = (f[1][i - 1] + f[0][i - 1]) % Mod;
}
while (T--) {
input();
solve();
output();
}
return 0;
}
CF1512F. Education
题目大意:每天你可以有两种操作:
1.在第i层挣a[i]
2.在钱足够b[i]的情况下升到i+1层,钱减少b[i]
问钱达到c的时候最少需要多少天
最终的答案可以分解为到达第i层的天数和在第i层的天数
对于每一层,需要挣到给定钱数的天数可以O(1)的求出。
对于上到i层的天数可以递推出 有一个小贪心,能上就上一定是最优的
然后枚举最后到了第几层即可 注意考虑一天挣很多钱的情况
#include<bits/stdc++.h>
#define ll long long
#define db double
using namespace std;
int readint() {
int rt = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
rt = (rt << 1) + (rt << 3) + ch - '0';
ch = getchar();
}
return rt * f;
}
ll readll() {
ll rt = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
rt = (rt << 1) + (rt << 3) + ch - '0';
ch = getchar();
}
return rt * f;
}
const int maxn = 2e5 + 5;
int T, n;
ll ans;
ll c, a[maxn], b[maxn], d[maxn], r[maxn];
void input() {
ans = 1e9;
n = readint();
c = readll();
for (int i = 1; i <= n; i++) a[i] = readll();
for (int i = 1; i <= n - 1; i++) b[i] = readll();
}
void solve() {
r[1] = 0;
d[1] = 0;
for (int i = 2; i <= n; i++) {
if (r[i - 1] >= b[i - 1]) {
d[i] = d[i - 1] + 1;
r[i] = r[i - 1] - b[i - 1];
} else {
ll t = (b[i - 1] - r[i - 1] + a[i - 1] - 1) / a[i - 1];
d[i] = d[i - 1] + t + 1;
r[i] = r[i - 1] + a[i - 1] * t - b[i - 1];
}
}
for (int i = 1; i <= n; i++) {
if (c <= r[i]) ans = min(ans, d[i]);
else ans = min(ans, d[i] + (c - r[i] + a[i] - 1) / a[i]);
}
}
void output() {
printf("%d\n", ans);
}
int main() {
T = readint();
while (T--) {
input();
solve();
output();
}
return 0;
}
CF1512G. Short Task
题目大意:定义函数d(n)为n的因子和,求d(n) = C的最小的n值, 没有输出-1
显然线性筛,考虑线性筛怎么求因数和:
-
对于p∈primesp∈primes,显然有d[p]=p+1d[p]=p+1.
-
对于ii,若i%primes[j]==0i%primes[j]==0说明primes[j]primes[j]不是ii的最小因子,把因数和公式展开后可以得到结论:d[i∗primes[j]]=d[i]∗(primes[j]+1)d[i∗primes[j]]=d[i]∗(primes[j]+1)
-
若i%pirmes[j]!=0i%pirmes[j]!=0说明primes[j]primes[j]是ii的最小因子,考虑维护每个数对应的最小质因子的在约数和中的贡献:即1+p+p2+...pw11+p+p2+...pw1,其中pp是ii的最小质因子。则d[i∗primes[j]]=d[i]/minp[i]∗minp[i∗primes[j]]d[i∗primes[j]]=d[i]/minp[i]∗minp[i∗primes[j]].
-
维护minpminp部分:质数显然,若primes[j]primes[j]不是ii的最小质因子,那么minp[i∗primes[j]]=primes[j]+1minp[i∗primes[j]]=primes[j]+1.否则minp[i∗primes[j]]=minp[i]∗primes[j]+1minp[i∗primes[j]]=minp[i]∗primes[j]+1.
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define forn(i,x,n) for(int i = x;i <= n;++i) #define forr(i,x,n) for(int i = n;i >= x;--i) #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0) typedef pair<int,int> pii; #define x first #define y second const int N = 1e7+7; int primes[N],cnt,ans[N]; ll minp[N],dsum[N]; bool st[N]; void init() { dsum[1] = 1; for(int i = 2;i < N;++i) { if(!st[i]) primes[cnt++] = i,dsum[i] = i + 1,minp[i] = i + 1; for(int j = 0;j < cnt && 1ll*primes[j] * i < N;++j) { st[primes[j] * i] = 1; if(i % primes[j]) dsum[i * primes[j]] = dsum[i] * (primes[j] + 1),minp[i * primes[j]] = primes[j] + 1; else { minp[i * primes[j]] = minp[i] * primes[j] + 1; assert(minp[i] != 0); dsum[i * primes[j]] = dsum[i] / minp[i] * minp[i * primes[j]]; break; } } } forn(i,1,N - 1) if(dsum[i] < N && !ans[dsum[i]]) ans[dsum[i]] = i; } int main() { init(); int T;scanf("%d",&T); while(T--) { int n;scanf("%d",&n); printf("%d\n",ans[n] == 0 ? -1 : ans[n]); } return 0; }