[CSP冲刺班]CSP-J2011模拟赛#3
诸题目君
T1-面试
题意:有n人参加面试,每人4轮,每轮有4个等级ABCD,如一轮及以上是D或两轮及以上是C,淘汰输出"failed",如三轮及以上是A,输出"sp offer",否则输出"offer".
思路:签到题。声明变量分别记录下A 、C 、D 的个数。具体见代码(太水了,dalao请自行跳过)
#include<bits/stdc++.h>
using namespace std;
int t,c,a,d;
char s[5];
int main(){
freopen("interview.in","r",stdin);
freopen("interview.out","w"stdout);
cin>>t;
for(int i=1;i<=t;i++){
cin>>s;
c=0;a=0;d=0;
for(int j=0;j<4;j++){
if(s[j]=='D')d=1;
if(s[j]=='C'){c++;}
if(s[j]=='A'){a++;}
}
if(c>=2||d==1)cout<<"failed"<<endl;
else if(a>=3)cout<<"sp offer"<<endl;
else cout<<"offer"<<endl;
}
return 0;
}
天啊!如此简单的签到题,本蒟蒻只提了0pts!所以……
反思:你调试可以,但是!一定一定要删除调试代码!!!做题一定要细心,完事了更一定要认真检查,这种致命的低级错误绝对不能犯!!!
T2-Excel计数法
题意:给你一个数n,输出它在Excel中列的字母序号(如:6->F,27->AA以此类推)。
思路:进制转换。把他想成26进制,再转换计算。具体见代码(老简单了)
#include<bits/stdc++.h>
using namespace stdl
string zm="ABCDEFGHIJKLMNOPQRSTUVWXYZ",s;
long long n;
int main(){
cin>>n;
for(;n>0;){
n--;
s=all[n%26]+s;
n=(n-n%26)/26;
}
cout<<s<<endl;
}
反思:一开始我一脸茫然,打了个暴力计算每一个字母位,错了好多次,差点崩溃。到后来才想到把它打成进制转换,所以,做题(尤其考试),必须冷静思考!
T3-纸牌游戏
题意:n个人玩牌,每个人从min(剩余人数-1,a[i])个人中拿走一张牌,无牌者淘汰。问最后最少剩下多少人。
思路:贪心。在现存n个人的情况下, 对于第 i个人,如果a[i]<n−1 ,那么 第i个人必然会被淘汰出局,反之则永远不会被淘汰出局。
上代码:
#include<bits/stdc++.h>
using namespace std;
long long n,a[100100]
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i]
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
if(a[i]>=n-i){
cout<<n-i+1<<endl;
break;
}
}
return 0;
}
反思:原本我想不到其他方法,打了个暴力也没有写贪心。事实上,如果一道题想不出其他解法,除了拿部分分,观察数据范围,如果适合贪心,就试试。
T4-涨薪
题意:公司有n个员工,工资分别为a[1],a[2]…a[n]。每年有x个员工绩效A,工资3倍;有y个员工绩效B,工资2倍;其余C,工资不变。如果连续2年C,开除。问 m 年后公司需要发工资总和多少。
思路:贪心(这次题出的真阳间……这么多贪心)。a[1]——a[n],sort排序,从大到小分配从A到C的绩效,最后一个快速幂求解。具体见代码。
#include<bits/stdc++.h>
using namespace std;
#define 1000000007 mod
long long kuaisumi(long long k){
long long p=m,ans=1;
while(p){
if(p&1)ans=(ans*k)%mod;
k=(k*k)%mod;
p>>=1;
}
return ans%mod;
}
bool cmp(int a,int b){return a>b;}
int main(){
cin>>n>>m>>x>>y;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n,cmp);
for(int i=1;i<=x;i++)sum+=((a[i]*kuaisumi(3)%mod)%mod);
for(int i=x+1;i<=x+y;i++)sum+=((a[i]*kuaisumi(2)%mod)%mod);
cout<<sum%mod<<endl;
return 0;
}
反思:绝对不能在考试中偷懒,该优化的不优化,该剪枝的不剪枝,还想考满分?!想桃子(pich)!
T5-富有数
题意:n个数组成的序列,其中每一位都是6或8的数叫富有数,问这个序列中所有是富有序列的子序列的长度和。
思路:dp动规(把脑子倒空都想不到)。先去掉非富有数,再记录富有数个数,设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示前
i
i
i 种富有数里面选
j
j
j 个的方案数。
状态转移方程(参照君哥写一个):
-
不 用 第 i 种 , d p [ i ] [ j ] = d p [ i − 1 ] [ j ] d p [ i ] [ j ] = d p [ i − 1 ] [ j ] ; 不用第 i 种,dp[i][j]=dp[i−1][j]dp[i][j]=dp[i−1][j]; 不用第i种,dp[i][j]=dp[i−1][j]dp[i][j]=dp[i−1][j];
-
用 第 i 种 , d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] ∗ t i d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] ∗ t i ; 用第 i 种,dp[i][j]=dp[i−1][j−1]∗tidp[i][j]=dp[i−1][j−1]∗ti; 用第i种,dp[i][j]=dp[i−1][j−1]∗tidp[i][j]=dp[i−1][j−1]∗ti;
-
d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i − 1 ] [ j − 1 ] ∗ t i dp[i][j]=dp[i−1][j]+dp[i−1][j−1]∗ti dp[i][j]=dp[i−1][j]+dp[i−1][j−1]∗ti
MAP!!!
#include<bits/stdc++.h>
#include <map>
using namespace std;
const int maxn = 1e6+10;
typedef long long LL;
LL a[maxn];
int n;
// map<key_type, value_type> name; 键是不能重复的,值可以重复
map<long long, int> mp; // 定义一个键为long long类型,值为 int类型的map容器
map<long long, bool> v1;
map<string, int> v2;
map<pair<int, int>, vector<int>> v3; // 键必须要稳定状态的数据类型或者容器,不可修改
void count()
{
for(int i=1; i<=n; i++) { // 键是富有数这个数字,值是这个富有数的个数
mp[a[i]]++; // 修改也是log的
}
}
int main()
{
scanf("%d", &n);
for(int i=1; i<=n; ++i)
scanf("%lld", &a[i]);
count();
printf("%d\n", mp[a[1]]); // mp[a[i]] 表示 a[i]为键对应的值 ,每次查找都是log(n)的
// 输出所有的a[i]与其对应的个数,遍历所有的键
map<long long, int>::iterator i; // 定义一个名字为 i 的迭代器
for(i=mp.begin(); i!=mp.end(); ++i) { // 默认按照键升序来排序
printf("%lld %d\n", i->first, i->second); / i表示一个键值对的指针
}
return 0;
}
最后提醒
- 比赛开数组的时候一定要计算使用的内存
- 认真的研究每档部分分,在你想的满分做法不能保证是正解时,一定要写分段。 分段保平安!!!
- map和离散化的代码要多看看,非常实用的知识点!!!
- dp 设计的状态空间不够用,要想一想能不能滚动数组