A、求导
题意
思路:
真的就是对 求导直到 x 的系数为1,求导
次后 x 的系数就是
,阶乘比较大,开ll算阶乘问题不大。
Code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
template <class T>
inline void read(T &res) {
char c; T flag = 1;
while ((c = getchar()) < '0' || c > '9')
if (c == '-')
flag = -1;
res = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
res = res * 10 + c - '0';
res *= flag;
}
ll n,ans=1;
int main() {
read(n);
for(ll i=2;i<=n;++i) ans=(ans*i)%1000000007;
printf("%lld\n",ans);
} B、猜数
题意:
题目描述
纸上写了 n 个数字,牛牛在之前改动了几个数字,他忘了他具体改了些数字了。
但是他记得动之前这些数字的和是 \ge m≥m 的,求他最少改动几个数字。
注意:这些数字在改之前和改之后均在 0 ~ 9 之间,且为整数。
输入描述:
第一行给出 n,m 第二行给出 n 个 0 ~ 9 的整数
输出描述:
输出最少改动了几个数字(保证答案 )
备注
对于 50% 数据有
对于 100% 数据有
思路:
一道思维题,我刚开始就是直接计算每个数字的贡献,就是并用m减去
,然后将贡献从大到小排序,统计将m减到小于等于0需要几个数字去贡献。但是现在想起来太蠢了。
之前思路的复杂度为 ,这个复杂度主要是排序带来了,而每个数使总和增加的贡献只能是0 ~ 9,也就是说记录可以贡献多少个
,然后遍历 9 ~ 1 用除法判断需要多少次贡献就可以了。
Code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
template <class T>
inline void read(T &res) {
char c; T flag = 1;
while ((c = getchar()) < '0' || c > '9')
if (c == '-')
flag = -1;
res = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
res = res * 10 + c - '0';
res *= flag;
}
int n,m,x,b[10],ans;
int main() {
read(n),read(m);
for(int i=1;i<=n;++i) {
read(x);
m-=x;
++b[9-x];
}
for(int i=9;i&&m>0;--i) if(m>i*b[i]) {
ans+=b[i];
m-=i*b[i];
}
else {
ans+=m/i+(m%i!=0);
printf("%d\n",ans);
return 0;
}
} C、求导
思路:
每行每列只能涂一个格子,判断这样涂的时候,对称矩阵的情况的种数。
打表找规律,前面是1,2,4,10,26。
得递推公式是 。
Code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
template <class T>
inline void read(T &res) {
char c; T flag = 1;
while ((c = getchar()) < '0' || c > '9')
if (c == '-')
flag = -1;
res = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
res = res * 10 + c - '0';
res *= flag;
}
ll n,a,b,c;
int main() {
read(n);
b=2,c=1;
for(int i=3;i<=n;++i) {
a=(b+c*(i-1))%1000000007;
c=b; b=a;
}
printf("%lld\n",a);
} D、杀树
题意:
题目描述
牛牛学习了树。
给出一棵节点数为 n 的树,删去一个点 i 的代价为 aia_iai,一条链的长度定义为路径上 点 的个数。一棵树死了,满足不存在一条长度 ≥l\geq l≥l 的链,牛牛希望用最少代价杀死这棵树。
输入描述:
第一行给出 n,l 第二行给出 n 个整数分别代表 aia_iai 接下来 n-1 行,每行给出 u,v 表示有一条 u 到 v 的边。
输出描述:
输出一个整数,表示最小的代价。
思路:
看了一下午还是。。。想不出来。
树状dp, 表示以 i 为根的子树,向下传 j 个长度的最小值,特别的dp[i][0]表示删除子树的根i。
1.首先,初始状态 表示去掉了自己,还要保证子树剩余的点满足题目意思。就将子树中
中的最小花费加上
给
。
2.保留点: ,便于下面更新
找最小值。
3. 。
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn=5e3+7;
template<class T>inline void read(T& res) {
char c; T flag = 1;
while ((c = getchar()) < '0' || c > '9')
if (c == '-')
flag = -1;
res = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
res = res * 10 + c - '0';
res *= flag;
}
int head[maxn],Next[maxn<<1],to[maxn<<1],tot;
void add(int u,int v) {
to[++tot]=v;
Next[tot]=head[u];
head[u]=tot;
}
int a[maxn],f[maxn][maxn],tmp[maxn],n,m;
void dfs(int u,int fa) {
f[u][0]=a[u];
for(int i=head[u];i;i=Next[i]) {
int v=to[i]; if(v==fa) continue;
dfs(v,u);
f[u][0]+=*min_element(f[v],f[v]+m);
for(int i=1; i<m; ++i)
tmp[i]=f[u][i],f[u][i]=INF;
for(int i=1; i<m;++i){
for(int j=0; j<m; ++j){
if(i+j<m)
f[u][max(i,j+1)]=min(f[u][max(i,j+1)],tmp[i]+f[v][j]);
else
break;
}
}
}
}
int main(){
read(n),read(m);
for(int i=1;i<=n;++i) read(a[i]);
for(int i=1;i<n;++i){
int u,v;
read(u),read(v);
add(u,v),add(v,u);
}
dfs(1,0);
printf("%d\n",*min_element(f[1],f[1]+m));
return 0;
} 
京公网安备 11010502036488号