分析
求阶乘,但是不能简单的递归,这样会TLE。需要记忆化递归,同时为防止数据爆掉,需要边乘边取余
ac代码
#include
using namespace std;
const int maxn=1e9+7;
long long n ,result;
long long fact(long long n){
if(n==0||n==1) return 1;//退出条件
long long dp[100001];
dp[1]=1;
for(int i=2;i<=n;i++)//记忆化
dp[i]=dp[i-1]*i%maxn;//计算阶乘
return dp[n];
}
int main(){
cin>>n;
if(n<0) cout<<0<<endl;
else{
cout<<fact(n)<<endl;
}
}
2.猜数
链接:猜数
来源:牛客网
题目描述
纸上写了 n 个数字,牛牛在之前改动了几个数字,他忘了他具体改了些数字了。
但是他记得动之前这些数字的和是 ≥ m \ge m ≥m 的,求他最少改动几个数字。
注意:这些数字在改之前和改之后均在 0 ~ 9 之间,且为整数。
输入描述:
第一行给出 n,m
第二行给出 n 个 0 ~ 9 的整数
输出描述:
输出最少改动了几个数字。(保证答案 \le n≤n)
示例
输入
2 3
1 1
输出
1
对于 50% 数据有 n ≤ 20 n\le 20 n≤20
对于 100% 数据有 n ≤ 1 0 6 n\le10^{6} n≤106
分析
把最小的数据变成9可以有最少的改动次数。输入时求和,之后从小到大排序,每次改动最小的数,并且更新和,不满足累加器+1,直到满足添加。
ac代码
#include
#include
using namespace std;
const int maxn=1e6+10;
long long sum=0;
int n,m,a[maxn],cnt=0;
int main(){
cin>>n>>m;
for(int i=0;i<n;i++){
cin>>a[i];
sum+=a[i];//求和
}
sort(a,a+n);//从小到大
for(int i=0;i<n;i++){
if(sum<m){
// cout<
sum+=(9-a[i]);
cnt++;
}
}
cout<<cnt<<endl;
}
3.累乘数字
链接:累乘数字
来源:牛客网
题目描述
我们知道将一个大于1的数乘以另一个大于1的数会使乘积大于任意一个乘数。
现在给出两个数字 n, d,你能否计算将n乘以d次100的结果。
输入描述:
多组输入
每组输入在一行中给出n, d, 1 ≤ n , d ≤ 100 1 \le n, d \le 100 1≤n,d≤100。
输出描述:
每组输入输出一行代表答案。
示例1
输入
5 1
11 1
85 2
输出
500
1100
850000
分析
字符读入,后面补2d个零。
ac代码
#include
#include
using namespace std;
string n;
int d;
int main(){
while(cin>>n>>d){//输入多组数据
for(int i=1;i<=d;i++)
n.append("00");//字符补0
cout<<n<<endl;
}
}
4.解锁专家
链接:解锁专家
来源:牛客网
文字锁是这样描述的,
对于给定的一个n,问存在多少正整数x满足:
1、x>0;
2、x二进制位的位数不超过n,例如5=101(2),它的二进制位的位数就是3;
3、x的二进制形式,不存在连续的两个二进制位上的数都是1。例如 3=11(2),则不满足条件,但是5=101(2) 则满足条件。
题目大意
给定二进制的位数n(n<=100),求出没有相邻的1,并且不为0的组合个数。
比如n=3,可以有001,010,101,100四种
分析
通过找规律,发现dp[i]=dp[i-1]+dp[i-2]+1
,打表
二进制位数n | 答案数dp[n] |
---|---|
1 | dp[1]=1 |
2 | dp[2]=2 |
3 | dp[3]=4 |
4 | dp[4]=7 |
5 | dp[5]=12 |
… | … |
i | dp[i-1]+dp[i-2]+1 |
ac代码
#include
using namespace std;
const int maxn=433494437;
int n;
int dp[200];//dp[i]表示i位二进制满足条件的个数
int main(){
dp[1]=1;
dp[2]=2;
for(int i=3;i<=100;i++)
dp[i]=(dp[i-2]+dp[i-1]+1)%maxn;
while(cin>>n){
cout<<dp[n]<<endl;
}
}
5.答题卡
链接:答题卡
来源:牛客网
牛牛即将要参加考试,他学会了填答题卡。
可惜他竖着的答题卡填成了横着的
好奇的他想知道对于 n 道题,每道题 n 个选项的答题卡 ( n * n 的矩阵 ),满足横答题卡和竖答题卡图形一致的方案数有多少种。
注:每道题只能选择一个选项,即 n * n 的矩阵中只能涂黑 n 个空。求横竖对称的方案数。
数据规模
链接:https://ac.nowcoder.com/acm/contest/5769/F
来源:牛客网
对于 50% 的数据有 n ≤ 10 n \leq 10 n≤10
对于 100% 的数据有 n ≤ 1 0 5 n\le 10^5 n≤105
分析
对于第一个位置,可以分为填或者不填两种情况。
如果填,则该行该列都不能填(该行不能填是因为每行只能填一个,对称的话,每列也只能填一个空),于是等价为剩下右下角的(i-1)阶方阵,dp[i-1]
如果不填第一个空,在第一行剩余(i-1)个位置找一个有(i-1)种可能,假设是(1,x),则对称点是(x,1),x行和x列不能再填,其余部分再拼接成(i-2)*(i-2)方阵。即(i-1)*dp[i-2]
于是状态转移
dp[i]=dp[i-1]+(i-1)*dp[i-2];//第1个空填了+第1个空没填
有问题代码,数据爆掉
ll test(ll n){
dp[1]=1;
dp[2]=2;
for(ll i=3;i<=n;i++)
dp[i]=dp[i-1]+(i-1)*dp[i-2];
return dp[n]%mod;
}
ll test(ll n){
dp[1]=1;
dp[2]=2;
for(ll i=3;i<=n;i++)
dp[i]=dp[i-1]%mod+(i-1)*dp[i-2]%mod;
return dp[n];
}
完全AC代码
记得每次计算都进行mod,中间过程需要,最后的结果也需要dp[i]=(dp[i-1]%mod+(i-1)%mod*dp[i-2]%mod)%mod;
#include
#include
using namespace std;
const int maxn=1e5+10;
const int mod=1e9+7;
typedef long long ll;
ll n, dp[maxn];
ll test(ll n){
dp[1]=1;
dp[2]=2;
for(ll i=3;i<=n;i++)
dp[i]=(dp[i-1]%mod+(i-1)%mod*dp[i-2]%mod)%mod;
return dp[n];
}
int main(){
cin>>n;
cout<<test(n)<<endl;
}
6.参赛
能不能组成参赛队,
题目大意
群里n个人,icpc赛事3个人一队,天梯赛事10个人一队,每个队配备一名教练,教练可以当多个参赛队的教练,队员可以参与不同的队伍,但是队员不能参与同一赛事的不同队伍。问能否成功组成队伍。
分析
错误思考,让队伍足够多,教练足够少,只要取余不为零说明可以组成。
错误代码
#include
#include
using namespace std;
int n;
int main(){
while(scanf("%d",&n)!=EOF){
if(n<=3) cout<<"No"<<endl;
else if(n>3&&n<=10){
if(n%3) cout<<"First"<<endl;
else cout<<"No"<<endl;
}
else{
if(n%3&&n%10) cout<<"All"<<endl;
else if(n%3&&n%10==0) cout<<"First"<<endl;
else if(n%3==0&&n%10) cout<<"Second"<<endl;
else cout<<"No"<<endl;
}
}
return 0;
}
正确思考
确实是贪心:让参赛队足够多,教练足够少但不为零。
分开独立完成,
对于icpc赛事,
如果对3取余不为0,并且参赛队个数大于等于教练数,则可以组队成功。如果对3取余为0,这个时候要看能不能拆开一支队伍,使得该队伍里面的人成为教练,这个时候要求队伍数≥教练数(队伍数-1≥3)才可以。
比如5个人,5/3==1……2,队伍数少于教练数,组不成队伍。
比如9个人,9%3==3,没有余数,也就是说没有教练,这个时候考虑,能不能拆开1只参赛队,变成2支队伍,3名教练,结果却发现教练数>队伍数,则不行。所以9个人组不成队伍。
再比如12个人,12%3= =4,也没有教练,考虑拆开一只参赛队,变成3支队伍,3个教练,队伍数≥教练数,这个时候可以组成icpc队伍。
对于天梯赛事,同理
如果对10取余不为0,并且参赛队个数大于等于教练数,则可以组队成功。
如果对10取余为0,这个时候要看能不能拆开一支队伍,使得该队伍里面的人成为教练,这个时候要求队伍数≥教练数才可以。
ac代码
#include
#include
using namespace std;
int n;
int main(){
while(scanf("%d",&n)!=EOF){
bool flag1=false,flag2=false;
//icpc赛事
int a=n/3,b=n%3;//分别是参赛队伍数和教练数
if(b!=0 &&a>=b) flag1=true;//教练不为0,参赛队≥教练
//教练为0,拆开一只队伍之后参赛队≥教练
else if(b==0&&a-1>=3) flag1=true;
else flag1=false;
//天梯赛事
int c=n/10,d=n%10;//分别是参赛队伍和教练数
if(d!=0 &&c>=d) flag2=true;
//教练为0,拆开一只队伍之后参赛队≥教练
else if(d==0&& c-1>=10) flag2=true;
else flag2=false;
if(flag1&&flag2) cout<<"All"<<endl;
else if(flag1) cout<<"First"<<endl;
else if(flag2) cout<<"Second"<<endl;
else cout<<"No"<<endl;
}
return 0;
}