题目1
题目链接:Cut Ribbon - CodeForces 189A - Virtual Judge,
思路:二进制优化背包问题,二进制拆分,然后跑01背包即可
代码如下:
#include <bits/stdc++.h>
using i64 = long long;
using namespace std;
const int mod = 1e9 + 7;
const int MAXN = 100005;
void solve() {
int n;
cin>>n;
vector<int>a(3);
for(int i=0; i<3; i++)cin>>a[i];
vector<int>ve[3];
for(int i=0; i<3; i++){
int maxnum=n/a[i];
int j=0;
for( j=1; j<=maxnum; j*=2){
ve[i].push_back(j);
}
maxnum=maxnum-j;
if(maxnum>0)ve[i].push_back(maxnum);
}
vector<int>f(n+1,-MAXN);
f[0]=0;
for(int i=0; i<3; i++){
for(auto v:ve[i]){
for(int j=n; j>=a[i]*v; j--){
f[j]=max(f[j],f[j-a[i]*v]+v);
}
}
}
cout<<f[n]<<endl;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
solve();
return 0;
}
题目2
题目链接:Marvolo Gaunt's Ring - CodeForces 855B - Virtual Judge
思路:我们考虑那么一个状态dp[i][j]表示第i个价格,在前j个物品的最大价值。所以答案为dp[3][n]
代码如下:
#include <bits/stdc++.h>
using i64 = long long;
using namespace std;
const int mod = 1e9 + 7;
const i64 INF =9*1e18;
void solve() {
int n;
cin>>n;
vector<i64>b(3),a(n+1);
for(int i=0; i<3; i++)cin>>b[i];
for(int i=0; i<n; i++)cin>>a[i];
vector<vector<i64>>f(4,vector<i64>(n+1,0));
i64 ans=0;
for(int i=0; i<3; i++){
i64 maxnum=-INF;
for(int j=0; j<n; j++){
f[i+1][j]=max(f[i][j]+a[j]*b[i],maxnum);
maxnum=f[i+1][j];
}
ans=maxnum;
}
cout<<ans<<endl;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
solve();
return 0;
}
题目3
题目链接:https://vjudge.net/problem/CodeForces-366C
思路:
我们考虑a/b=k转化为a-k*b=0;因此我们求出a-k*b的最大价值和即可
代码如下:
#include <bits/stdc++.h>
using i64 = long long;
using namespace std;
const int mod = 1e9 + 7;
const i64 INF =9*1e18;
void solve() {
int n,k;
cin>>n>>k;
vector<int>a(n),b(n);
vector<vector<int>>dp(101,vector<int>(20010,-1));
dp[0][10000]=0;
for(int i=0; i<n; i++){
cin>>a[i];
}for(int i=0; i<n; i++)cin>>b[i];
for(int i=1; i<=n;i++){
for(int j=0; j<=20000; j++){
if(dp[i-1][j]==-1)continue;
int y=j+a[i-1]-b[i-1]*k;
dp[i][j]=max(dp[i][j],dp[i-1][j]);
if(y>=0 && y<=20000){
dp[i][y]=max(dp[i][y],dp[i-1][y]);
dp[i][y]=max(dp[i][y],dp[i-1][j]+a[i-1]);
}
}
}
cout<<((dp[n][10000]==0)?(-1):(dp[n][10000]))<<endl;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
solve();
return 0;
}
题目4
题目链接:https://vjudge.net/problem/CodeForces-788C
思路:我们考虑题目三的转化,s1+s2+s3=3*n,看出s1+s2-2*n+s3-n=0,即s1+s2-n=x;x+s3-n=n;
考虑出递推公式后我们便很快的做出来,我们考虑BFS,求出每个值的第一次出现;
代码如下:
#include <bits/stdc++.h>
const int N = 1000;
using namespace std;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, k;
std::cin >> n >> k;
std::vector<int> a(k);
for (int i = 0; i < k; ++i) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
a.erase(std::unique(a.begin(), a.end()), a.end());
if (n < a[0] || n > a.back()) {
std::cout << -1 << "\n";
return 0;
}
std::vector<int> dis(N + 1, -1);
std::queue<int> que;
k=a.size();
for (int i = 0; i < k; ++i) {
if (a[i] == n) {
std::cout << 1 << "\n";
return 0;
}
dis[a[i]] = 1;
que.push(a[i]);
}
while (!que.empty()) {
int u = que.front();
que.pop();
for (auto x : a) {
int v = u + x - n;
if (0 <= v && v <= N && dis[v] == -1) {
dis[v] = dis[u] + 1;
que.push(v);
}
}
}
cout << dis[n] << "\n";
return 0;
}
题目5
题目链接:https://vjudge.net/problem/CodeForces-118D
思路:为了区分n1以及n2,我们考虑dp[n1][n2][2]代表,i个步兵,j个骑兵,结尾为01(步兵骑兵)的方案数;
转移方程为:dp[i][j][1]+=dp[i][j-k][1];
代码如下:
#include <bits/stdc++.h>
using i64 = long long;
using namespace std;
const int mod = 1e8;
const i64 INF =9*1e18;
int dp1[110][110][2];
void solve() {
int n1,n2,k1,k2;
cin>>n1>>n2>>k1>>k2;
dp1[0][0][0]=dp1[0][0][1]=1;
for(int i=0; i<=n1; i++){
for(int j=0; j<=n2; j++){
for(int k=1; k<=k1 && k<=i; k++){
dp1[i][j][0]+=dp1[i-k][j][1];
dp1[i][j][0]%=mod;
}
for(int k=1; k<=k2 && k<=j; k++){
dp1[i][j][1]+=dp1[i][j-k][0];
dp1[i][j][1]%=mod;
}
}
}
int ans=0;
ans=(dp1[n1][n2][0]+dp1[n1][n2][1])%mod;
cout<<ans<<endl;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
solve();
return 0;
}
题目6
题目链接:https://vjudge.net/problem/CodeForces-922E
思路:这个实际上是贪心+dp,我们考虑击杀k个恶魔,法力值剩余最大,因为法力值上限只和击杀恶魔数量有关。
代码如下:
#include <bits/stdc++.h>
using i64 = long long;
using namespace std;
const int mod = 1e8;
const i64 INF =9*1e18;
pair<i64,i64> dp[1005][10005];
void solve() {
int n,W,B,X;
cin>>n>>W>>B>>X;
vector<i64>c(n+1);
i64 sum=0;
for(int i=1; i<=n; i++){
cin>>c[i];
sum+=c[i];
}
vector<i64>cost(n+1);
for(int i=1; i<=n; i++)cin>>cost[i];
memset(dp,-0x3f,sizeof dp);
dp[0][0]={W,W};
for(int i=1; i<=n; i++){
for(i64 j=0; j<=sum; j++)
dp[i-1][j].first=min(dp[i-1][j].first+X,dp[i-1][j].second);
for(i64 v=0; v<=c[i]; v++){
for(i64 j=0; j<=sum; j++){
//cout<<i<<' '<<j<<' '<<dp[i][j].first<<' '<<dp[i][j].second<<endl;
if(dp[i][j].first<dp[i-1][j].first){
dp[i][j]=dp[i-1][j];
}else if(dp[i][j].second<dp[i-1][j].second){
dp[i][j]=dp[i-1][j];
}
if(j>=v){
if(dp[i-1][j-v].first-cost[i]*v>=0 && dp[i][j].first<dp[i-1][j-v].first-cost[i]*v){
dp[i][j].first=dp[i-1][j-v].first-cost[i]*v;
dp[i][j].second=dp[i-1][j-v].second+B*v;
}
}
//cout<<i<<' '<<j<<' '<<dp[i][j].first<<' '<<dp[i][j].second<<endl;
}
}
}
for(i64 i=sum; i>=0; i--){
if(dp[n][i].first>=0){
cout<<i<<endl;
return ;
}
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
solve();
return 0;
}