这周学了点数学的东西,Java的大数类,快速幂,矩阵快速幂,近几天做的codeforce不大好,思路想不出来,又陆陆续续做了几个dp背包的题,感觉dp的练习还是差的很远啊,而且dp有很大一部分是与别的知识点一块出题,遍往下学边刷题吧
luogu p2979
第一种情况不考虑大奶酪
第二种情况是考虑大奶酪;因为存在大奶酪会压扁下面的奶酪,所以T最大是T*5/4
P2979 [USACO10JAN]奶酪塔Cheese Towers - Cxs3 - 洛谷博客 (luogu.com.cn)
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define CHECK(x,y) (x>0&&x<=n&&y>0&&y<=m)
const int inf=0x3f3f3f3f;
const int mod=1e9;
const int N=1e6+5;
using namespace std;
int n,t,k,v[110],h[110];
ll f[2000];
int main(){
//freopen("in.txt","r",stdin);
scanf("%d%d%d",&n,&t,&k);
for(int i=1;i<=n;i++) scanf("%d%d",&v[i],&h[i]);
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++){
for(int j=h[i];j<=t*5/4;j++)
f[j]=max(f[j],f[j-h[i]]+v[i]);
}
ll ans=f[t];
for(int i=1;i<=n;i++)
if(h[i]>=k) ans=max(ans,f[(t-h[i])*5/4]+v[i]);
cout<<ans<<endl;
return 0;
}
luogu p5365
一个多重背包题,懵逼的我看了题解才知道。。。钱作为容量,方案数为价值;dp[j]代表钱为j时能获得的最大方案数,容量qb就等于所有的k[i]*c[i]之和;然后就是多重背包模板了,但是我用二进制拆分的模板却不对,用普通的反而过了。。。
[洛谷]P5365 [SNOI2017]英雄联盟 (#背包dp)_A.pro的博客-CSDN博客
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define CHECK(x,y) (x>0&&x<=n&&y>0&&y<=m)
const int inf=0x3f3f3f3f;
const int mod=1e9;
const int N=1e6+5;
using namespace std;
ll n,m,k[1000001],c[1000001];
ll dp[1000001];
int qb;
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld%lld",&n,&m);
qb=0;
for(int i=1;i<=n;i++) scanf("%lld",&k[i]);
for(int i=1;i<=n;i++) scanf("%lld",&c[i]),qb+=k[i]*c[i];
dp[0]=1;
/*for(int i=1;i<=n;i++){
int num=min(k[i],qb/c[i]);
for(int k=1;num>0;k<<=1){
if(k>num) k=num;
num-=k;
for(int j=qb;j>=c[i]*k;j--)
dp[j]=max(dp[j],dp[j-c[i]*k]*k),cout<<dp[j]<<endl;;
}
}*/
for(int i=1;i<=n;i++)
for(int j=qb;j>=c[i];j--)
for(int p=1;p<=k[i]&&p*c[i]<=j;p++)
dp[j]=max(dp[j],dp[j-c[i]*p]*p);
int ans=0;
while(ans<=qb&&dp[ans]<m) ans++;
cout<<ans<<endl;
return 0;
}
luogu p1156
dp[j]代表高度为j时最长可存活的时间,把高度d看做是容量,如果dp[j]>=d了,直接输出a[i].t即可,如果不能逃出就把垃圾能吃就吃能活多长活多长
#include<bits/stdc++.h>
using namespace std;
struct rub{
int t,f,h;
}a[110];
bool cmp(rub a,rub b){
return a.t<b.t;
}
int main(){
//freopen("in.txt","r",stdin);
int d,g;
int dp[110];
scanf("%d%d",&d,&g);
memset(dp,0,sizeof(dp));
dp[0]=10;
for(int i=1;i<=g;i++)
scanf("%d%d%d",&a[i].t,&a[i].f,&a[i].h);
sort(a+1,a+g+1,cmp);
for(int i=1;i<=g;i++)
for(int j=d;j>=0;j--)
if(dp[j]>=a[i].t){
if(j+a[i].h>=d){
cout<<a[i].t<<endl;
return 0;
}
dp[j+a[i].h]=max(dp[j+a[i].h],dp[j]);
dp[j]+=a[i].f;//能吃就吃,此处修改dp[j]
//的值并不影响dp[j+a[i].h]的值
}
cout<<dp[0]<<endl;
return 0;
}
luogu p1282
dp[i][j]代表前i个多米诺骨牌上下差为j时最小的翻转次数,去掉绝对值差值是在-5000-5000之间,数组不能为负值,所以平移一下数组,最后找出差值最小的最小翻转次数,小于等于1000就输出(因为最多能翻1000次,小于等于1000就是最小值了)
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
int dp[1005][10005];
int main(){
//freopen("in.txt","r",stdin);
int n,a[1005],n1,n2;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&n1,&n2);
a[i]=n1-n2;
}
int m=5000;//差最大就是5000
memset(dp,inf,sizeof(dp));
dp[0][m]=0;
for(int i=1;i<=n;i++)
for(int j=-m;j<=m;j++)
//数组不能为负,所以数组平移一下
dp[i][j+m]=min(dp[i-1][j+m-a[i]],dp[i-1][j+m+a[i]]+1);
//前者代表不翻转,后者代表翻转
int minn=inf;
for(int i=0;i<=m;i++){
//对可能的差遍历
minn=min(dp[n][m+i],dp[n][m-i]);
if(minn<=1000){
cout<<minn<<endl;
break;
}
}
return 0;
}
hdu5392
求解多个数的最小公倍数,题意就没看懂Orz,看的题解并没有快速幂,主要是如何求多个数的最小公倍数
HDU-5392-Infoplane in Tina Town_娃娃酱斯密酱的博客-CSDN博客
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N=3e6+10;
const ll mod=3221225473;
int t,a[N],vis[N],num[N],n;
int main(){
//freopen("in.txt","r",stdin);
cin>>t;
while(t--){
scanf ("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf ("%d", &a[i]);
vis[i] = 0;
num[i] = 0;
}
for(int i=1;i<=n;i++){
if(!vis[i]){
int cnt=0;
int k=i;
while(!vis[k]){//求循环长度
vis[k]=1;
cnt++;
k=a[k];
}
for(int j=2;j*j<=cnt;j++){
int top=0;
if(!(cnt%j)){//求质因数
while(!(cnt%j)){
cnt/=j;
top++;
}
}
num[j]=max(num[j],top);//维护最高次幂的质因数
}
if(cnt>1){
num[cnt]=max(num[cnt],1);
}
}
}
ll res = 1;
for (int i = 2; i <= n; i++)
{
while (num[i]--)
{
res = res * i % mod;
}
}
cout << res << endl;
}
return 0;
}
luogu p2224
dp[j]表示A机器用时j,B机器的用时,挨个判断每个任务用哪种情况更好
(1条消息) 洛谷 P2224 [HNOI2001]产品加工 解题报告_weixin_30940783的博客-CSDN博客
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#define ll long long
const int inf=0x3f3f3f3f;
using namespace std;
int main(){
//freopen("in.txt","r",stdin);
int n,c[4],dp[30005],r=0;
scanf("%d",&n);
memset(dp,inf,sizeof(inf));
dp[0]=0;
for(int i=1;i<=n;i++){
scanf("%d%d%d",&c[0],&c[1],&c[2]);
r+=max(c[0],max(c[1],c[2]));
for(int j=r;j>=0;j--){
if(c[1])//这个任务用b机器做
dp[j]+=c[1];
else dp[j]=inf;
if(j>=c[0])//这个任务用a机器做
dp[j]=min(dp[j],dp[j-c[0]]);
if(j>=c[2])//这个任务a和b一起做
dp[j]=min(dp[j],dp[j-c[2]]+c[2]);
}
}
int ans=inf;
for(int i=0;i<=r;i++)
ans=min(ans,max(dp[i],i));//选A和B用时最长的,因为两台机器都做完才算做完
cout<<ans<<endl;
return 0;
}
codeforce B Update Files
思路好像是对的,但是老是想不出那个代码的算式要怎么写,还是代码能力太差了,如果没有k限制的话,copy数是2的n次方递增的,所以看看mul一直乘以2小于k的次数cnt,然后n再减去mul,剩余的除以k再加上cnt就是答案,还有就是不要忘了取余
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#define ll long long
const int inf=0x3f3f3f3f;
using namespace std;
int main(){
//freopen("in.txt","r",stdin);
ll t,n,k;
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&n,&k);
ll cnt=0,mul=1;
while(mul<k){
cnt++;
mul*=2;
}
if(mul<n)
cnt+=(n-mul)/k+(((n-mul)%k)!=0);
printf("%lld\n",cnt);
}
return 0;
}