20190820考试反思
这次考试考得不够好。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 */
T2:差点想到正解。给n*m矩阵要求$(n+m-1)*\sum (A_{i}-Avag)^{2}$最小值。看到平方不会处理就先拆出来。
$(n+m-1)*\sum(A_{i}^{2}-2A_{i}*Avag+Avag^{2})$
$\sum((n+m-1)*A{i}^2-2A_{i}*\sum A_{i}+Avag*\sum A_{i})$
$(n+m-1)*\sum(A_{i}^2)-(\sum A_{i})^{2}$
然后,我就傻X的用这个柿子打搜索。。。。
题目明确提醒,矩阵元素不大于30,以前不知道他在说啥,以后应该知道他在提示可以压进状态。
设f[s][i][j]为到i,j的和为s的最小平方和。
转移即可。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int S=30*920,N=40; int f[S][N][N],a[N][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; } int main() { int T=rd(); while(T--) { int n=rd(),m=rd(),maxi=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=rd(),maxi=max(maxi,a[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int s=0;s<=maxi*(n+m);s++) f[s][i][j]=0x7ffffff; f[a[1][1]][1][1]=a[1][1]*a[1][1]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { for(int s=0;s<=maxi*(n+m);s++) { f[s+a[i+1][j]][i+1][j]=min(f[s+a[i+1][j]][i+1][j],f[s][i][j]+a[i+1][j]*a[i+1][j]); f[s+a[i][j+1]][i][j+1]=min(f[s+a[i][j+1]][i][j+1],f[s][i][j]+a[i][j+1]*a[i][j+1]); } } long long ans=0x7ffffffffffffff; for(int s=0;s<=maxi*(n+m);s++) { ans=min(1ll*ans,1ll*(n+m-1)*f[s][n][m]-s*s); } printf("%lld\n",ans); } } /* g++ 2.cpp -o 2 ./2 1 2 2 1 2 3 4 */
T3:好题,再次提醒:位运算是位的运算,只和位之间有关,我们可以知道,异或不满足加法结合律,那么这个就没法树DP转移。
那么我们可以好好想一下到底怎么处理这种东西。另外,异或的数不超过16。
性质:由于只和位有关,我没们发现,假设异或的数有k位,对于后k位相同的,异或前后变化相同,我们就可以找到后k位的数是j的路径个数,然后可以通过这个数组得到答案,这个数组满足结合律,可以树上转移,另外用最朴素的f数组存路径和。
这两个数组既然可以树上转移,那就可以换根,最终换根算出最终答案就可以了。
#include<iostream> #include<cstdio> using namespace std; const int N=500020; int fr[N],tt,fa[N],f[N],size[N],tmp[20],s[N][20],n,m,ans; struct node{int to,pr,w;}mo[N*2]; 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; } void add(int x,int y,int c) { mo[++tt].to=y;mo[tt].w=c; mo[tt].pr=fr[x];fr[x]=tt; } void dfs1(int x) { size[x]=1;s[x][0]++; for(int i=fr[x];i;i=mo[i].pr) { int to=mo[i].to; if(to==fa[x]) continue; fa[to]=x; dfs1(to); f[x]+=f[to]+size[to]*mo[i].w; for(int j=0;j<=15;j++) s[x][(j+mo[i].w)&15]+=s[to][j]; //s[x][(mo[i].w)&15]++; size[x]+=size[to]; } /*for(int j=0;j<=15;j++) { cout<<x<<" "<<j<<" "<<s[x][j]<<endl; }*/ } void dfs2(int x) { for(int i=fr[x];i;i=mo[i].pr) { int to=mo[i].to; if(to==fa[x]) continue; fa[to]=x; f[to]=f[to]+f[x]-(f[to]+size[to]*mo[i].w)+mo[i].w*(n-size[to]); //cout<<to<<" "<<f[to]<<endl; //cout<<s[4][13]<<endl; for(int j=0;j<=15;j++) { //cout<<to<<" "<<j<<" "<<s[x][j]<<" "<<s[to][j]<<endl; tmp[(mo[i].w+(j+mo[i].w)&15)&15]=s[x][(j+mo[i].w)&15]-s[to][j]; } for(int j=0;j<=15;j++) { s[to][j]+=tmp[j]; ///cout<<to<<" "<<j<<" "<<s[to][j]<<endl; } dfs2(to); } } int main() { n=rd();m=rd(); for(int i=1;i<n;i++) { int x=rd(),y=rd(),z=rd(); add(x,y,z);add(y,x,z); } dfs1(1); dfs2(1); for(int i=1;i<=n;i++) { for(int j=0;j<=15;j++) { f[i]-=s[i][j]*j; f[i]+=s[i][j]*(j^m); } printf("%d\n",f[i]-m); } } /* g++ 3.cpp -o 3 ./3 5 3 1 2 1 1 3 2 1 4 3 2 5 4 */