牛客IOI周赛16-普及组
求导
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
输入描述:
给出一个数 n
输出描述:
输出求 xn求 n - 1 次导后 x 前的系数。(答案对 109+7 取余)
示例1
输入
复制
5
输出
复制
120
备注:
对于50% 的数据满足n≤15
对于%100% 的数据满足 n≤10 5
题解:
第一次求导,系数为n
第二次求导,系数为n*(n-1)
。。。
第n-1次求导,系数为n*(n-1)…*2
不就是阶乘吗?
直接暴力走起
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn = 1e5 +5;
int main(){
ll n;
cin>>n;
ll base=1;
for(int i=1;i<=n;i++)
{
base=base*i%mod;
}
cout<<base<<endl;
return 0;
}
猜数
题意:
n个数改动前之和是大于等于m,现在给出改动后,问最少改动几个数字?
输入
2 3
1 1
输出
1
题解:
方法一 贪心
我们从最小的数字开始改,同时记录每个数字的次数
有两种情况要记录个数:第一个是把还未修改的最小数改成最大数(9)后总值还是没m大,那这个数一定要改
另一个是改完当前数就正好满足条件,那也记入答案,结束
因为数的范围都在0到9,所以可以用桶来存每个数,这样操作时同时多个操作
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 4;
int n,m,a[maxn];
int tong[12];
int main() {
cin>>n>>m;
int sum = 0,num,ans,tot=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
tong[9 - a[i]]++;
sum += a[i];
}
for(int i=9;i>=0;i--)
{
if(sum >= m) break;
ans = tong[i] * i;
if(sum + ans < m)
{
sum += ans;
tot += tong[i];
}
else
{
num = ((double)(m - sum)/(double)i+0.9);
tot += num;
sum += num * i;
}
}
cout << tot << endl;
return 0;
}
方法二 暴力
貌似直接暴力就可以过
排个序,然后从小将每个数补满(补到9),如果补后大于m,输出当前数的序号,如果没补满继续
答题卡
题意:
题解:
dp做法
我们要先知道所选格子的横列不能冲突,因为每个题只能有一个答案。。。
如果我们选中第一行第一列的格子,反转后还是本身,因为行列不能再选,所以剩下就成了(n-1) * (n-1)的问题
如果选的是第一行第二列,对称位置是第二行第一列,也就是第一二行和第一二列都不能再选了,就成了(n-2) * (n-2)的问题
第三行到第n行与第二种情况一样,都变成了(n-2) * (n-2)的问题
汇总一起:
第一种情况为dp[i-1],出现一次
第二种情况为dp[i-2],出现了n-1次
dp[n]=dp[n-1]+(n-1)*dp[n-2]
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+3;
ll dp[maxn];
int main(){
dp[0] = 1;
dp[1] = 1;
dp[2] = 2;
dp[3] = 4;
ll n;
cin>>n;
for(int i = 4 ; i <= n ;++i)dp[i] = (dp[i-1] + (i-1)*dp[i-2])%mod;
cout<<dp[n]<<endl;
}