csdn的竞赛,与其他OJ的周赛相比,有些不太好的体验。举个例子,T1只是想分段收个电费,150度以下的怎么收费,151度以上的怎么收费,按照表述151度电就只收150度的电费,因为没说150-151度之间怎么收费了;T2虽然题目没啥毛病,但是给句子中单词逆序,本来需要做些操作的,cpp给定的模板直接将每个单词存入vector了,要做的就是给vector倒着取下数,没啥意义。T3一开始给的唯一一个用例是3 3,结果是10,给3拆分成3个不小于1的整数,有10种拆法,后面刷新修正为1,用例出错不说什么了。如果给4分为两个整数,那么1 3和3 1算一种还是两种题目也没有表述清楚;T4就是像求个最小的修改数量是多少,问的是通过修改最小的数字变成美丽数列,很容易误解为只能改最小的数字。希望后面的竞赛能改掉这些不足的地方吧。
下面题解代码为赛后书写,所以还不能保证能够通过评测,如果有问题,还望各位大佬帮忙指正。
夏天到了,各家各户的用电量都增加了许多,相应的电费也交的更多了。小玉家今天收到了一份电费通知单。小玉看到上
面写:据闽价电[2006]27号规定,月用电量在150千瓦时及以下部分按每千瓦时0.4463元执行,月用电量在151~400
千瓦时的部分按每千瓦时0.4663元执行,月用电量在401千瓦时及以上部分按每千瓦时0.5663元执行;小玉想自己验证一
下,电费通知单上应交电费的数目到底是否正确呢。请编写一个程序,已知用电总计,根据电价规定,计算出应交的电费
应该是多少。
首先忽略题目不恰当的表述,重新理解为150以下电费多少,150-400电费多少,400以上电费多少,然后分类讨论下即可。
#include
#include
using namespace std;
int main() {
float n;
cin>>n;
float res = 0;
if(n <= 150) res += n * 0.4463;
else {
res += 150 * 0.4463;
if(n <= 400) res += (n - 150) * 0.4663;
else {
res += 250 * 0.4663 + (n - 400) * 0.5663;
}
}
printf("%.1f\n",res);
return 0;
}
对于一个字符串,请设计一个算法,只在字符串的单词间做逆序调整,也就是说,字符串由一些由空格分隔的部分组成,
你需要将这些部分逆序。 给定一个原字符串A,请返回逆序后的字符串。例,输入”I am a boy!“输出”boy! a am I“
题目输入模板已经帮我们分割了单词,逆序输出即可。
#include
#include
#include
#include
std::vector<std::string> solution(std::vector<std::string>& vec){
std::vector<std::string> result;
int n = vec.size();
for(int i = n - 1;i >= 0;i--) result.push_back(vec[i]);
return result;
}
int main() {
std::vector<std::string> vec;
std::string line_0, token_0;
getline(std::cin >> std::ws,line_0);
std::stringstream tokens_0(line_0);
while(std::getline(tokens_0, token_0, ' ')){
vec.push_back((token_0));
}
std::vector<std::string> result = solution(vec);
for(auto it=result.begin();it!=result.end();++it){
std::cout<<*it<<" ";
}
std::cout<<std::endl;
return 0;
}
小Q决定把一个整数n,分割为k个整数。 每个整数必须大于等于1。 小Q有多少方案。
举个例子,如果将4分割为2个正整数,1 3和3 1算不同的方案数的话,那么只需要考虑简单的组合数问题。也就是等价于有一个长度为n的线段,要将这条线段切成k段,就需要在线段上找k - 1个切点,一共有C(n - 1,k - 1)种切法,这个组合数就是答案。
但是本题实际的含义将1 3和3 1视为不同的方案,这个就有点难度了。可以理解为在1到n中找k个正整数,使得这k个正整数之和等于n的方案数。然后问题就变成了方案里面1选了多少个,2选了多少个,…。就可以使用背包问题的思想来解决本题了。
状态表示:f[i][j][t]表示1到i中选了t个整数,且这t个整数的和是j的方案数。t个整数的和可以理解为背包问题中的体积,t相当于附加的限制条件。
状态边界:f[i][0][0] = 1表示前i个整数中一个不选的方案数。
状态转移:需要考虑i这个整数选了几次,选的次数可以是0, 1, 2, …, r次,那么状态转移方程为f[i][j][t] = sum(f[i-1][j-i*r][t-r])。
复杂度分析:枚举i、j、r需要三重循环,而枚举i出现的次数还需要一重循环,本题的数据规模是100,O(n4)的复杂度就有点危险了,考虑使用背包问题类似的优化手段。
考虑f[2][8][4]这个状态转移的过程
2这个数字可以出现0到4次
f[2][8][4] = f[1][8][4] + f[1][6][3] + f[1][4][2] + f[1][2][1] + f[1][0][0]
再来看f[2][6][3]状态的转移过程
f[2][6][3] = f[1][6][3] + f[1][4][2] + f[1][2][1] + f[1][0][0]
显然,f[2][8][4] = f[2][6][3] + f[1][8][4]
根据上面的例子我们可以得到优化后的状态转移方程:f[i][j][t] = f[i][j-i][t-1] + f[i-1][j][t]。这样一来时间复杂度降到了立方级别,106的计算次数是完全可以接受的。由于每个状态只用到了左边以及上一层相同的状态,所以可以使用滚动数组实现,去掉第一维状态。
#include
using namespace std;
const int N = 105, MOD = 1e9 + 7;
int n,k;
int f[N][N];
int main() {
cin>>n>>k;
f[0][0] = 1;
for(int i = 1;i <= n;i++) {
for(int j = i;j <= n;j++) {
for(int t = 1;t <= k;t++) {
f[j][t] = (f[j][t] + f[j - i][t - 1]) % MOD;
}
}
}
cout<<f[n][k]<<endl;
return 0;
}
定义美丽数列A: 1. 数列中相邻的数越是靠内相对大小加一,a[2]=a[1]+1,a[n-2]=a[n-1]+1… 2. 距离边缘距离相等的
数的大小相等:a[0] = a[n-1],a[1] = a[n-2]… 通过修改最小的数字使得给定数列变成美丽数列。 修改后的值必须仍是正
整数。
输入描述:
第一行输入整数n。(1<=n<=1000)表示数列的大小。
第二行输入n个整数。
输出描述:
输出最小修改。
输入样例:
3
1 1 1
输出样例:
1
比赛时候想的是DFS和DP的思路,后面没时间就没作答了。比赛之后又看了下,分析出题目的隐藏条件,就很容易解决了。
首先,明确题意,题目表述不太清楚,我理解为数列有奇数个元素时,像1 2 3 2 1,除了中间数只有一个,其他数都是由内而外逐渐减去一的;数列有偶数个元素时,像1 2 2 1这种中间两个数是相等的,其他数由内而外减去一。然后给定若干个数列,判断要多少次操作才能将给定的数列转化为美丽数列。(PS:这么简单的表述,题目表述不清像是直接机器从英文题面翻译过来的。)
解题的关键在于一个性质,表面看是要修改很多元素才能变为美丽数列,实际只要确定了中间的数字,其他数字也就确定了。举个例子:
1 4 3 2 5
设中间的元素3改变为t,那么最终的数列就是t - 2,t - 1, t,t - 1,t - 2,来看下每个数字的改变量,分别是t - 3, t - 5, t - 3 - 1, t - 3, t - 7,现在希望改变的元素数量最少,也就是希望改变量数组中0的数量最多,而t是变量,意味着只要让改变量数组中出现最多的元素是0,那么就可以使得改变的元素数量最少,最后发现t - 3出现的次数最多,是3次,所以有三个位置元素不用改变,因此t取3最合适。
如果数列有偶数个元素呢,那么只需要设中间两个数改变为t即可。
具体在实现时,并不需要设变量t,只需要对最中间的数保持不变,由内而外每个数字一次加上1,2,3,…即可,比如1 4 3 2 5,处理后得到3 5 3 3 7,然后出现最多的数字就是3,所以最中间的数字取3,最后不等于3的数有2个,就是需要改变的数量。所以本题相当于给原数组做了下归一化之后求个哈希。
#include
#include
#include
using namespace std;
const int N = 1005;
int n,a[N];
unordered_map<int,int> m;
int main() {
cin>>n;
for(int i = 0;i < n;i++) cin>>a[i];
int t = (n - 1) / 2;
if(n & 1) {
int k = 1;
while(t - k >= 0) {
a[t-k] += k;
a[t+k] += k;
k++;
}
}
else {
int k = 1;
while(t - k >= 0) {
a[t-k] += k;
a[t+k+1] += k;
k++;
}
}
for(int i = 0;i < n;i++) m[a[i]]++;
int s = 0;
for(auto x : m) {
s = max(s,x.second);
}
cout<<n - s<<endl;
return 0;
}
}