牛客小白賽22 G 倉庫選址(容斥/前綴和

這題要求n*m矩陣中選擇一個點,使得其他點到這個點的哈密頓距離之和最小

題解用的是O(n4)
我也是很無語

這裏可以用O(2)來做

做出無權值的二維前綴和,再分別作出以x和y座標爲權值的二維前綴和

    for (i=1;i<=n;i++){
    	for (j=1;j<=m;j++){
    	scanf ("%d",&a[i][j]);
    	s[i][j]=a[i][j];
   	    sx[i][j]=a[i][j]*i;
  	    sy[i][j]=a[i][j]*j;
  	    s[i][j]+=(s[i][j-1]+s[i-1][j]-s[i-1][j-1]);
 	    sx[i][j]+=(sx[i][j-1]+sx[i-1][j]-sx[i-1][j-1]);
  	    sy[i][j]+=(sy[i][j-1]+sy[i-1][j]-sy[i-1][j-1]);
        }
    }

然後對於題意,枚舉每個點爲倉庫,取出
(無權置的前綴和*x座標-帶x權值的前綴和)+(無權置的前綴和*y座標-帶y權值的前綴和)
這就是廣義的答案

對於具體的答案

我們必須分爲4大塊

在這裏插入圖片描述

具體的4部分你們看代碼吧

#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define pi pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define mod 1000000007
using namespace std;
int a[105][105],n,m;
int s[105][105],sx[105][105],sy[105][105];
inline int gs(int a,int b,int c,int d)
{if (a>c||b>d) return 0;
return s[c][d]-s[a-1][d]-s[c][b-1]+s[a-1][b-1];
}
inline int gx(int a,int b,int c,int d)
{if (a>c||b>d) return 0;
return sx[c][d]-sx[a-1][d]-sx[c][b-1]+sx[a-1][b-1];
}
inline int gy(int a,int b,int c,int d)
{if (a>c||b>d) return 0;
return sy[c][d]-sy[a-1][d]-sy[c][b-1]+sy[a-1][b-1];
}
int main (){
    int i,j,k,T;
    scanf ("%d",&T);
    while (T--)
    {scanf ("%d%d",&n,&m);
    swap(n,m);
    memset(s,0,sizeof(s));
    memset(sx,0,sizeof(sx));
    memset(sy,0,sizeof(sy));
    for (i=1;i<=n;i++)
    {for (j=1;j<=m;j++)
    {scanf ("%d",&a[i][j]);
    s[i][j]=a[i][j];
    sx[i][j]=a[i][j]*i;
    sy[i][j]=a[i][j]*j;
    s[i][j]+=(s[i][j-1]+s[i-1][j]-s[i-1][j-1]);
    sx[i][j]+=(sx[i][j-1]+sx[i-1][j]-sx[i-1][j-1]);
    sy[i][j]+=(sy[i][j-1]+sy[i-1][j]-sy[i-1][j-1]);
    }
    }
 /*   cout<<endl;
    for(int i=1;i<=n;i++){
    	for(int j=1;j<=m;j++){
    		cout<<s[i][j]<<" ";
		}
		cout<<endl;
	} 
	cout<<endl;
	for(int i=1;i<=n;i++){
    	for(int j=1;j<=m;j++){
    		cout<<sx[i][j]<<" ";
		}
		cout<<endl;
	} 
	cout<<endl;
	for(int i=1;i<=n;i++){
    	for(int j=1;j<=m;j++){
    		cout<<sy[i][j]<<" ";
		}
		cout<<endl;
	} 
	cout<<endl;*/
	
//	cout<<gs(1,1,2,2);
    int ans=200*100*100*1000;
    for (i=1;i<=n;i++)
    {for (j=1;j<=m;j++)
    {int p1=(s[i][j]*i-sx[i][j])+(s[i][j]*j-sy[i][j]);
    int p2=(gs(1,j+1,i,m)*i-gx(1,j+1,i,m))+(gy(1,j+1,i,m)-gs(1,j+1,i,m)*j);
    int p3=(gx(i+1,1,n,j)-gs(i+1,1,n,j)*i)+(gs(i+1,1,n,j)*j-gy(i+1,1,n,j));
    int p4=(gx(i+1,j+1,n,m)-gs(i+1,j+1,n,m)*i)+(gy(i+1,j+1,n,m)-gs(i+1,j+1,n,m)*j);
    int res=p1+p2+p3+p4;
    if (res<ans) ans=res;
    
    printf("%d %d %d %d   %d,",p1,p2,p3,p4,res);
    }
    printf("\n");
    }
    printf ("%d\n",ans);
    }
    return 0;
}

(這其實是我抄的榜一的代碼,見諒

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章