2021-07-17【普及组】模拟赛C组

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,fivj+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=x1x!=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; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值