1. 程式人生 > >牛客網暑期ACM多校訓練營(第二場)-J-farm

牛客網暑期ACM多校訓練營(第二場)-J-farm

(一)題面:

題目描述 

White Cloud placed n containers in sequence on a axes. The i-th container is located at x[i] and there are a[i] number of products in it.
White Rabbit wants to buy some products. The products which are required to be sold must be placed in the same container.
The cost of moving a product from container u to container v is 2*abs(x[u]-x[v]).
White Cloud wants to know the maximum number of products it can sell. The total cost can't exceed T.

輸入描述:

The first line of input contains 2 integers n and T(n <= 500000,T <= 1000000000000000000)
In the next line there are n increasing numbers in range [0,1000000000] denoting x[1..n]
In the next line there are n numbers in range[0,10000] denoting a[1..n]

輸出描述:

Print an integer denoting the answer.

示例1

輸入

2 3
1 2
2 3

輸出

4

(二)題意:

給定一個n*m的矩陣,給出矩陣中每一個位置的初始值,給定T次操作,每次操作給出一個子矩陣及一個值val,需要將該子矩陣中的每一個位置的值替換為val,問在操作T次以後,原矩陣中有多少個位置上的值改變過至少一次。

(三)題解:

①現將原操作中的替換操作視作加操作,那麼經過T操作以後,如果某個位置上的值只與與初始值相等的值相加過,那麼最後相加以後的結果一定是初始值的整倍數。那麼如果與不想等的值相加過呢?結果是不確定的,比如某個位置上的初始值為3,然後該位置上先後加了1、2,那麼最終得到的結果也是初始值3的整倍數。為了儘可能避免這種情況,我們可以為每一個初始值重新對映一個值,這樣處理以後雖然仍然會有錯誤的可能,但是機率就比較小了。接著就是求一個二維字首和查詢即可。複雜度O(n*m)。

②官方題解是將每一個值化成一個二進位制串處理,如果兩個值不想等,那麼這兩個值的二進位制位上至少有一個不相同,那麼我們統計一下每一個位置的每一個二進位制位上被0覆蓋和被1覆蓋的次數,這個求一次二維字首和也可統計。如果原來的數字為0,而現在有1覆蓋過,那麼肯定被不同的數覆蓋過,同理如果原來為1,而被0覆蓋過,則也是被不同的數覆蓋過。這種做法和上述做法有一定的相似,但是結果一定是對的。複雜度O(n*m+T)log(n*m)。

(四)程式碼:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<ctime>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e6+10;
int n,m,k,x1,Y1,x2,y2,z;
LL Hash[maxn];
int main(){
    srand(time(0));
//    freopen("in.txt","r",stdin);
    for(LL i=0;i<maxn;i++)Hash[i]=i*i+i*rand()+1;
    scanf("%d%d%d",&n,&m,&k);
    LL **pre=new LL *[n+5];
    LL **now=new LL *[n+5];
    for(int i=0;i<n+5;i++){
        pre[i]=new LL[m+5];
        now[i]=new LL[m+5];
    }
    for(int i=0;i<=n+1;i++){
        for(int j=0;j<=m+1;j++){
            now[i][j]=pre[i][j]=0;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%lld",&pre[i][j]);
            pre[i][j]=Hash[pre[i][j]];
            now[i][j]=0;
        }
    }
    for(int i=0;i<k;i++){
        scanf("%d%d%d%d%d",&x1,&Y1,&x2,&y2,&z);
        now[x1][Y1]+=Hash[z];
        now[x1][y2+1]-=Hash[z];
        now[x2+1][Y1]-=Hash[z];
        now[x2+1][y2+1]+=Hash[z];
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            now[i][j]+=now[i][j-1]+now[i-1][j]-now[i-1][j-1];
            ans+=now[i][j]%pre[i][j]!=0;
        }
    }
    printf("%d\n",ans);
    return 0;
}