9.8考试
题面
T1
T2
T3
原题
三道原题所以没密码。
题解。。。
T1
设f[i][j]为放i个数j种数的方案。然后转移方程求法:
1.最后一个数以前没出现过。有(n-j+1)种。(f[i][j]+=f[i-1][j-1×(n-j+1)])
2.最后一个数以前出现过。有j种,但前面有m种不能选,所以是(j-m)种。(f[i][j]=f[i-1][j]×(j-m))
然鹅j-m可能爆负,所以先求出f[m][m]。
(f[m][m]=P_m^n)。
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define Fname "pf"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il int gi(){
rg int x=0,f=1;rg char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
ll f[1010][1010];
//f[i][j]:
//放i个数j种数的方案
ll mod=1e9+7;
int main(){
freopen(Fname".in","r",stdin);
freopen(Fname".out","w",stdout);
int n=gi(),m=gi(),p=gi();
if(p==n){ll prt=1;rep(i,2,n)prt=prt*i%mod;printf("%lld
",prt);return 0;}
if(p<n){puts("0");return 0;}
f[m][m]=1;
rep(i,1,m)f[m][m]=f[m][m]*(n-i+1)%mod;
rep(i,m+1,p)rep(j,m,n)f[i][j]=(f[i-1][j-1]*(n-j+1)%mod+f[i-1][j]*(j-m)%mod)%mod;
printf("%lld
",f[p][n]);
return 0;
}
T2
裸dp。然鹅考场上没调出来,不知道为什么,然后稍稍调一下上界就过了。。。
设f[i][j][k]为当前挑战完第i场,共胜利j场,背包容量k(可负)的获胜概率。
方程:
1.胜利,(f[i][j][k]×p[i+1]->f[i+1][j+1][k+a[i]])
2.失败,(f[i][j][k]×(1-p[i+1])->f[i+1][j][k])
k可负就整体加一个值
先与n取min,剩下的没用
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define Fname "guard"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il int gi(){
rg int x=0,f=1;rg char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
#define db double
db p[210];
int a[210];
db F[201][201][401];
#define f(a,b,c) (F[a][b][min((c)+n,n*2)])
int main(){
freopen(Fname".in","r",stdin);
freopen(Fname".out","w",stdout);
int n=gi(),L=gi(),K=gi();
rep(i,1,n)scanf("%lf",&p[i]),p[i]/=100.00;
rep(i,1,n)a[i]=gi();
f(0,0,K)=1;
rep(i,0,n-1)rep(j,0,i)rep(k,-i,n)
f(i+1,j+1,k+a[i+1])+=f(i,j,k)*p[i+1],
f(i+1,j,k)+=f(i,j,k)*(1-p[i+1]);
db ans=0;
rep(i,L,n)rep(j,0,n)ans+=f(n,i,j);
printf("%.6lf
",ans);
return 0;
}
T3
选若干个数,不能取连续的k+1个,求最大和
反过来也是可以的,选若干个数,相邻两数距离不超过k,求最小和
设f[i]表示1~i区间里选若干个数,相邻两数距离不超过k的最小和(f[0]=0)
(f[i]=min{f[i-j]}+e[i](jin[i-k,i-1]))
这就有70了。再弄个单调队列优化一下
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#ifndef lemon
#define Fname "mowlawn"
#else
#define Fname "cg"
#endif
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il ll gi(){
rg ll x=0;rg char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x;
}
ll f[100010],e[100010];
int que[100010],hd=0,tl=0;
int main(){
freopen(Fname".in","r",stdin);
freopen(Fname".out","w",stdout);
int n=gi(),k=gi();ll sum=0;
rep(i,1,n)e[i]=gi(),sum+=e[i];
e[n+1]=0;++n;
f[0]=0;
rep(i,1,n){
f[i]=2e18;
while(hd^tl&&que[hd]<i-k-1)++hd;
f[i]=f[que[hd]]+e[i];
while(hd^tl&&f[i]<f[que[tl]])--tl;
que[++tl]=i;
}
ll ans=2e18;
rep(i,n-k,n)ans=min(ans,f[i]);
printf("%lld
",sum-ans);
return 0;
}