前面简单一点的题直接过吧。
A 暴力DP
B 怎么还是暴力DP
C 还是暴力DP
D 直接背包
E 这个背包不太一样了,这里有一个技巧,就是因为价值很小,所以直接对价值背包,求出来达到某一个权值最小的重量,然后找到满足限制的最大的价值即可。注意,如果能达到权值比这个还大的点,那么这个点很显然也是可以达到的。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define qmin(x,y) (x=min(x,y))
#define qmax(x,y) (x=max(x,y))
using namespace std;
inline char gc() {
// static char buf[100000],*p1,*p2;
// return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
return getchar();
}
template<class T>
int read(T &ans) {
ans=0;char ch=gc();T f=1;
while(!isdigit(ch)) {
if(ch==EOF) return -1;
if(ch=='-') f=-1;
ch=gc();
}
while(isdigit(ch))
ans=ans*10+ch-'0',ch=gc();
ans*=f;return 1;
}
template<class T1,class T2>
int read(T1 &a,T2 &b) {
return read(a)!=EOF&&read(b)!=EOF?2:EOF;
}
template<class T1,class T2,class T3>
int read(T1 &a,T2 &b,T3 &c) {
return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
}
typedef long long ll;
const int Maxn=210000;
const int inf=0x3f3f3f3f;
int n,w,tot;
ll f[Maxn],v;
signed main() {
// freopen("test.in","r",stdin);
read(n,tot);
memset(f,0x3f,sizeof(f));f[0]=0;
int now=0;
for(int i=1;i<=n;i++) {
read(w,v);
for(int j=now+v;j>=v;j--) f[j]=min(f[j],f[j-v]+w);
now+=v;
}
for(int i=now;i>=0;i--) f[i]=min(f[i],f[i+1]);
int ans=0;
while(f[ans]<=tot) ans++;
printf("%d\n",ans-1);
return 0;
}
F 套路题,统计答案略恶心,还是贴一下代码吧。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define qmin(x,y) (x=min(x,y))
#define qmax(x,y) (x=max(x,y))
using namespace std;
inline char gc() {
// static char buf[100000],*p1,*p2;
// return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
return getchar();
}
template<class T>
int read(T &ans) {
ans=0;char ch=gc();T f=1;
while(!isdigit(ch)) {
if(ch==EOF) return -1;
if(ch=='-') f=-1;
ch=gc();
}
while(isdigit(ch))
ans=ans*10+ch-'0',ch=gc();
ans*=f;return 1;
}
template<class T1,class T2>
int read(T1 &a,T2 &b) {
return read(a)!=EOF&&read(b)!=EOF?2:EOF;
}
template<class T1,class T2,class T3>
int read(T1 &a,T2 &b,T3 &c) {
return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
}
typedef long long ll;
const int Maxn=3100;
const int inf=0x3f3f3f3f;
int f[Maxn][Maxn],pre[Maxn][Maxn],top;
char a[Maxn],s[Maxn],st[Maxn];
signed main() {
// freopen("test.in","r",stdin);
scanf("%s%s",a,s);
int n=strlen(a),m=strlen(s);
for(int i=0;i<m;i++) if(a[0]==s[i]) f[0][i]=1;
for(int i=0;i<m;i++) pre[0][i]=-1;
for(int i=1;i<n;i++) {
int now=0,las=-1;
for(int j=0;j<m;j++) {
if(a[i]==s[j]) {
if(f[i-1][j]>now+1) {
now=f[i-1][j],las=(a[i-1]==s[j]?i-1:pre[i-1][j]);
pre[i][j]=las;
f[i][j]=now;
}
else {
pre[i][j]=las;
f[i][j]=now+1;
if(f[i-1][j]>now)
now=f[i-1][j],las=(a[i-1]==s[j]?i-1:pre[i-1][j]);
}
}
else {
if(f[i-1][j]>now)
now=f[i-1][j],las=(a[i-1]==s[j]?i-1:pre[i-1][j]);
pre[i][j]=las;
f[i][j]=now;
}
}
}
int ans=0,temp;
for(int i=0;i<m;i++) if(f[n-1][i]>ans) {
ans=f[n-1][i];
temp=i;
}
if(ans==0) return 0;
int nx,ny=temp;
if(a[n-1]==s[temp]) nx=n-1;
else nx=pre[n-1][temp];
while(nx!=-1) {
st[++top]=a[nx];
nx=pre[nx][ny];
int ans=0,temp;
for(int i=0;i<ny;i++)
if(f[nx][i]>ans) ans=f[nx][i],temp=i;
ny=temp;
}
while(top) putchar(st[top--]);
return 0;
}
G 直接DAG上的DP,太简单了不放代码了。
H 每个点都是从上边或左边转移即可。
I 概率DP,直接记有i个正面朝上的概率,然后就可以\(O(n^2)\)DP了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define qmin(x,y) (x=min(x,y))
#define qmax(x,y) (x=max(x,y))
using namespace std;
inline char gc() {
// static char buf[100000],*p1,*p2;
// return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
return getchar();
}
template<class T>
int read(T &ans) {
ans=0;char ch=gc();T f=1;
while(!isdigit(ch)) {
if(ch==EOF) return -1;
if(ch=='-') f=-1;
ch=gc();
}
while(isdigit(ch))
ans=ans*10+ch-'0',ch=gc();
ans*=f;return 1;
}
template<class T1,class T2>
int read(T1 &a,T2 &b) {
return read(a)!=EOF&&read(b)!=EOF?2:EOF;
}
template<class T1,class T2,class T3>
int read(T1 &a,T2 &b,T3 &c) {
return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
}
typedef long long ll;
const int Maxn=11000;
const int inf=0x3f3f3f3f;
const int mod=1000000007;
int n;
double f[Maxn],p;
signed main() {
// freopen("test.in","r",stdin);
read(n);
f[0]=1;
for(int i=1;i<=n;i++) {
scanf("%lf",&p);
for(int j=i;j>=1;j--) f[j]=(f[j]*(1.0-p)+f[j-1]*p);
f[0]*=1.0-p;
}
double ans=0;
for(int i=n/2+1;i<=n;i++) ans+=f[i];
printf("%.10lf",ans);
return 0;
}
J 期望DP,因为每个数都很小,直接记目前剩一个,两个,三个的分别有多少。好像从小到大转移要方便一些。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define qmin(x,y) (x=min(x,y))
#define qmax(x,y) (x=max(x,y))
using namespace std;
inline char gc() {
// static char buf[100000],*p1,*p2;
// return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
return getchar();
}
template<class T>
int read(T &ans) {
ans=0;char ch=gc();T f=1;
while(!isdigit(ch)) {
if(ch==EOF) return -1;
if(ch=='-') f=-1;
ch=gc();
}
while(isdigit(ch))
ans=ans*10+ch-'0',ch=gc();
ans*=f;return 1;
}
template<class T1,class T2>
int read(T1 &a,T2 &b) {
return read(a)!=EOF&&read(b)!=EOF?2:EOF;
}
template<class T1,class T2,class T3>
int read(T1 &a,T2 &b,T3 &c) {
return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
}
typedef long long ll;
const int Maxn=310;
const int inf=0x3f3f3f3f;
const int mod=1000000007;
int n,x,a[4];
double f[Maxn][Maxn][Maxn];
signed main() {
// freopen("test.in","r",stdin);
read(n);
for(int i=1;i<=n;i++) {
read(x);
a[x]++;
}
for(int i=0;i<=n;i++)
for(int j=0;j<=n-i;j++)
for(int k=0;k<=n-i-j;k++) {
if(!i&&!j&&!k) continue;
double x=i+j+k,p=(double)n/x;
if(i) f[i][j][k]+=f[i-1][j+1][k]*i/x;
if(j) f[i][j][k]+=f[i][j-1][k+1]*j/x;
if(k) f[i][j][k]+=f[i][j][k-1]*k/x;
f[i][j][k]+=p;
}
printf("%.10lf",f[a[3]][a[2]][a[1]]);
return 0;
}
K 记忆化搜索,如果你知道博弈论,那就很简单了。