今天我居然A了一道题???怕不是把明年的运气都用光了
T1 题意简述:给出两个n*n的矩阵,m次询问它们的积中给定子矩阵的数值和。
n<=2000,m<=50000
解题思路:这道题其实最主要的是这个...每个测试点时限6秒
这告诉我们...暴力就能过...
当然也不能随便暴力。分别做前缀和即可。复杂度O(nm)。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<ctime> #define ll long long using namespace std; ll n,m; ll ans,suma[2010][2010],sumb[2010][2010]; ll read() { ll f=1;ll x=0;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} x*=f;return x; } int main() { // system("CreatRand.exe"); freopen("matrix.in","r",stdin); freopen("matrix.out","w",stdout); // ll st=clock(); n=read(),m=read(); for(ll i=1;i<=n;i++) for(ll j=1;j<=n;j++) suma[i][j]=read(),suma[i][j]+=suma[i-1][j]; for(ll i=1;i<=n;i++) for(ll j=1;j<=n;j++) sumb[i][j]=read(),sumb[i][j]+=sumb[i][j-1]; for(ll i=1;i<=m;i++) { ans=0; ll xa=read(),ya=read(),xb=read(),yb=read(); if(xa>xb) swap(xa,xb); if(ya>yb) swap(ya,yb); for(ll i=1;i<=n;i++) ans+=(suma[xb][i]-suma[xa-1][i])*(sumb[i][yb]-sumb[i][ya-1]); printf("%lld ",ans); } // ll ed=clock(); // printf("%lld ",ed-st); return 0; }
T2 题意简述:平面上有N个整数坐标点。如果将点(x0,y0)移动到(x1,y1),则代价为它们之间的切比雪
夫距离。求使得K个点在同一位置上最少需要的代价。
N≤50,K=(1,N),0≤xi≤yi≤10^6
解题思路:有一条很显然的性质:这个同一位置的横坐标必与某个点的横坐标相同。纵坐标亦然。
至于怎么证明...感性理解就好。(略略略)
因此只需要枚举出所有满足条件的点(最多n^2个),分别求出其与n个坐标点的距离,排】
序后做前缀和,分别取最小值即可。
能这么做的原因是因为数据太水。正解似乎是平衡树。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<ctime> #define ll long long #define INF 0x3f3f3f3f using namespace std; int n,cnt,dot[55][3],dis[2505][55]; int main() { freopen("tower.in","r",stdin); freopen("tower.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&dot[i][1],&dot[i][2]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { cnt++; for(int k=1;k<=n;k++) dis[cnt][k]=abs(dot[k][1]-dot[i][1])+abs(dot[k][2]-dot[j][2]); sort(dis[cnt]+1,dis[cnt]+1+n); for(int k=1;k<=n;k++) dis[cnt][k]+=dis[cnt][k-1]; } for(int i=1;i<=n;i++) { int ans=INF; for(int j=1;j<=cnt;j++) ans=min(ans,dis[j][i]); printf("%d ",ans); } return 0; }
T3 题意简述:求一棵树的最大匹配及最大匹配种类数。
60%的数据:答案不超过10^18。100%的数据:N≤1000。
解题思路:先得吐槽一下出题人...模拟赛出什么高精度...听AK大佬说普通的高精还过不了,得用
压位高精什么的...垃圾出题人
以下思路及代码仅适用于前60分。
考虑到匈牙利算法无法算出种类数,考虑树上算法。
扳了扳手指算了算发现这次考试还没有考dp,考虑树形dp。
f[i][0,1]表示以i为根的子树,f[i][0]表示点i未匹配的最大值,f[i][1]表示点i匹配
的最大值,g[i][0,1]表示相应的方案数。
f[i][0] = ∑max{f[i.son][0],f[i.son][1]}
g[i.son][0] (f[i.son][0] > f[i.son][1])
g[i][0] = ∏g[i.son][1] (f[i.son][0] < f[i.son][1])
g[i.son][0]+g[i.son][1](f[i.son][0] == f[i.son][1])
f[i][1] = max{f[i][0] - max(f[i.son][0],f[i.son][1]) + f[i.son][0]}+1
g[i][1] = f[i][1]时的方案数。
由于博主本人过菜,代码无法输出正确答案,这里贴出Menteur_Hxy大佬的代码
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define ll long long using namespace std; ll n,cnt,root,d[1005],head[1005]; ll f[1005][2],g[1005][2]; struct uio{ ll nxt,to; }edge[1000005]; void add(ll x,ll y) { edge[++cnt].nxt=head[x]; edge[cnt].to=y; head[x]=cnt; } void dfs(ll x) { ll sum=0,mul=1; for(ll i=head[x];i;i=edge[i].nxt) { ll y=edge[i].to; dfs(y); sum+=max(f[y][0],f[y][1]); if(f[y][0]>f[y][1]) mul*=g[y][0]; else if(f[y][0]<f[y][1]) mul*=g[y][1]; else mul*=(g[y][0]+g[y][1]); } f[x][0]=sum,g[x][0]=mul; for(ll i=head[x];i;i=edge[i].nxt) { ll y=edge[i].to; ll now=sum-max(f[y][0],f[y][1])+f[y][0]+1; if(now>f[x][1]) { f[x][1]=now; if(f[y][0]>f[y][1]) g[x][1]=mul; else if(f[y][0]<f[y][1]) g[x][1]=mul/g[y][1]*g[y][0]; else g[x][1]=mul/(g[y][0]+g[y][1])*g[y][0]; } else if(now==f[x][1]) { if(f[y][0]>f[y][1]) g[x][1]+=mul; else if(f[y][0]<f[y][1]) g[x][1]+=mul/g[y][1]*g[y][0]; else g[x][1]+=mul/(g[y][0]+g[y][1])*g[y][0]; } } // g[x][0]=1;f[x][0]=0; // for(ll i=head[x];i;i=edge[i].nxt) // { // ll y=edge[i].to; // dfs(y); // f[x][0]+=max(f[y][0],f[y][1]); // if(f[y][0]>f[y][1]) g[x][0]*=g[y][0]; // if(f[y][0]<f[y][1]) g[x][0]*=g[y][1]; // if(f[y][0]==f[y][1]) g[x][0]*=(g[y][0]+g[y][1]); // } // for(ll i=head[x];i;i=edge[i].nxt) // { // ll y=edge[i].to; // ll now=f[x][0]-max(f[y][0],f[y][1])+f[y][0]+1; // if(now>f[x][1]) // { // f[x][1]=now; // if(f[y][0]>f[y][1]) g[x][1]=g[x][0]; // if(f[y][0]<f[y][1]) g[x][1]=g[x][0]/g[y][1]*g[y][0]; // if(f[y][0]==f[y][1]) g[x][1]=g[x][0]/(g[y][0]+g[y][1])*g[y][0]; // } // if(now==f[x][1]) // { // if(f[y][0]>f[y][1]) g[x][1]+=g[x][0]; // if(f[y][0]<f[y][1]) g[x][1]+=g[x][0]/g[y][1]*g[y][0]; // if(f[y][0]==f[y][1]) g[x][1]+=g[x][0]/(g[y][0]+g[y][1])*g[y][0]; // } // } } int main() { // freopen("tree.in","r",stdin); // freopen("tree.out","w",stdout); scanf("%lld",&n); for(ll i=1;i<=n;i++) { ll u,v,w; scanf("%lld%lld",&u,&v); for(ll j=1;j<=v;j++) { scanf("%lld",&w), add(u,w);d[w]++; } } for(ll i=1;i<=n;i++) if(!d[i]) {root=i;break;} dfs(root); printf("%lld ",max(f[root][0],f[root][1])); if(f[root][0]>f[root][1]) printf("%lld ",g[root][0]); if(f[root][0]<f[root][1]) printf("%lld ",g[root][1]); if(f[root][0]==f[root][1]) printf("%lld ",g[root][0]+g[root][1]); return 0; }