文章目录
T18 Chain Reaction
这题好像做过
f i f_i fi表示能保留的塔个数,那么有:
f i = { f i − 1 i 位 置 没 有 激 光 塔 1 i ≤ b i f i − b i − 1 + 1 i > b i f_i= \left\{ \begin{aligned} &f_i-1&&i位置没有激光塔\\ &1&&i\leq b_i\\ &f_{i-b_i-1}+1&&i>b_i \end{aligned} \right. fi=⎩⎪⎨⎪⎧fi−11fi−bi−1+1i位置没有激光塔i≤bii>bi
a n s = n − max 1 ≤ i ≤ l e n f i ans=n-\max_{1\le i\le len}f_i ans=n−1≤i≤lenmaxfi
注意边界
注意空间,直接开数组估计要炸
换成map
挺好
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e6+5;
int n,maxn,f[N],ans;
struct Data{
int a,b;
}a[N];
map<int,bool>mp;
map<int,int>Pow;
bool cmp(Data u,Data v){
return u.a<v.a;
}
int main(){
n=in;
for(int i=1;i<=n;++i) a[i].a=in,a[i].b=in,maxn=max(maxn,a[i].a);
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;++i){
mp[a[i].a]=true;
Pow[a[i].a]=a[i].b;
maxn=max(maxn,a[i].a);
}
if(mp[0]) f[0]=1;
for(int i=0;i<=maxn;++i){
if(mp[i]){
if(Pow[i]>=i) f[i]=1;
else f[i]=f[i-Pow[i]-1]+1;
}else f[i]=f[i-1];
ans=max(ans,f[i]);
}
printf("%d\n",n-ans);
return 0;
}
T19 the Monetary System
我很菜的时候见过这题
当然现在还是不会
显然我们要去掉原系统中由小面值能得到大面值的
这样才能构成合法的新系统
若新系统中有原系统没有且无法表示的货币,新系统显然不合法
考虑背包,用已确认不能删的更新未得到的
这题数据范围是假的
数组要往大了开
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e5+5;
int n,a[N],f[N],cnt;
void solve(){
memset(a,0,sizeof(a));
memset(f,0,sizeof(f));
n=in,cnt=n,f[0]=1;
for(int i=1;i<=n;++i) a[i]=in;
sort(a+1,a+n+1);
for(int i=1;i<=n;++i){
if(f[a[i]]){
--cnt;
continue;
}
for(int j=a[1];j<=a[n];++j) f[j]|=f[j-a[i]];
}
printf("%d\n",cnt);
// for(int i=1;i<=a[n];++i) if(f[i]) cout<<i<<" ";cout<<endl;
// for(int i=1;i<=cnt;++i) cout<<b[i]<<" ";cout<<endl;
return;
}
int main(){
int T=in;
while(T--) solve();
return 0;
}
T20 精卫填海
0/1背包
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e4+5;
const int INF=2147483647;
int v,n,c;
int vol[N],wei[N],f[N];
int main(){
v=in,n=in,c=in;
for(int i=1;i<=n;++i) vol[i]=in,wei[i]=in;
for(int i=1;i<=v;++i) f[i]=INF;f[0]=0;
for(int i=1;i<=n;++i)
for(int j=v;j>=1;--j)
if(f[j-vol[i]]!=INF)
f[j]=min(f[j],f[j-vol[i]]+wei[i]);
if(f[v]>c) puts("Impossible");
else printf("%d\n",c-f[v]);
return 0;
}
T21 [AHOI2001]质数和分解
哈!
这道题可以用生成函数做!
F = ∑ i = 1 ∞ [ i ∈ P r i m e ] x i a n s = [ x n ] ∑ i = 0 ∞ F i = [ x n ] 1 1 − F F=\sum_{i=1}^\infin [i\in \mathrm{Prime}]x^i\\ ans=[x^n]\sum_{i=0}^\infin F^i=[x^n]\frac{1}{1-F} F=i=1∑∞[i∈Prime]xians=[xn]i=0∑∞Fi=[xn]1−F1
当然这道题200的数据范围是没必要瞎搞的
递推就行
下面是一个低级至极的代码
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1000;
int n,a[N],cnt,maxn,f[N];
int p[N],num;
bool pd(int x){
for(int i=2;i<=sqrt(x);++i)
if(x%i==0) return false;
return true;
}
int main(){
while(cin>>n){
int num=0;
for(int i=2;i<=n;++i)
if(pd(i)) p[++num]=i;
memset(f,0,sizeof(f));
f[0]=1;
for(int i=1;i<=num;++i)
for(int j=p[i];j<=n;++j)
f[j]+=f[j-p[i]];
printf("%d\n",f[n]);
}
return 0;
}
T22 疯狂的采药
啊!
菜鸡痛苦的回忆
最后发现省一维空间就行了
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e5+5;
int t,m,v[N],w[N],f[N];
int main(){
t=in,m=in;
for(int i=1;i<=m;++i) v[i]=in,w[i]=in;
for(int i=1;i<=m;++i)
for(int j=v[i];j<=t;++j)
f[j]=max(f[j],f[j-v[i]]+w[i]);
printf("%d",f[t]);
return 0;
}
T23 A+B Problem(再升级)
大水题
又不能积累到筛法经验qwq
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e5+5;
int n,p[N],cnt,f[N];
bool check(int x){
for(int i=2;i<=sqrt(x);++i)
if(x%i==0) return false;
return true;
}
void prime(int lim){
for(int i=2;i<=lim;++i)
if(check(i)) p[++cnt]=i;
return;
}
signed main(){
n=in;
prime(n);
f[0]=1;
for(int i=1;i<=cnt;++i)
for(int j=p[i];j<=n;++j)
f[j]+=f[j-p[i]];
printf("%lld\n",f[n]);
// for(int i=1;i<=n;++i) cout<<f[i]<<" ";cout<<endl;
return 0;
}
果然水题
注意一下数据范围就行了
T24 最大约数和
好多数论水题
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e5+5;
int n,sum[N],f[N];
int main(){
n=in;
for(int i=1;i<=n;++i)
for(int j=1;j<i;++j)
if(!(i%j)) sum[i]+=j;
for(int i=1;i<=n;++i)
for(int j=n;j>=i;--j)
f[j]=max(f[j],f[j-i]+sum[i]);
printf("%d\n",f[n]);
// for(int i=1;i<=n;++i) cout<<f[i]<<" ";cout<<endl;
return 0;
}
T25 [USACO07DEC]Charm Bracelet S
水题?
啊不,这题是让我们读题。。。
抱歉我嘤语不好
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e5+5;
int n,v[N],m,w[N],f[N];
int main(){
n=in,m=in;
for(int i=1;i<=n;++i) v[i]=in,w[i]=in;
for(int i=1;i<=n;++i)
for(int j=m;j>=v[i];--j)
f[j]=max(f[j],f[j-v[i]]+w[i]);
printf("%d\n",f[m]);
return 0;
}
T26 [USACO09OCT]Bessie’s Weight Problem G
传送门
又是水题
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=1e5+5;
int f[N],n,w[N],lim;
int main(){
lim=in,n=in;
for(int i=1;i<=n;++i)
w[i]=in;
for(int i=1;i<=n;++i)
for(int j=lim;j>=w[i];--j)
f[j]=max(f[j],f[j-w[i]]+w[i]);
printf("%d\n",f[lim]);
return 0;
}
T27 传纸条
好题!
CCF出品,必属精品!
考虑转化题意
从起点到终点只能往右或往下
求路径上值之和最大
考虑记录状态
棋盘型DP
考虑记录坐标f[x1][y1][x2][y2]
考虑转移
f[x1][y1][x2][y2]=max(f[x1][y1-1][x2][y2-1],f[x1][y1-1][x2-1][y2],f[x1-1][y1][x2][y2-1],f[x1-1][y1][x2-1][y2])+a[x1][y1]+a[x2][y2]
即四种走下来的方法取max
考虑保证路径不重合
发现步数一致(当然是一致的)
考虑曼哈顿距离
显然每个状态都在一个棋盘的上三角形(还是等腰的)的斜边边界上
显然要选两个点
而且下面一个点确定了上面的点就只能在斜边边界上往上找了
考虑优化
上面已经提到两个点的相对位置
考虑枚举下面的点,利用这个相对位置算出上面的点
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=100;
int a[N][N],n,m,f[N][N][N];
int main(){
n=in,m=in;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
a[i][j]=in;
for(int step=3;step<=n+m;++step)
for(int x1=1,y1=step-x1;x1<=n;++x1,--y1){
if(y1>m) continue;
for(int x2=x1+1,y2=step-x2;x2<=n;++x2,--y2){
if(y2>m) continue;
f[step][x1][x2]=max(max(f[step-1][x1][x2],f[step-1][x1-1][x2-1]),max(f[step-1][x1-1][x2],f[step-1][x1][x2-1]));
f[step][x1][x2]+=a[x1][y1]+a[x2][y2];
}
}
printf("%d\n",f[n+m-1][n-1][n]);
// for(int k=1;k<=m+n;++k)
// for(int i=1;i<=n;++i)
// for(int j=1;j<=n;++j)
// printf("%d(%d,%d,%d) ",f[k][i][j],k,i,j);
return 0;
}
hurray!基本上是自己做出来的
T28 方格取数
棋盘型DP
和传纸条一样,发现每一步都有一个层次:
上三角形的斜边,只有斜边
没有前效性,DP妥妥的
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=50;
int a[N][N],n,m,f[N][N][N];
int main(){
n=in;
int x,y,w;
while(x=in){
y=in,w=in;
a[x][y]=w;
}
for(int step=2;step<=n+n;++step){
for(int x1=1,y1=step-x1;x1<=n&&y1>=1;++x1,--y1){
for (int x2=1, y2=step-x2;x2<=n&&y2>=1;++x2, --y2) {
f[step][x1][x2]=max(max(f[step-1][x1][x2], f[step-1][x1-1][x2-1]), max(f[step-1][x1-1][x2], f[step-1][x1][x2-1]));
f[step][x1][x2]+=(x1==x2&&y1==y2)?a[x1][y1]:(a[x1][y1]+a[x2][y2]);
}
}
}
printf("%d\n",f[n+n][n][n]);
// for(int k=1;k<=m+n;++k)
// for(int i=1;i<=n;++i)
// for(int j=1;j<=n;++j)
// printf("%d(%d,%d,%d) ",f[k][i][j],k,i,j);
return 0;
}