前面简单一点的题直接过吧。

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 记忆化搜索,如果你知道博弈论,那就很简单了。

L 这个总觉得在哪里见过,不过结论也很简单,就直接记左右端点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=3100;
const int inf=0x3f3f3f3f;
const int mod=1000000007; int n;
ll f[Maxn][Maxn],a[Maxn]; signed main() {
// freopen("test.in","r",stdin);
read(n);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++) {//[j-i+1,j]
int l=j-i+1,r=j,len=n-i;
f[l][r]=max(a[l]-f[l+1][r],a[r]-f[l][r-1]);
}
printf("%lld",f[1][n]);
return 0;
}

M 首先\(O(nk^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=110000;
const int inf=0x3f3f3f3f;
const int mod=1000000007; int n,k,x;
ll f[Maxn],g[Maxn]; signed main() {
// freopen("test.in","r",stdin);
read(n,k);
f[0]=1;
for(int i=1;i<=n;i++) {
read(x);
int sum=0;
for(int j=0;j<=x;j++) {
sum+=f[j];
sum%=mod;
g[j]=sum;
}
for(int l=0,r=x+1;r<=k;l++,r++) {
sum+=f[r]-f[l];
sum%=mod;
sum+=mod;
sum%=mod;
g[r]=sum;
}
memcpy(f,g,sizeof(f));
}
printf("%d",f[k]);
return 0;
}

N 合并石子不解释。

O 枚举前i个men,匹配了哪i个women的方案数,注意i是没必要记的。

#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=3100000;
const int inf=0x3f3f3f3f;
const ll mod=1000000007; int n,a[30][30],f[Maxn]; signed main() {
// freopen("test.in","r",stdin);
read(n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
read(a[i][j]);
int end=1<<n;f[0]=1;
for(int i=1;i<end;i++) {
int cnt=0;
for(int j=1,nh=1;j<=n;j++,nh<<=1)
if(i&nh) cnt++;
for(int j=1,nh=1;j<=n;j++,nh<<=1)
if((i&nh)&&a[cnt][j]) f[i]=(f[i]+f[i^nh])%mod;
}
printf("%d\n",f[end-1]);
return 0;
}

P 很简单的入门树形DP。

Q 首先\(O(n^2)\)的DP很简单,然后用数据结构优化即可。

R 首先\(O(kn^2)\)的DP很简单,然后用矩乘优化即可。

S 简单的数位DP,具体还是看代码吧。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define qmax(x,y) (x=max(x,y));
using namespace std; typedef long long ll;
const int Maxn=11000;
const ll mod=1000000007; char a[Maxn];
int k,f[Maxn][110],ans; int main() {
scanf("%s",a);
scanf("%d",&k);
int n=strlen(a);
f[0][0]=1;
for(int i=1;i<n;i++)
for(int l=0;l<=9;l++)
for(int j=0;j<=k;j++) f[i][(j+l)%k]=(f[i][(j+l)%k]+f[i-1][j])%mod;
int sum=0;
for(int i=0;i<n;sum=(sum+a[i]-'0')%k,i++)
for(int j=0;j<a[i]-'0';j++) {
ans+=f[n-i-1][(k-(sum+j)%k)%k];
ans%=mod;
}
if(sum==0) ans++;ans--;ans+=mod;
ans%=mod;
printf("%d",ans);
return 0;
}

T 记fij为前i个数其中第i个数排名为j的方案数,然后用前缀和和后缀和维护即可。

#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=31000;
const int inf=0x3f3f3f3f;
const ll mod=1000000007; int f[Maxn],pre[Maxn],suf[Maxn],n; char readch() {
char ch=gc();
while(ch!='>'&&ch!='<') ch=gc();
return ch;
} signed main() {
// freopen("test.in","r",stdin);
read(n);f[1]=pre[1]=suf[1]=1;
for(int i=2;i<=n;i++) {
if(readch()=='<') for(int j=1;j<=i;j++) f[j]=pre[j-1];
else for(int j=1;j<=i;j++) f[j]=suf[j];
for(int j=1;j<=i;j++) pre[j]=(pre[j-1]+f[j])%mod;
for(int j=i;j>=1;j--) suf[j]=(suf[j+1]+f[j])%mod;
}
printf("%d",pre[n]);
return 0;
}

U 常见的枚举子集的套路,转移的系数要预处理一下,然后就是\(O(3^n)\)。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define qmax(x,y) (x=max(x,y));
using namespace std; typedef long long ll;
const int Maxn=110000;
const ll mod=1000000007; int n,a[21][21];
ll f[Maxn],g[Maxn]; int main() {
scanf("%d",&n);int end=1<<n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
for(int i=0;i<end;i++)
for(int j=1,tempp=1;j<=n;j++,tempp<<=1)
if(i&tempp)
for(int k=j,tempt=tempp;k<=n;k++,tempt<<=1)
if(i&tempt) f[i]+=a[j][k];
for(int i=0;i<end;i++) g[i]=f[i];
for(int i=0;i<end;i++)
for(int s=i&(i-1);s;s=i&(s-1)) qmax(g[i],g[i^s]+f[s]);
printf("%lld",g[end-1]);
return 0;
}

V 换根DP,具体请参考代码。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define qmax(x,y) (x=max(x,y));
using namespace std; typedef long long ll;
const int Maxn=210000;
const ll mod=1000000007; int to[Maxn],nxt[Maxn],first[Maxn],tot=1;
ll f[Maxn],g[Maxn],pr[Maxn],su[Maxn],p[Maxn],ans[Maxn],m;
int n,u,v; inline void add(int u,int v) {
to[tot]=v;
nxt[tot]=first[u];
first[u]=tot++;
to[tot]=u;
nxt[tot]=first[v];
first[v]=tot++;
} void dfs(int root,int fa) {
int tot=0;
f[root]++;
for(int i=first[root];i;i=nxt[i])
if(to[i]!=fa) {
dfs(to[i],root);
f[root]=f[root]*f[to[i]]%m;
}
for(int i=first[root];i;i=nxt[i]) if(to[i]!=fa) p[++tot]=to[i];
f[root]++;f[root]%=m;
pr[0]=su[tot+1]=1;
for(int i=1;i<=tot;i++) pr[i]=pr[i-1]*f[p[i]]%m;
for(int i=tot;i>=1;i--) su[i]=su[i+1]*f[p[i]]%m;
for(int i=1;i<=tot;i++) g[p[i]]=pr[i-1]*su[i+1]%m;
} void dfs2(int root,int fa) {
if(root==1) ans[root]=1;
else ans[root]=(g[root]*ans[fa]+1)%m;
for(int i=first[root];i;i=nxt[i])
if(to[i]!=fa) dfs2(to[i],root);
} int main() {
scanf("%d%lld",&n,&m);
for(int i=1;i<n;i++) {
scanf("%d%d",&u,&v);
add(u,v);
}
dfs(1,1);
dfs2(1,1);
for(int i=1;i<=n;i++) printf("%lld\n",ans[i]*(m+f[i]-1)%m);
return 0;
}

W 首先把所有的区间按照右端点排序,然后从1到n依次考虑,设fi为在第i个位置为1的最大值,那么我们每次令这个值为前面所有值的最大值,然后把扫过的区间加在这些值上,这个就可以用线段树做了。

#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=3100000;
const int inf=0x3f3f3f3f;
const ll mod=1000000007; int tl[Maxn],tr[Maxn],n,m;
ll tn[Maxn],flag[Maxn]; void build(int root,int l,int r) {
tl[root]=l;tr[root]=r;
int mid=l+r>>1;
if(l==r) return;
build(root<<1,l,mid);
build((root<<1)|1,mid+1,r);
} inline void update(int root) {
tn[root]=max(tn[root<<1],tn[(root<<1)|1]);
} void pushdown(int root) {
if(flag[root]) {
flag[root<<1]+=flag[root];
tn[root<<1]+=flag[root];
flag[(root<<1)|1]+=flag[root];
tn[(root<<1)|1]+=flag[root];
flag[root]=0;
}
} ll query(int root,int x) {
int l=tl[root],r=tr[root],mid=l+r>>1;
if(r==x) return tn[root];
pushdown(root);
if(x<=mid) return query(root<<1,x);
else return max(tn[root<<1],query((root<<1)|1,x));
} void change(int root,int l,int r,ll x) {
int lc=tl[root],rc=tr[root],mid=lc+rc>>1;
if(l<=lc&&r>=rc) {
flag[root]+=x;
tn[root]+=x;
return;
}
pushdown(root);
if(l<=mid) change(root<<1,l,r,x);
if(r>mid) change((root<<1)|1,l,r,x);
update(root);
} struct node {
int l,r;
ll x;
}b[Maxn]; int cmp(node a,node b) {
return a.r<b.r;
} signed main() {
// freopen("test.in","r",stdin);
read(n,m);
for(int i=1;i<=m;i++)
read(b[i].l,b[i].r,b[i].x);
sort(b+1,b+m+1,cmp);
build(1,1,n);
int zhy=1,nh=1;
for(int i=1;i<=n;i++) {
change(1,i,i,query(1,i));
while(b[nh].r==i) {
change(1,b[nh].l,b[nh].r,b[nh].x);
nh++;
}
}
printf("%lld",max(tn[1],0ll));
return 0;
}

X 神仙の结论:按照w+s排序然后背包即可。

至于为什么是对的,可以感性理解一下。

#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=31000;
const int inf=0x3f3f3f3f;
const ll mod=1000000007; struct node {
int w,s;
ll v;
}a[Maxn]; int n;
ll f[Maxn],ans; int cmp(node a,node b) {
return a.w+a.s<b.w+b.s;
} signed main() {
// freopen("test.in","r",stdin);
read(n);
for(int i=1;i<=n;i++)
read(a[i].w,a[i].s,a[i].v);
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
for(int j=a[i].s;j>=0;j--)
qmax(f[j+a[i].w],f[j]+a[i].v);
for(int i=0;i<Maxn;i++) qmax(ans,f[i]);
printf("%lld\n",ans);
return 0;
}

Y 这个跟前面的类似,可以用容斥算答案,但是暴力容斥是\(O(n^3)\)的,很显然通过不了本题。

但是我们可以注意到把这些点排序后,这个转移的时候是在一个DAG上转移的,那么我们在这个DAG上直接转移,时间复杂度即可降为\(O(n^2)\)。从点i到点j的方案数为\(C_{|x_i-x_j|+|y_i-y_j|}^{|x_i-x_j|}\)

#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;
const ll mod=1000000007; ll jc[Maxn],ijc[Maxn],inv[Maxn],n,m,q,f[Maxn]; struct node {
ll x,y;
}a[Maxn]; ll C(int n,int k) {
return jc[n]*ijc[k]%mod*ijc[n-k]%mod;
} int cmp(node a,node b) {
return a.x==b.x?a.y<b.y:a.x<b.x;
} signed main() {
// freopen("test.in","r",stdin);
read(n,m);
inv[0]=inv[1]=1;
for(int i=2;i<=n+m;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
jc[0]=ijc[0]=1;
for(int i=1;i<=n+m;i++) jc[i]=jc[i-1]*i%mod,ijc[i]=ijc[i-1]*inv[i]%mod;
read(q);
for(int i=1;i<=q;i++) read(a[i].x,a[i].y);
sort(a+1,a+q+1,cmp);
a[0]=(node){1,1};a[++q]=(node){n,m};
f[0]=1;
for(int i=0;i<q;i++) for(int j=i+1;j<=q;j++) if(a[i].y<=a[j].y)
f[j]=(mod+f[j]-f[i]*C(a[j].x-a[i].x+a[j].y-a[i].y,a[j].x-a[i].x)%mod)%mod;
printf("%lld",(mod-f[q])%mod);
return 0;
}

Z 蒟蒻表示不会斜率优化,于是学了一晚上。

所以这道题就很裸了啊,直接斜率优化就好了,如果不会的话可以百度一下。

#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=310000;
const int inf=0x3f3f3f3f;
const ll mod=1000000007; int n;
ll C,h[Maxn],f[Maxn]; struct node {
ll x,y;
}a[Maxn]; signed main() {
// freopen("test.in","r",stdin);
read(n,C);
for(int i=1;i<=n;i++) read(h[i]);
int zhy=1,nh=0;
a[++nh]=(node){-2*h[1],h[1]*h[1]};
for(int i=2;i<=n;i++) {
while(zhy!=nh&&h[i]*a[zhy+1].x+a[zhy+1].y<h[i]*a[zhy].x+a[zhy].y) zhy++;
f[i]=a[zhy].x*h[i]+a[zhy].y+C+h[i]*h[i];
ll x=-2*h[i],y=f[i]+h[i]*h[i];
while(zhy!=nh&&1.0*(y-a[nh].y)*(a[nh].x-a[nh-1].x)>1.0*(a[nh].y-a[nh-1].y)*(x-a[nh].x)) nh--;
a[++nh]=(node){-2*h[i],f[i]+h[i]*h[i]};
}
printf("%lld",f[n]);
return 0;
}

Atcoder Educational DP Contest的更多相关文章

  1. Atcoder Educational DP Contest 题解

    A - Frog 1/B - Frog 2 入门... #include<cstdio> #define abs(a) ((a)>=0?(a):(-(a))) #define min ...

  2. Atcoder Educational DP Contest I - Coins (概率DP)

    题意:有\(n\)枚硬币,每枚硬币抛完后向上的概率为\(p[i]\),现在求抛完后向上的硬币个数大于向下的概率. 题解:我们用二维的\(dp[i][j]\)来表示状态,\(i\)表示当前抛的是第\(i ...

  3. AtCoder Educational DP Contest 总结

    前言 感觉都初一升初二了,再做这个题是不是有点太菜了啊-- 里面大概都是些 DP 板子题(确信,题目质量还挺高的,不过不涉及太难的优化(实际上只有最后一题是斜率优化). 不管了,还是写个 blog 来 ...

  4. Sth about Educational DP Contest

    Contest Website : atcoder.jp/contests/dp \[\begin{array}{c|C|c|c} TaskNum & TaskName & Statu ...

  5. 【DP】Educational DP Contest

    这份 dp 题单的最后几题好难 orz. 前面的题比较简单,所以我会选取一些题来讲,其它的直接看代码理解吧 qwq. 传送门: https://atcoder.jp/contests/dp 全部 AC ...

  6. Educational DP Contest H - Grid 1 (DP)

    题意:有一个\(n\)X\(m\)的图,"#"表示障碍物,"."表示道路,只能向右或向下走,问从左上角走到右下角的方案数. 题解:这题可以用bfs来搞,但dp更 ...

  7. Educational DP Contest G - Longest Path (dp,拓扑排序)

    题意:给你一张DAG,求图中的最长路径. 题解:用拓扑排序一个点一个点的拿掉,然后dp记录步数即可. 代码: int n,m; int a,b; vector<int> v[N]; int ...

  8. Educational DP Contest F - LCS (LCS输出路径)

    题意:有两个字符串,求他们的最长公共子序列并输出. 题解:首先跑个LCS记录一下dp数组,然后根据dp数组来反着还原路径,只有当两个位置的字符相同时才输出. 代码: char s[N],t[N]; i ...

  9. Educational DP Contest E - Knapsack 2 (01背包进阶版)

    题意:有\(n\)个物品,第\(i\)个物品价值\(v_{i}\),体积为\(w_{i}\),你有容量为\(W\)的背包,求能放物品的最大价值. 题解:经典01背包,但是物品的最大体积给到了\(10^ ...

随机推荐

  1. vmware 安装 kali linux 系统到U盘 启动错误(initramfs:) 修复方法

    安装kalilinux到U盘 启动之后出现这个错误: 这是grub路径不对. 解决办法: 在这模式下可以输入命令:blkid 查看所列举出的磁盘 找到你的U盘系统 TYPE="ext4&qu ...

  2. python课件-淘宝-目录.txt

    卷 TOSHIBA EXT 的文件夹 PATH 列表卷序列号为 AE86-8E8DF:.│ python课件-淘宝-目录.txt│ ├─01python核心编程阶段-linux基础(│ linux_h ...

  3. literallycanvas的简介

    LiterallyCanvas是什么 Literally Canvas是一个可扩展的开源(BSD许可)HTML5绘图组件,可以用于网页中插入画图板,类似于windows自带的画图板.可以用可视化工具绘 ...

  4. PAT 1032 Sharing[hash][链表][一般上]

    1032 Sharing (25)(25 分) To store English words, one method is to use linked lists and store a word l ...

  5. 算法---数组总结篇2——找丢失的数,找最大最小,前k大,第k小的数

    一.如何找出数组中丢失的数 题目描述:给定一个由n-1个整数组成的未排序的数组序列,其原始都是1到n中的不同的整数,请写出一个寻找数组序列中缺失整数的线性时间算法 方法1:累加求和 时间复杂度是O(N ...

  6. How to install MVVM Light Toolkit via NuGet

    Here is how you can install MVVM Light Toolkit  via NuGet in an easy way using only Visual Studio. S ...

  7. Summary: difference between public, default, protected, and private key words

    According to Java Tutorial: Controlling Access to Members of a Class Access level modifiers determin ...

  8. Django初级手册2-管理界面的使用及定制

    管理界面的使用 管理界面的URL,帐号和密码在第一次输入syncdb时建立 http://127.0.0.1:8000/admin/ 将app加入管理界面 编辑polls/admin.py from ...

  9. 电子地图/卫星地图下载并转存为jpg图片

    1.下载水经注万能地图下载器破解版 http://download.csdn.net/download/hyb2012/8714725,此软件为绿色免安装且免注册 2.下载后解压缩后,运行sgwn.e ...

  10. C# Bulk Operations(转)

    转自http://blog.csdn.net/winnyrain/article/details/51240684 Overcome SqlBulkCopy Limitations with C# B ...