A-求导
Question
求在
次导后
前的系数。
Solution
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll maxn = 1e6 + 5;
const int N = 1e5 +5;
ll f[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
ll n;cin>>n;
ll base=1;
for(int i=1;i<=n;i++){
base=base*i%mod;
f[i]=base;
}
cout<<f[n]<<'\n';
return 0;
}B-猜数
Question
纸上写了 个数字,牛牛在之前改动了几个数字,他忘了他具体改了些数字了。
但是他记得动之前这些数字的和是 的,求他最少改动几个数字。
注意:这些数字在改之前和改之后均在 ,且为整数。
Solution
贪心,优先从数字最小的开始改,记入每个数字的次数。
- 若没改过的最小数字全改还没有
则全改,记入该数字的个数。
- 若改完当前数字一定可以结束,求最小改当前数字多少个,记入答案。
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll maxn = 1e6 + 5;
const int N = 1e6 + 5;
ll a[N],cnt[10];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
ll n,m;cin>>n>>m;
ll sum=0,ans=0;
for(int i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
cnt[a[i]]++;
}
ll ma=0,idx=0;
while(sum<m){
ma=(9-idx)*cnt[idx];
if(sum+ma<m){
sum+=ma;
ans+=cnt[idx];
idx++;
}else{
int base=9-idx;
int t=(m-sum+base-1)/base;
sum+=t*base;
ans+=t;
}
}
cout<<ans<<'\n';
return 0;
}C-答题卡
Question
求一个的矩阵主对角线对称,且每行每列只有一个为
其余均为
的方案数。
Solution
DP,我们画图,发现每次扩一行一列的时候,我们可以把新的看做老图的左上角加一个1(原来的
变为
),剩下的格子
个格子由于不在
所以选中他的同时,必须要选中他对称的格子的位置,那样的话还剩
个格子,我们把选中的那一行一列划掉,剩下的拼在一起就构成了一个
的图,这样的拿法有
个。
故得到DP关系式:
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll maxn = 1e6 + 5;
const int N = 1e5 + 5;
ll f[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;cin>>n;
f[1]=1;f[2]=2;f[3]=4;
int base=2;
for(int i=4;i<=n;i++){
f[i]=(f[i-1]+(i-1)*f[i-2]%mod)%mod;
}
cout<<f[n]<<'\n';
return 0;
}D-杀树
Question
给出一棵节点数为 的树,删去一个点
的代价为
,一条链的长度定义为路径上点的个数。
一棵树死了,满足不存在一条长度 的链,牛牛希望用最少代价杀死这棵树。
Solution
树形背包
设表示第
个结点链长不超过
的最小花费,令
表示删掉第
个结点所需要的最小花费。
对于不删这个节点而言,有两种情况:
- 该节点子树两边的最长链+该节点
- 该节点子树最长链+该节点
(该节点为叶子)
两种情况子树的一边取,另一边就只能取
想了很久还是没能想通为什么可以这么转移以及数组在这里的含义
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll maxn = 1e6 + 5;
const int N = 5e3 + 5;
int n,l,a[N],f[N][N],dp[N][N];
vector<int> G[N];
void dfs(int x,int fa){
memset(f[x],INF,sizeof(f[x]));
f[x][0]=a[x];
f[x][1]=0;
for(auto c:G[x]){
if(c==fa) continue;
dfs(c,x);
f[x][0]+=f[c][l-1];
for(int i=1;i<l;i++){
f[x][i]=min(f[x][i]+f[c][min(l-i-1,i-1)],f[c][i-1]+dp[x][i]);
dp[x][i]+=f[c][min(l-i-1,i-1)];
}
}
for(int i=1;i<l;i++) f[x][i]=min(f[x][i],f[x][i-1]);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>l;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<n;i++){
int u,v;cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
cout<<f[1][l-1]<<'\n';
return 0;
}
京公网安备 11010502036488号