第一题
题目大意
给定两个数字,分别表示 n 和 k,并要求给出 k 个奇偶性相同的正整数,使得其和等于 n,例如 n = 10,k = 3,答案可以为 [4 2 4]。本题是SPJ
思路
这个题乍一看没有头绪,其实仔细想一下:题目只需要奇偶性相同就可以,试想,若一个数可以分成全是奇数的组合,则一定可以拆分为1+1+1+…+一个奇数;若全是偶数可以组成,则一定可以拆分为:2+2+2…+一个偶数。所以只需要判断这两种情况就可以了
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int t=0;
scanf("%d",&t);
while(t--){
long long n,k;
scanf("%lld%lld",&n,&k);
long long s=n-(k-1);
long long m=n-(k-1)*2;
if(s%2==1&&s>0){
printf("YES\n");
int i=0;
for(;i<k-1;i++){
if(i) printf(" ");
printf("1");
}
if(i) printf(" ");
printf("%lld\n",s);
}
else if(m%2==0 && m>0){
printf("YES\n");
int i=0;
for(;i<k-1;i++){
if(i) printf(" ");
printf("2");
}
if(i) printf(" ");
printf("%lld\n",m);
}
else printf("NO\n");
}
return 0;
}
第二题
题目大意
给定两个数字,分别表示 n 和 k,要求给出无法被 n 整除的第 k 大的正整数。例如 n = 3,k = 7,则前 7 个无法被 n 整除的正整数为 [1 2 4 5 7 8 10],所以第7个为 10。
思路
这个题实际要求的是:无法被 n 整除 n的倍数 ,只需要想到,无法被n整除的数,一定分布在:m*n~(m+1)*n之间,其中m大于等于0。所以,我们只需要先计算出k属于哪个区间内: k/(n-1), 再计算内部的偏移量:k%(n-1)。如果偏移量为0,则说明是上一个区间的最后一个数;若不为0,则为本区间的数。
代码
#include<bits/stdc++.h>
using namespace std;
//无法被 n 整除 n的倍数
long long n,k;
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
long long mod = k /(n-1);
long long s=k%(n-1);
if(s==0) printf("%lld\n",mod*n-1);
else printf("%lld\n",mod*n+s);
}
return 0;
}
第三题
题目大意
猫咪从天上往下掉,且只会掉在 [0, 10] 范围内,TT 初始站在位置五上,且每秒只能在移动不超过一米的范围内接住掉落的猫咪,如果没有接住,猫咪就会跑掉。例如,在刚开始的一秒内,TT 只能接到四、五、六这三个位置其中一个位置的猫咪。
输入给出不同时刻,猫咪的掉落位置,输出TT最大可获得的猫咪数量。
思路
首先,通过输入,得到不同时刻,每个点掉落的数量,并且获得掉落持续的总时间。之后,设定状态为
f
[
k
]
[
t
]
f[k][t]
f[k][t],即当TT在坐标为k的位置,时间是第t秒,可以获得的总数量。转移方程就是:从t-1时刻的3个位置,向k转移
f
[
k
]
[
t
]
=
m
a
x
(
f
[
k
−
1
]
[
t
−
1
]
,
f
[
k
]
[
t
−
1
]
,
f
[
k
+
1
]
[
t
−
1
]
)
+
g
[
k
]
[
t
]
f[k][t]=max(f[k-1][t-1],f[k][t-1],f[k+1][t-1])+g[k][t]
f[k][t]=max(f[k−1][t−1],f[k][t−1],f[k+1][t−1])+g[k][t]
g
[
k
]
[
t
]
g[k][t]
g[k][t]是掉落的数量。
但要注意的是,因为t-1时刻下,k-1,k+1,k 并不是都可以来更新k位置,因为只有TT可能出现位置的左右一个单位之内,才可以转移状态,所以需要额外记录时刻t,位置k是否有效: v a l [ k ] [ t ] val[k][t] val[k][t],因此转移方程变为:
if((val[k-1][t-1]|val[k][t-1])|val[k+1][t-1])
f[k][t]=max(f[k-1][t-1]*val[k-1][t-1],max(f[k][t-1]*val[k][t-1],f[k+1][t-1]*val[k+1][t-1]))+g[k][t];
最后,对t时刻的所有位置取max即可
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int g[15][100099];
int f[15][100099];
int val[15][100099]; //是否有效
int main()
{
int m;
while(~scanf("%d",&m))
{
if(m==0) break;
for(int s=0;s<=10;s++) f[s][0]=0;
memset(val,0,sizeof 0);
val[5][0]=1;
memset(g,0,sizeof g);
int a,b,maxt=0,ans=0;
for(int i=0;i<m;i++){
scanf("%d%d",&a,&b);
maxt=max(maxt,b);
g[a][b]++;
}
for(int t=1;t<=maxt;t++){
for(int k=0;k<=10;k++){
int tmp=0;
bool tag=0;
if(k==0){
tmp=max(f[0][t-1]*val[0][t-1],f[1][t-1]*val[1][t-1]);
tag=val[0][t-1]|val[1][t-1];
}
else if(k==10) {
tmp=max(f[10][t-1]*val[10][t-1],f[9][t-1]*val[9][t-1]);
tag = val[10][t-1]|val[9][t-1];
}
else {
tmp =max(f[k-1][t-1]*val[k-1][t-1],max(f[k][t-1]*val[k][t-1],f[k+1][t-1]*val[k+1][t-1]));
tag =(val[k-1][t-1]|val[k][t-1])|val[k+1][t-1];
}
if(tag>0){
val[k][t]=1;
f[k][t]=tmp+g[k][t];
ans = max(ans,f[k][t]);
}
}
}
printf("%d\n",ans);
}
return 0;
}