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 ……**nx**加粗为不符合条件的 -
找到数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;
}