当前位置: 代码迷 >> 综合 >> NewOJ Week 5
  详细解决方案

NewOJ Week 5

热度:94   发布时间:2023-11-27 00:06:22.0

NewOJ Week 5

C.E待补

目录

      • A. 并行处理(前缀和)
      • B. 排列变换(思维)
      • D. 矩阵(数学+前缀和)

A. 并行处理(前缀和)

思路:显然最短时间为 m i n ( m a x ( ∑ i = 1 j a i , ∑ i = j + 1 n a i ) min(max(\sum_{i=1}^{j} a_i,\sum_{i=j+1}^{n}a_i) min(max(i=1j?ai?,i=j+1n?ai?) 1 ≤ j ≤ n 1\le j \le n 1jn,前缀和处理一下
复杂度: O ( n ) O(n) O(n)

C o d e : Code: Code:

#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e6+10,mod=1e9+7;
int n,a[N];
int main(){
    IOS;cin>>n;ll ans=1e18,ans1=0,sum=0;for(int i=1;i<=n;i++) {
    cin>>a[i];sum+=a[i];}for(int i=1;i<=n;i++){
    ans1+=a[i];ans=min(ans,max(ans1,sum-ans1));}cout<<ans<<endl;return 0;
}

B. 排列变换(思维)

思路:先考虑一个常见的问题:对于一个长度为 n n n的排列 a a a,每次选择一个数字往左移若干位,求将其变为递增序列需要的最小移动次数?
举个例子: 3 , 1 , 5 , 2 , 4 3,1,5,2,4 3,1,5,2,4,显然我们需要移动 3 3 3次,分别为 1 , 2 , 4 1,2,4 1,2,4,我们发现移动的原因显然是: 3 > 1 , 5 > 2 , 5 > 4 3>1,5>2,5>4 3>1,5>2,5>4,即:对于某个位置,如果它前面的序列的最大值大于它,它就需要移动位置
那对于这个问题,我们就把序列 b b b的值映射到一个递增序列中,即可把问题转换为上述问题
复杂度: O ( n ) O(n) O(n)

C o d e : Code: Code

#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e6+10,mod=1e9+7;
int n,a[N],c[N],b[N];
map<int,int>mp;
int main(){
    IOS;cin>>n;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++) cin>>b[i],mp[b[i]]=i;for(int i=1;i<=n;i++) c[i]=mp[a[i]];int ans=0,pos=0;for(int i=1;i<n;i++){
    if(max(pos,c[i])>c[i+1]) {
    ans++;pos=max(pos,c[i]);}}cout<<ans<<endl;return 0;
}

D. 矩阵(数学+前缀和)

思路:对于矩阵乘法: C i , j = ∑ k = 1 n A i , k ? B k , j C_{i,j}=\sum\limits_{k=1}^{n} A_{i,k}*B_{k,j} Ci,j?=k=1n?Ai,k??Bk,j?,如果直接运算,复杂度 O ( n 3 ) O(n^3) O(n3)肯定 T L E TLE TLE
但对于每次询问 a , b , c , d a,b,c,d a,b,c,d构成的子矩阵和时,我们通过和式变换:
∑ i = a c ∑ j = b d C i , j = ∑ i = a c ∑ j = b d ∑ k = 1 n A i , k ? B k , j = ∑ k = 1 n [ ( ∑ i = a c A i , k ) ? ( ∑ j = b d B k , j ) ] \sum\limits_{i=a}^{c}\sum\limits_{j=b}^{d}C_{i,j}=\sum\limits_{i=a}^{c}\sum\limits_{j=b}^{d}\sum\limits_{k=1}^{n}A_{i,k}*B_{k,j}=\sum\limits_{k=1}^{n}\Bigg[\Big(\sum\limits_{i=a}^{c}A_{i,k}\Big)*\Big(\sum\limits_{j=b}^{d}B_{k,j}\Big)\Bigg] i=ac?j=bd?Ci,j?=i=ac?j=bd?k=1n?Ai,k??Bk,j?=k=1n?[(i=ac?Ai,k?)?(j=bd?Bk,j?)]
然后我们通过这个式子写出了如下 q u e r y query query函数:

ll query(int a,int b,int c,int d){
    ll ans=0;for(int k=1;k<=n;k++){
    ll ans1=0,ans2=0;for(int i=1;i<=n;i++) ans1+=A[i][k];for(int i=1;i<=n;i++) ans2+=B[k][i];	ans+=ans1*ans2;}return ans;
}

然后就继续 T L E TLE TLE,显然上述做法复杂度是 O ( m ? n 2 ) O(m*n^2) O(m?n2),不可行
我们考虑对上述做法进行优化,我们发现通过预处理前缀和可以实现:
∑ i = a c A i , k = s u m c , k ? s u m a ? 1 , k ∑ j = b d B k , j = s u m k , d ? s u m k , b ? 1 \sum\limits_{i=a}^{c}A_{i,k}=sum_{c,k}-sum_{a-1,k}\ \sum\limits_{j=b}^{d}B_{k,j}=sum_{k,d}-sum_{k,b-1} i=ac?Ai,k?=sumc,k??suma?1,k? j=bd?Bk,j?=sumk,d??sumk,b?1?
将这个求和符号优化掉之后,复杂度为: O ( m ? n ) O(m*n) O(m?n),可行

C o d e : Code: Code

#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e3+10,mod=1e9+7;
int n,m,a,b,c,d,A[N][N],B[N][N],sum1[N][N],sum2[N][N];
template<class T>
void read(T &x){
    x=0; char c; int sign=1;do{
     c=getchar(); if(c=='-') sign=-1;}while(!isdigit(c));do{
     x=x*10+c-'0',c=getchar();}while(isdigit(c));x*=sign;
}
ll query(int a,int b,int c,int d){
    ll ans=0;for(int k=1;k<=n;k++){
    ll ans1=sum1[c][k]-sum1[a-1][k];ll ans2=sum2[k][d]-sum2[k][b-1];	ans+=ans1*ans2;}return ans;
}
int main(){
    read(n),read(m);for(int i=1;i<=n;i++){
    for(int j=1;j<=n;j++){
    read(A[i][j]);}}for(int i=1;i<=n;i++){
    for(int j=1;j<=n;j++){
    read(B[i][j]);}}for(int k=1;k<=n;k++){
    for(int i=1;i<=n;i++) sum1[i][k]=sum1[i-1][k]+A[i][k];for(int i=1;i<=n;i++) sum2[k][i]=sum2[k][i-1]+B[k][i];}while(m--){
    read(a),read(b),read(c),read(d);if(a>c)swap(a,c);if(b>d)swap(b,d);printf("%lld\n",query(a,b,c,d));}return 0;
}
  相关解决方案