2021.07.17【普及组】模拟赛C组
写在前面:
今天比昨天好一点,因为今天只因为吃换行丢了100分呢!
快乐…😢😢😢
ok,来总结吧!
T1:
题目大意:
金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是整数元)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,……,jk,则所求的总和为:
v[j1]×w[j1]+v[j2]×w[j2]+ …+v[jk]×w[jk]。
请你帮助金明设计一个满足要求的购物单。
正解:
我都不太想讲,这道题…
那么裸的DP,这都不会?
ok我们设:
f
i
=
背
包
容
量
为
i
时
,
所
拥
有
的
价
值
f_i=背包容量为i时,所拥有的价值
fi=背包容量为i时,所拥有的价值
然后,我们直接写出状态转移方程:
f
i
=
max
(
f
i
,
f
i
−
v
j
+
w
j
)
f_i=\max(f_i,f_{i-v_j}+w_j)
fi=max(fi,fi−vj+wj)
直接过掉!!!
code:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6*3+1;
int f[N], v[N], w[N];
int n, m;
int main() {
freopen("happy.in","r",stdin);
freopen("happy.out","w",stdout);
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i ++) {
scanf("%d%d", &v[i], &w[i]);
w[i]*=v[i];
}
for (int i = 1; i <= m; i ++) {
for(int j = n; j >= v[i]; j --)
f[j] = max(f[j], f[j-v[i]]+w[i]);
}
printf("%d",f[n]);
}
T2:
题目大意:
am是个喜欢标新立异的科学怪人。他不使用阿拉伯数字计数,而是使用小写英文字母计数,他觉得这样做,会使世界更加丰富多彩。在他的计数法中,每个数字的位数都是相同的(使用相同个数的字母),英文字母按原先的顺序,排在前面的字母小于排在它后面的字母。我们把这样的“数字”称为Jam数字。
在Jam数字中,每个字母互不相同,而且从左到右是严格递增的。每次,Jam还指定使用字母的范围,例如,从2到10,表示只能使用{b,c,d,e,f,g,h,i,j}这些字母。如果再规定位数为5,那么,紧接在Jam数字“bdfij”之后的数字应该是“bdghi”。(如果我们用U、V依次表示Jam数字“bdfij”与“bdghi”,则U<V,且不存在Jam数字P,使U<P<V)。你的任务是:对于从文件读入的一个Jam数字,按顺序输出紧接在后面的5个Jam数字,如果后面没有那么多Jam数字,那么有几个就输出几个。
正解:
枚举啊!
直接dfs打组合数即可,可以瞬间过掉,昨天火星人那道题跟这个差不多。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+1;
char b[N],c[N];
int s,t,w,sum,flag=false;
char p;
void dfs(int l) {
if(sum == 5) return ;
if(l > w) {
if(flag) {
for(int i = 1; i <= w; i ++) printf("%c", b[i]);
sum ++;
if(sum == 5) return ;
printf("\n");
}
else {
int o = 0;
for(int i = 1; i <= w; i ++) {
if(b[i] != c[i]) {
o = 1;
break;
}
}
if(o == 0) flag = true;
}
return ;
}
for(char i = char(b[l-1]+1); i <= p; i ++) {
b[l] = i;
dfs(l+1);
b[l] = 0;
}
return ;
}
int main() {
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d%d%d", &s, &t, &w);
scanf("\n",&p);
for(int i = 1; i <= w; i ++) scanf("%c", &c[i]);
b[0] = char(96+s-1);
p = char(96+t);
dfs(1);
return 0;
}
T3:
题目大意:
给定一个正整数k(3≤k≤15),把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列,例如,当k=3时,这个序列是:
1,3,4,9,10,12,13,…
(该序列实际上就是:30,31,30+31,32,30+32,31+32,30+31+32,…)
请你求出这个序列的第N项的值(用10进制数表示)。
例如,对于k=3,N=100,正确答案应该是981。
正解:
我们仔仔细细观察,显然,3=2+1=21+20;
所以,第三项就等于:30+31;
这不就是规律吗?
第k项=3(x2)+3(y2)……,k=x+y+……
ok,我们直接使用两个while即可做出本题。
code:
#include <bits/stdc++.h>
using namespace std;
const int N = 100001;
long long n, k, i, j, sum;
int main() {
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
scanf("%d%d", &n, &k);
while(k > 0) {
while(j <= k) {
j = pow(2, i);
i ++;
}
k -= pow(2, i-2);
sum += pow(n, i-2);
i = j = 0;
}
printf("%lld",sum);
}
T4:
题目大意:
乐乐是一个聪明而又勤奋好学的孩子。他总喜欢探求事物的规律。一天,他突然对数的正整数次幂产生了兴趣。
众所周知,2的正整数次幂最后一位数总是不断的在重复2,4,8,6,2,4,8,6……我们说2的正整数次幂最后一位的循环长度是4(实际上4的倍数都可以说是循环长度,但我们只考虑最小的循环长度)。类似的,其余的数字的正整数次幂最后一位数也有类似的循环现象:
循环 循环长度
2 2、4、8、6 4
3 3、9、7、1 4
4 4、6 2
5 5 1
6 6 1
7 7、9、3、1 4
8 8、4、2、6 4
9 9、1 2
这时乐乐的问题就出来了:是不是只有最后一位才有这样的循环呢?对于一个整数n的正整数次幂来说,它的后k位是否会发生循环?如果循环的话,循环长度是多少呢?
注意:
1. 如果n的某个正整数次幂的位数不足k,那么不足的高位看做是0。
2. 如果循环长度是L,那么说明对于任意的正整数a,n的a次幂和a + L次幂的最后k位都相同。
正解:
首先,因为他只求k位,因此,我们可直接忽略掉前面的数位。
其次,我们看到上图的表,如果我们求十位是多少,那绝对是个位长度的倍数(只有这样,才能使个位重复)
按着这条路走,我们可得知:
x
位
的
长
度
=
x
−
1
的
长
度
的
倍
数
(
x
!
=
1
)
x位的长度=x-1的长度的倍数(x!=1)
x位的长度=x−1的长度的倍数(x!=1)
ok,不过,码量极多,建议大家去找叶奆问问,或找做出来的人问问即可。
我的话……我有空你再来问我也行。
code:
#include <bits/stdc++.h>
using namespace std;
int a[205], b[205], s[505], k, e, d[205], f[205], cnt, ans[205], t, ss(1);
char c[205];
void zh(int x) {
memset(s, 0, sizeof(s));
for(int i = 1; i <= x; i ++)
for(int j = 1; j <= x; j ++)
s[i+j-1] += a[i]*b[j];
for(int i = 1; i <= x; i ++){
s[i+1] += s[i]/10;
s[i] %= 10;
}
for(int i = 1; i <= x; i ++)
a[i] = s[i];
return;
}
bool bd(int x) {
int ff = 0;
for(int i = 1; i <= x; i ++)
if(a[i] != d[i]) {
ff = 1;
break;
}
if(ff)
return false;
else
return true;
}
int pr(int x) {
cnt = 0;
for(int i = 1; i <= x; i ++) {
a[i] = d[i];
b[i] = f[i];
}
do {
zh(x);
cnt ++;
if(cnt>11) {
printf("-1\n");
exit(0);
}
}while(!bd(x));
for(int i = 1; i <= k; i ++) {
a[i] = 0;
b[i] = f[i];
}
a[1] = 1;
for(int i = 1; i <= cnt; i ++)
zh(k);
for(int i = 1; i <= k; i ++)
f[i] = a[i];
return cnt;
}
void cf(int x)
{
int w = 0;
for(int i = 1; i <= ss; i ++) {
ans[i] = ans[i]*x+w;
w = ans[i]/10;
ans[i] %= 10;
if(i == ss&&w)
ss ++;
}
return;
}
int main() {
freopen("circle.in", "r", stdin);
freopen("circle.out", "w", stdout);
scanf("%s%d", c+1, &k);
e = strlen(c+1);
for(int i = 1; i <= k; i ++) {
d[i] = c[e-i+1]-'0';
f[i] = d[i];
}
ans[1] = 1;
for(int i = 1; i <= k; i ++) {
t = pr(i);
cf(t);
}
for(int i = ss; i >= 1; i--)
printf("%d", ans[i]);
return 0;
}