题目链接:https://cn.vjudge.net/contest/243243#overview
A题:
一道完全背包题,由于都是1000的整数倍注意除1000省空间
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int dp[100005];
int value[11],interest[11];
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int t;
cin>>t;
int start,year;
while(t--)
{
cin>>start>>year;
int d;
cin>>d;
for(int i=1;i<=d;i++)
cin>>value[i]>>interest[i];
while(year--){
int s=start/1000;
memset(dp,0,sizeof dp);
for(int i=1;i<=d;i++){
for(int j=value[i]/1000;j<=s;j++)///区分和0-1背包的区别,0-1背包是逆向循环,完全背包是正向
dp[j]=max(dp[j],dp[j-value[i]/1000]+interest[i]);
}
start+=dp[s];///利息加本金
}
cout<<start<<endl;
}
return 0;
}
F题:
由于物品都是3的整数倍,可以想到化为3进制来做
把n化为3进制有三种情况
1、位数上为0不处理
2、位数上为1放在右边
3、位数上为2,由于每个物品只有一个,应在左边相应的位上加1使其满3进位
最后统计每边有几个1就应放几个物品。
举个栗子:左边是42,化为3进制为1120,加上1110后就变为了10000(右边),所以左边加3个物品(3,9,27),右边加一个(81)
AC code:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
ll f[20];
ll l,r;
ll Pow(ll n)
{
ll ans=1;
while(n--)
ans*=10;
return ans;
}
void div(ll n)
{
int pos=0;
while(n)
{
int t=n%3;
n/=3;
if(t==1)
r+=Pow(pos);
else if(t==2)
{
l+=Pow(pos);
n++;
}
pos++;
}
}
int getsum(ll n)
{
int res=0;
while(n)
{
if(n%10)
res++;
n/=10;
}
return res;
}
void print(ll n)
{
int pos=0;
while(n)
{
if(n%10)
printf(" %d",f[pos]);
n/=10;
pos++;
}
printf("\n");
}
int main()
{
f[0]=1;
for(int i=1;i<20;i++)
f[i]=3*f[i-1];
ll n;
while(~scanf("%lld",&n)){
l=r=0;
div(n);
printf("%d",getsum(l));
print(l);
printf("%d",getsum(r));
print(r);
}
return 0;
}
H题:
没什木说的,贴两个素数打表吧
1、
void set_prime()
{
cnt=0;
for(int i=2;i<=N;i++)
if(!vis[i]){
prime[cnt++]=i;
for(int j=1;i*j<=N;j++)
vis[i*j]=1;
}
}
2、
void set_prime()
{
cnt=0;
memset(vis,0,sizeof vis);
for(int i=2;i<=N;i++)
if(!vis[i]){
prime[cnt++]=i;
for(int j=i+i;j<=N;j+=i)///与第一种不同
vis[j]=1;
}
}
AC code:
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
int prime[1000001];
int vis[1000001]={0};
int cnt,m[1000001];
void set_prime()
{
cnt=0;
//memset(vis,0,sizeof vis);
for(int i=2;i<1000000;i++)
if(!vis[i]){
prime[cnt++]=i;
m[i]=cnt;
for(int j=i+i;j<1000000;j+=i)
vis[j]=1,m[j]=cnt;
}
}
int main()
{
set_prime();
int n;
while(scanf("%d",&n)!=EOF&&n){
printf("%d\n",m[n]);
}
return 0;
}
J题:
一道基础dp题,就是把二维分开求,先求每行的不连续序列最大值,把每行的最大值有当成一个数组,求该数组的不连续最大值
AC code:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=2e5+1;
int a[maxn],b[maxn],choose[maxn],no[maxn];///choose表示第i个选,no表示第i个不选
int Dp(int *a,int len)
{
choose[1]=a[1],no[1]=0;
for(int i=2;i<=len;i++){
choose[i]=no[i-1]+a[i];///第i个选了=第i-1个不选+a[i]
no[i]=max(choose[i-1],no[i-1]);///第i个不选等于第i-1选或不选的最大值
}
return max(choose[len],no[len]);
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int n,m;
while(cin>>n>>m){
//memset(choose,0,sizeof choose);
//memset(no,0,sizeof no);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cin>>a[j];
b[i]=Dp(a,m);///记录每行的最大值
}
cout<<Dp(b,n)<<endl;///找出每行最大值中最大的
}
return 0;
}