题目:1050. 鸣人的影分身
题解:相当于有m个苹果n个盘子,问有多少种分法。盘子可以为空,但m个苹果要分完
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=(1<<20)+10;
int m,n;
LL f[15][15];
int main() {
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&m,&n);
memset(f,0,sizeof f);
f[0][0]=1;
for(int i=0;i<=m;i++){
for(int j=1;j<=n;j++){
f[i][j]=f[i][j-1];
if(i>=j) f[i][j]+=f[i-j][j];
}
}
printf("%lld",f[m][n]);
}
return 0;
}
题目:1047. 糖果
解法一:求如何到f[i][j]
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<double,double>PII;
const int N=(1<<20)+10;
const int mod=1000000009;
int f[110][110];//f[i][j],i为对第i件物品进行操作,j为当前前i件糖果总数的和模上m
int main(){
int n,m;
cin>>n>>m;
int a[110];
for(int i=1;i<=n;i++){
cin>>a[i];
}
memset(f,-0x3f,sizeof f);//将非法状态置为无穷小
f[0][0]=0;//还没选时,容量为0是合法状态,置为0即可
for(int i=1;i<=n;i++){//从第i件物品开始
for(int j=0;j<m;j++){//当前i件物品中选的糖果总数%m为j时
f[i][j]=f[i-1][j];//不选第i件物品
f[i][j]=max(f[i][j],f[i-1][((j-a[i])%m+m)%m]+a[i]);//选第i件物品后看其值能否比不选的大
}
}
cout<<f[n][0];
return 0;
}
解法二:看f[i][j]可以到哪
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=(1<<20)+10;
int n,k;
LL f[110][110];
int main() {
cin>>n>>k;
int x;
memset(f,-1,sizeof f);
f[0][0]=0;
for(int i=1;i<=n;i++){
scanf("%d",&x);
for(int j=0;j<k;j++){
if(f[i-1][j]!=-1){
f[i][j]=max(f[i][j],f[i-1][j]);
f[i][(j+x)%k]=max(f[i][(j+x)%k],f[i-1][j]+x);
}
}
}
printf("%lld",f[n][0]);
return 0;
}
题目:1222. 密码脱落
题解:区间dp,因为区间再遍历就不能满足回文串的定义,所以这里不能在区间里面再遍历一遍。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=(1<<20)+10;
int f[1010][1010];
int main() {
char s[1010];
scanf("%s",s+1);
int lens=strlen(s+1);
memset(f,0x3f,sizeof f);
for(int len=1;len<=lens;len++){
for(int i=lens-len+1;i>=1;i--){
int j=i+len-1;
if(len==1){
f[i][j]=0;
}else{
if(s[i]==s[j]){
if(i==j-1){
f[i][j]=0;
}else{
f[i][j]=min(f[i][j],f[i+1][j-1]);
}
}else{
f[i][j]=min(f[i][j],f[i+1][j]+1);
f[i][j]=min(f[i][j],f[i][j-1]+1);
}
}
}
}
printf("%d",f[1][lens]);
return 0;
}
题目:1070. 括号配对
题解:区间dp,这里需要对区间进行遍历,因为子区间的最优解组合可以替换大区间的最优解
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=(1<<20)+10;
int f[110][110];
int main() {
char s[110];
scanf("%s",s+1);
int lens=strlen(s+1);
memset(f,0x3f,sizeof f);
for(int len=1;len<=lens;len++){
for(int i=1;i+len-1<=lens;i++){
int j=i+len-1;
if(len==1){
f[i][j]=1;
}else{
if(s[i]=='('&&s[j]==')'||s[i]=='['&&s[j]==']'){
if(i==j-1){
f[i][j]=0;
}else{
f[i][j]=min(f[i][j],f[i+1][j-1]);
}
}
for(int k=i;k<j;k++){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
}
}
}
printf("%d",f[1][lens]);
return 0;
}
题目:1220. 生命之树
题目:树形dp
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=1e5+10;
int a[N];
LL dp[N];
vector<int > g[N];
int n;
void dfs(int u,int fa){
dp[u]=a[u];
for(int i=0;i<g[u].size();i++){
int t=g[u][i];
if(t==fa) continue;
dfs(t,u);
dp[u]+=max(0ll,dp[t]);
}
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int x,y;
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1,-1);
LL res=dp[1];//注意,里面会有负数,所以最后不要默认为0是最小的。
for(int i=1;i<=n;i++){
res=max(res,dp[i]);
}
printf("%lld",res);
return 0;
}
题目:1303. 斐波那契前 n 项和
题解:矩阵乘法+快速幂
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=1e5+10;
LL A[][3]={
{2,0,-1},{1,0,0},{0,1,0}
};
LL X[3]={4,2,1};
LL n,m;
void mult1(LL X[],LL Y[][3]){
LL t[3]={0};
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
t[i]=(t[i]+Y[i][j]*X[j]%m)%m;
}
}
for(int i=0;i<3;i++)
X[i]=t[i];
}
void mult2(LL X[][3],LL Y[][3]){
LL t[3][3]={0};
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
for(int k=0;k<3;k++){
t[i][j]=(t[i][j]+X[i][k]*Y[k][j]%m)%m;
}
}
}
memcpy(X,t,sizeof t);
}
int main() {
scanf("%lld%lld",&n,&m);
if(n==1){
cout<<1%m;
}else if(n==2){
cout<<2%m;
}else if(n==3){
cout<<4%m;
}else{
n-=3;
while(n){
if(n&1) mult1(X,A);
mult2(A,A);
n>>=1;
}
printf("%lld",(X[0]%m+m)%m);//像这种一定为正数的最好在来一次取余确保为正数
}
return 0;
}
题目:1226. 包子凑数
题解:数论+完全背包
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=1e5+10;
int n;
int a[110];
int gcd(int x,int y){
return y?gcd(y,x%y):x;
}
int main() {
cin>>n;
int res=0;
for(int i=1;i<=n;i++){
cin>>a[i];
res=gcd(res,a[i]);
}
if(res!=1){
puts("INF");
}else{
bool f[10010];
memset(f,0,sizeof f);
f[0]=1;
for(int i=1;i<=n;i++){
for(int j=a[i];j<=10000;j++){
f[j]=f[j]||f[j-a[i]];
}
}
int ans=0;
for(int i=1;i<=10000;i++){
if(!f[i]) ans++;
}
cout<<ans;
}
return 0;
}
题目:1078. 旅游规划
题解:树形dp
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=2e5+10;
vector<int > g[N];
int d1[N],d2[N],son[N],up[N];
int n;
int maxd=0,maxu;
void dfs(int u,int fa,int bc){
for(int i=0;i<g[u].size();i++){
int t=g[u][i];
if(t==fa) continue;
dfs(t,u,bc+1);
int distance=d1[t]+1;
if(distance>d1[u]){
d2[u]=d1[u],d1[u]=distance;
son[u]=t;
}else if(distance>d2[u]){
d2[u]=distance;
}
}
maxd=max(maxd,d1[u]+d2[u]);
}
void dfs2(int u,int fa){
for(int i=0;i<g[u].size();i++){
int t=g[u][i];
if(t==fa) continue;
up[t]=up[u]+1;
if(son[u]==t){
up[t]=max(up[t],d2[u]+1);
}else{
up[t]=max(up[t],d1[u]+1);
}
dfs2(t,u);
}
}
int main() {
scanf("%d",&n);
int x,y;
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(0,-1,1);
dfs2(0,-1);
//cout<<maxd<<endl;
for(int i=0;i<n;i++){
int d[3]={d1[i],d2[i],up[i]};
sort(d,d+3);
if(d[1]+d[2]==maxd){
printf("%d\n",i);
}
}
return 0;
}