week13 作业

TT的神秘任务1


思路

  • 题目要求找出k个奇偶性相同正整数,使其和等于n。

  • 当k>n的时候可以知道,k个正整数等于n是不可能的。

  • 当k==n的时候,这k个正整数只能全是1。

  • 接下来讨论k>n的时候。
    思想是:在k个数奇偶性相同的情况下,对其中的数进行+2是一定能够保证这k个数的奇偶性的一致性。

  • 先考虑k个奇数是否能够刚好等于n。将这k个数先置为1,就变成了求解k个数是否能到达n-k。判断k和n-k的关系,依照2和3步骤。

  • 对于这k个数,先计算n-k中能给这k个数多少个2,假设能给d个2,即k* 2 * d<=n&&k * 2 * (d+1)>n。那么将这k个数分别加上2 * d。

  • 若k * 2 *d == n-k,代表这k个数符合条件。

  • 若k * 2 * d != n-k,假设n-k给了k个数d个2后,还剩了last。如果last是奇数,代表不能给出偶数个2来保持k个数的奇偶性,则代表不成功;如果是last偶数,那么还能给出last/2个2来,给k个数中的其中last/2个数加上2即可成功。

  • 对于考虑k个偶数是否能够刚好等于n,只需将这k个数先置为2,其他操作与考虑奇数一样。

总结

上述对于k先置1或先置2后,需要重新判断一下k和n-k或n-2 * k的关系,判断是否能能有解。并且对于考虑k个偶数 的时候,这里选择的是先置2,因为0不是正整数,置0会出现错误。例如6个数加起来等于8,先置0的话,会计算出2 2 2 2 0 0这6个数。

代码

#include<iostream>
#include<string.h>
using namespace std;
#define range 100+10
int T = 0, n = 0, k = 0;
int a[range];
bool solve(int sum,int num) {
	int d = sum / (num * 2);//能给多少个2
	int last = sum % (num * 2);//给了d个2还剩多少
	if (last == 0) {//全给
		for (int i = 0; i < num; i++) a[i] += 2 * d;
		return true;
	}
	else {
		for (int i = 0; i < num; i++) a[i] += 2 * d;
		if (last % 2 != 0)//剩了奇数
			return false;
		else {
			int tmp = last / 2;
			for (int i = 0; i < tmp; i++)
				a[i] += 2;
			return true;
		}
	}
}
int main() {
	cin >> T;
	while (T--) {
		cin >> n >> k;
		if (k > n) {
			cout << "NO" << endl;
			continue;
		}
		else if (n % k == 0) {
			cout << "YES" << endl;
			cout << n/k;
			for (int i = 1; i < k; i++)
				cout << " " << n/k;
			cout << endl;
			continue;
		}
		for (int i = 0; i < k; i++)a[i] = 2;
		if (n - (2 * k) >= 0 && solve(n - (2 * k), k) == true) {
			cout << "YES" << endl;
			cout << a[0];
			for (int i = 1; i < k; i++)
				cout << " " << a[i];
			cout << endl;
			continue;
		}
		for (int i = 0; i < k; i++)a[i] = 1;
		if (n - k >= 0 && solve(n - k, k) == true) {
			cout << "YES" << endl;
			cout << a[0];
			for (int i = 1; i < k; i++)
				cout << " " << a[i];
			cout << endl;
			continue;
		}
		cout << "NO" << endl;
	}
	return 0;
}

TT的神秘任务2


思路

  • 如果k<n,那么符合条件的第k个数就是k。

  • 对于数n,可以知道前nx个数里面nx-x=(n-1)x个符合条件(能被n整除)。
    1 2 3 4 ……x x+1 x+2 x+3 ……2 * x ……**n
    x**加粗为不符合条件的

  • 找到数x,使前n * (x-1)个数里符合条件的数小于k个,前n*x个数里符合条件的数大于等于k个。在数n * (x-1)后面还要找k-(n-1) * (x-1)个数,故答案最终为n *(x-1)+k-(n-1) * (x-1)。

总结

对于求x,因为(n-1)* x >= k && (n-1) * (x-1) < k,只需要k/(n-1)向上取整就好了。一开始居然用二分,搞不懂在想什么/(ㄒoㄒ)/~~。

代码

#include<iostream>
#include<cmath>
using namespace std;
int T = 0, n = 0, k = 0, ans = 0;
void solve() {
	if (k < n) {
		ans = k;
		return;
	}
	//前nx个数里有nx-x=(n-1)*x个符合条件,(n-1)x>=k,x>=k/(n-1)
	int x = k / (n - 1);
	if (k % (n - 1) != 0) x++;
	//cout << "前" << n * (x-1) << "个数里有" << (n - 1) * (x-1) << "个数符合要求" << endl;
	//cout << "前" << n * x << "个数里有" << (n - 1) * x << "个数符合要求" << endl;
	
	//cout << "x" << x << endl;
	if (x == 1) ans = k + 1;
	else {
		int num = k - (n - 1) * (x - 1);
		ans = n * (x - 1) + num;
	}
}
int main() {
	cin >> T;
	ans = 0;
	while (T--) {
		cin >> n >> k;
		solve();
		cout << ans << endl;
	}
	return 0;
}

TT的奖励


思路

dp(i,j)代表时间从最后一秒往前走,到达第i秒的时候,j坐标接到的猫总数量。初始的时候都置为0。

  • 从后往前到达第i秒的的时候,dp(i,j)等于第i+1秒的时候j-1,j,j+1位置上最大的猫数加上第i秒j位置掉落的猫。
  • 因为在第一秒的时候,只能接到4,5,6三个位置的猫,所以答案是dp(1,5),dp(1,4),dp(1,6)里面的最大值。

总结

一开始想的是时间从前往后走,但是又要考虑第一秒只能走4,5,6,第二秒只能走3,4,5,6,7,……,比较麻烦。

代码

#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
#define range 100000+10
int dp[range][11];//dp[i][j]前i秒j坐标
int cat[range][11];//cat[i][j]第i秒j位置的猫
int m = 0;
int main() {
	while (cin >> m && m != 0) {
		memset(dp, 0, sizeof(dp));
		memset(cat, 0, sizeof(cat));
		int a = 0, b = 0, lastt = 0;
		for (int i = 0; i < m; i++) {
			cin >> a >> b;//第b秒落在a点
			cat[b][a]++;
			lastt = max(lastt, b);
		}
	//	for (int i = 0; i <= lastt; i++) {
	//		for (int j = 0; j <= 10; j++)
	//			cout << cat[i][j] << "   ";
	//			cout << endl;
	//	}
		for (int i = lastt+1; i > 0; i--) {
				for (int j = 0; j < 11; j++) {
					if (j - 1 >= 0) dp[i][j] = max(dp[i][j], dp[i+1][j - 1]);
					if (j + 1 <= 10) dp[i][j] = max(dp[i][j], dp[i+1][j + 1]);
					dp[i][j] = max(dp[i][j], dp[i+1][j]);
					dp[i][j] += cat[i][j];
				}
		}
		int ans = max(dp[1][5], max(dp[1][4], dp[1][6]));
		cout << ans<< endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值