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;
}