这次考试考得不够好。T1开挂做的,然后T2不是很会(思路不通),T3更没有思考,还是没能深入思考
T1:可以说这题开挂了,因为我知道小凯的疑惑,然后这题就A了;没有什么可吹的。在考试的时候这种结论一般不是很好找,一定要大胆猜想,看看转移是否可以减少。
按照m的dp:$f[i]=max(f[i-4],f[i-7])+a[i]$60分到手。
然后转成按照n的dp:$f[i]=max(f[j])+a[i]$(b[i]-b[j]能被4,7表示) 然后考虑如何实现后边的限制,可以先把从1到1e5的能被4,7表示的数表打出来,发现从18开始后边都能表示,那么18之前直接维护前缀最大值即可。复杂度$O(n)$
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int N=100020; long long f[N],maxi[N],a[N]; bool v[30]; struct node{long long a,b;}mo[N]; inline int rd() { int s=0,w=1; char cc=getchar(); for(;cc<'0'||cc>'9';cc=getchar()) if(cc=='-') w=-1; for(;cc>='0'&&cc<='9';cc=getchar()) s=(s<<3)+(s<<1)+cc-'0'; return s*w; } bool cmp(node a,node b) { return a.b<b.b; } int main() { //freopen("data.in","r",stdin); //freopen("data.out","w",stdout); int n=rd(),m=rd(); if(m<=100000) { memset(f,-0x3f,sizeof(f)); for(int i=1;i<=n;i++) { int x=rd(),y=rd(); a[y]+=x; } long long ans=0; f[0]=0; for(int i=1;i<=m;i++) { if(i-4<0) f[i]=-0x7fffffff; else if(i-7<0) f[i]=f[i-4]+a[i]; else f[i]=max(f[i-4],f[i-7])+a[i]; ans=max(ans,f[i]); } printf("%lld\n",ans); } else { v[0]=1;v[4]=1;v[7]=1;v[8]=1;v[11]=1;v[12]=1;v[14]=1;v[15]=1;v[16]=1; for(int i=1;i<=n;i++) mo[i].a=rd(),mo[i].b=rd(); sort(mo+1,mo+n+1,cmp); memset(f,-0x3f,sizeof(f)); f[0]=0; long long ans=0; for(int i=1;i<=n;i++) { for(int j=i-1;j>=0;j--) { if(mo[i].b-mo[j].b>17) { f[i]=max(f[i],maxi[j]+mo[i].a); break; } if(v[mo[i].b-mo[j].b]) f[i]=max(f[i],f[j]+mo[i].a); } maxi[i]=max(maxi[i-1],f[i]); ans=max(ans,f[i]); } printf("%lld\n",ans); } } /* g++ 1.cpp -o 1 ./1 3 13 100 4 10 7 1 11 */