Educational Codeforces Round 99 (Rated for Div. 2) 11/30

比赛链接

T1

给出 f ( x ) = i n t ( r e v e r s e ( x ) ) f(x)=int(reverse(x)) f(x)=int(reverse(x)),例如 f ( 123 ) = 321 , f ( 100 ) = 001 = 1 f(123)=321,f(100)=001=1 f(123)=321,f(100)=001=1
再给出 g ( x ) = x f ( f ( x ) ) g(x)=\frac{x}{f(f(x))} g(x)=f(f(x))x,输入一个整数n。求 1 ≤ x ≤ n 1\leq x\leq n 1xn,构成的 g ( x ) g(x) g(x)集合中有几个元素。
1 ≤ x ≤ 1 0 100 1\leq x\leq10^{100} 1x10100

签到题,观察题目,发现例如123,189,这样结尾不带0的求出来之后 g ( x ) = 1 g(x)=1 g(x)=1
例如 g ( 90 ) = 10 , g ( 900 ) = 100 , g ( 800 ) = 100 , g ( 1000 ) = 1000 g(90)=10,g(900)=100,g(800)=100,g(1000)=1000 g(90)=10,g(900)=100,g(800)=100,g(1000)=1000,也就是多一位就可以多一个10的倍数。求一下输入的x的长度就行了。

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define all(__vv__) (__vv__).begin(), (__vv__).end()
#define endl "\n"
#define pai pair<int, int>
#define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__))
#define rep(i, sta, en) for(int i=sta; i<=en; ++i)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())	s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op)	putchar(op); return; }	char F[40]; ll tmp = x > 0 ? x : -x;	if (x < 0)putchar('-');	int cnt = 0;	while (tmp > 0) { F[cnt++] = tmp % 10 + '0';		tmp /= 10; }	while (cnt > 0)putchar(F[--cnt]);	if (op)	putchar(op); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;	while (b) { if (b & 1)	ans *= a;		b >>= 1;		a *= a; }	return ans; }	ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 7;

void solve() {
	char s[N];
	scanf("%s", s);
	int len = strlen(s);
	print(len);
}

int main() {
	int T = read();	while (T--)
		solve();
	return 0;
}

T2

沿着x轴正方向跳格子,第几个回合你的正向跳跃距离就是几。但是你的回合也可以选择后退一个格子。问跳到x=p点处最小的跳跃次数。
1 ≤ p ≤ 1 0 6 1\leq p\leq10^6 1p106

我们不难发现上面就是一个等差数列求和,例用求和公式,先计算一下如果恰好一次都不后退可以跳到目标点,直接输出等差数列的项数即可。如果我们只在第一次跳跃后退,那么我们最终答案就会变成 n ∗ ( n − 1 ) / 2 − 2 n*(n-1)/2-2 n(n1)/22,因为之前+1,现在-1,对长度的影响是2。那么同理,如果我们只在第二次跳跃的时候回退,我们对长度的影响是3,在第n-1次跳跃的时候回退,对长度的影响就是n。那么如果我们上面不能直接通过等差数列跳到目标点,那么我们就可以使用n次等差数列跳跃去到第一个大于等于n的点,接下来我们如果刚好停在了x+1处,但是我最小的回退距离都是2,说明无法通过修改中间步骤进行调整,只能原地回退一步,但是如果我们停在大于x+1的地方,一定向前跳跃的时候选择一步进行回退,让终点刚好停在x处。

void solve() {
	int n = read();
	int ans = 1;
	while (ans * (ans + 1) < 2 * n)
		++ans;
	if (ans * (ans + 1) / 2 == n + 1)	++ans;
	print(ans);
}

T3

博弈题,给出双方体力x和y,由x体力的人先发球,每次发球消耗一点体力,对方可以选择也消耗一点体力将这个球打回去,这样x就不能得分。谁得分下一次球就是谁发,现在他们两个人都希望在自己得分最高为第一前提,其次在降低对方得分的情况下,双方的最高得分分别是几。
1 ≤ x , y ≤ 1 0 6 1\leq x,y\leq10^6 1x,y106

看到双方都要最大化自己的比分,那么做为后手的y,只能在x发完最后一球,没有体力的时候进行反击一定会最大化自己的得分,那么x的最大得分就是发球数-1了。

void solve() {
	n = read(), m = read();
	printf("%lld %lld\n", n - 1, m);
}

T4

给出长度为n的序列,以及起始的x。你可以选择一个元素 a i a_i ai,如果保证了 a i > x a_i>x ai>x,你就可以选择交换这两个元素,使用x填充进之前 a i a_i ai的位置,并且把 a i a_i ai看成新的x,进行下一次匹配。询问在最少的次数交换中使得序列变得非递减,这样的交换次数是几次。如果永远无法有序输出-1。
1 ≤ n , x ≤ 500 1\leq n,x\leq500 1n,x500

动态规划题目,我们使用 d p [ i ] [ j ] dp[i][j] dp[i][j]代表当前使用 j j j替换掉 a i a_i ai的最少替换次数。那么接下来我们就可以找到递推的方程,首先第一次替换的时候,我们找出全部可以用初始的x替换的点更新成1,其余赋值无穷大。注意如果当前遍历的 a i > a i + 1 a_i>a_{i+1} ai>ai+1,说明不需要继续往后面找第一次替换了,因为这个地方如果不更新 a i a_i ai,下一次我们只能把 a i + 1 a_{i+1} ai+1变成一个更小的x,显然无法使得它变成有序的。
下面的递推式就是,使用双重的循环,枚举 i i i j j j了,保证 d p [ i ] [ j ] ! = I N F dp[i][j]!=INF dp[i][j]!=INF前提,如果 i i i走到了n说明替换完成,或者使用 j j j替换 a i a_i ai后,序列满足了要求,也可以更新一次答案。下面就是状态的转移了,我们使用 j j j替换 a i a_i ai之后,枚举 k k k,尝试使用 a i a_i ai替换 a k a_k ak。也是要注意保证序列要有序的前提下。

const int N = 500 + 7;
 
ll n, m;
int dp[N][N], a[N];
 
void solve() {
	n = read(), m = read();
	rep(i, 1, n)	a[i] = read();
	if (is_sorted(a + 1, a + 1 + n)) { print(0); return; }
	ms(dp, 0x3f);
	rep(i, 1, n) {
		if (a[i] > m and (i == 0 or a[i - 1] <= m))
			dp[i][m] = 1;
		if (i<n and a[i]>a[i + 1])
			break;
	}
	int ans = INF;
	rep(i, 1, n) {
		rep(j, 0, 500) {
			if (dp[i][j] == INF)	continue;
			if (i == n or (j <= a[i + 1] and is_sorted(a + i + 1, a + n + 1)))
				ans = min(ans, dp[i][j]);
			rep(k, i + 1, n) {
				int pre = (k == i + 1 ? j : a[k - 1]); // a[i]已经被替换成j的前提下
				if (a[i] >= pre and a[k] > a[i]) // 可以把a[i]换入a[k]
					dp[k][a[i]] = min(dp[k][a[i]], dp[i][j] + 1);
				if (a[k] < pre)	break; // 出现了一个不合理的排序对
			}
		}
	}
	if (ans == INF) ans = -1;
	print(ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值