http://vjudge.net/contest/135602#overview
http://vjudge.net/contest/135602#rank
A
给出一些对 X 加加减减的过程,问 X 最后是几(X 最初是 0)。
#include <bits/stdc++.h>
int main()
{
int n;
scanf("%d", &n);
int x = 0;
char cmd[5];
for (int i = 1; i <= n; ++i) {
scanf("%s", cmd);
if (cmd[1] == '-') {
x--;
}
else {
x++;
}
}
printf("%d\n", x);
return 0;
}
B
给出 x,每次减去 x 某个数位上的数,问最少多少次可以使得 x 变成 0。
可以 dp,如果注意到贪心策略也可以模拟通过。
#include <bits/stdc++.h>
const int MAX_N = 1e6 + 10;
int f[MAX_N];
int main()
{
int n;
scanf("%d", &n);
f[0] = 0;
for (int i = 1; i <= n; ++i) {
f[i] = 1e9;
for (int j = i; j; j /= 10) {
if (j % 10 == 0) {
continue;
}
f[i] = std::min(f[i], f[i - j % 10] + 1);
}
}
printf("%d\n", f[n]);
return 0;
}
C
给出一个字符串,查询一个区间中有多少对相邻相等的字符。
用 fi 表示 1 到 i 中相邻相等的字符对数,对于 l 到 r 的查询,答案就是 fr−fl 。
#include <bits/stdc++.h>
const int MAX_N = 1e5 + 10;
int f[MAX_N];
char str[MAX_N];
int main()
{
scanf("%s", str + 1);
int n = strlen(str + 1);
f[1] = 0;
for (int i = 2; i <= n; ++i) {
f[i] = f[i - 1] + (str[i] == str[i - 1]);
}
int m;
scanf("%d", &m);
for (int i = 1; i <= m; ++i) {
int l, r;
scanf("%d %d", &l, &r);
printf("%d\n", f[r] - f[l]);
}
return 0;
}
D
n 个物品排列成 a(a > 1)行,n / a 列的方阵,每次取一行留下,其余丢掉,直到剩余一个物品即不再进行操作。问操作过程中每一步剩余物品数目的和最大是多少。
要上述值最大,应让操作更多,应让每次剩余的最多——这两个要求是统一的,即每次都使得 a 尽量小。故可以模拟这个过程,不难发现这个过程最多大概只有 O(n√) 步,毋需担心时间。
#include <bits/stdc++.h>
int main()
{
int n;
std::cin >> n;
long long ans = n;
for (int i = 2; i <= n / i; ++i) {
for (; n % i == 0; ) {
n /= i;
ans += n;
}
}
if (n > 1) {
ans += 1;
}
std::cout << ans << std::endl;
return 0;
}
E
给出 x = 1,y = 0,依赖一个数列 a1,a2,...,an ,轮流进行题目指示的操作(比较繁琐……见题目描述吧……),操作会无限循环下去或者使得 x 超出 [1,n] 。对于 i,a2,a3,...,an(1≤i<n) 。如果不断循环,输出 -1,否则输出结束时 y 的值。
第一次操作之后 x = 1 + i,y = i,并 y 在操作中不断累加,这启发我们 dp。用
fx,0
表示先进行加操作,从 x 开始,y 初始取 0,直到最后时 y 的值,如果操作不能结束,令这个值为无穷大;同理
fx,1
表示先进行减操作的对应值。每个状态模拟当前的操作就不难转移,转移到正在递归的值即说明出现循环,具体不再赘述。当处理出所有的
f
之后,
#include <bits/stdc++.h>
const int MAX_N = 2e5 + 100;
const long long INFLL = 0x3f3f3f3f3f3f3f3fLL;
long long f[MAX_N][2];
bool vis[MAX_N][2];
int a[MAX_N];
long long dfs(int n, int x, int d)
{
if (x > n || x < 1) {
return 0;
}
if (x == 1) {
return INFLL;
}
if (f[x][d] != -1) {
return f[x][d];
}
if (vis[x][d]) {
return INFLL;
}
vis[x][d] = true;
long long ans;
if (d == 0) {
ans = dfs(n, x + a[x], !d);
}
else {
ans = dfs(n, x - a[x], !d);
}
if (ans != INFLL) {
ans += a[x];
}
return f[x][d] = ans;
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 2; i <= n; ++i) {
scanf("%d", a + i);
}
memset(f, -1, sizeof(f));
for (int i = 2; i <= n; ++i) {
dfs(n, i, 0);
dfs(n, i, 1);
}
for (int i = 1; i < n; ++i) {
if (f[i + 1][1] == INFLL) {
printf("-1\n");
}
else {
printf("%I64d\n", f[i + 1][1] + i);
}
}
return 0;
}
F
一排 n 只奶牛,有些朝前看,有些朝后看。Iahub 按照一定顺序给牛挤奶,每头牛只挤一次。当一头牛看到某头牛被挤了奶,则会受到一点心理伤害。问牛心理伤害总和最小是多少。
两头相互看到的牛无论谁先都会产生一点心理伤害(来啊!相互伤害啊!!!),否则可以恰当安排挤奶顺序,使得这两头牛不会因为彼此受到伤害。故答案就是相互注视的牛的对数。
#include <bits/stdc++.h>
const int MAX_N = 2e5 + 10;
int l1[MAX_N];
int r0[MAX_N];
int a[MAX_N];
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
}
for (int i = 1; i <= n; ++i) {
l1[i] = l1[i - 1] + (a[i] == 1);
}
for (int i = n; i >= 1; --i) {
r0[i] = r0[i + 1] + (a[i] == 0);
}
long long ans = 0;
for (int i = 1; i <= n; ++i) {
if (a[i] == 0) {
ans += l1[i - 1];
}
else {
ans += r0[i + 1];
}
}
std::cout << ans / 2 << std::endl;
return 0;
}
posted by 张静之