有$𝑛$張卡片,每張卡片有正反兩面。正面和反面一共有$1, 2, ..,𝑚$這$𝑚$個數,有些數在正面,有些在反面,可是不會有數同時存在於兩個面。這$𝑛$張卡片排成一排,標號爲$1, 2, .., 𝑛$。c++
進行$𝑄$次詢問,每次給出兩個數$𝑙, 𝑟(𝑙 ≤ 𝑟)$,定義$𝑓(𝑙, 𝑟)$爲全部在第$𝑙, 𝑙 + 1, .., 𝑟$張卡片的正面出現過的數的平方和。你能夠隨意將卡片翻面,使得$𝑓(𝑙, 𝑟)$最大化,輸出這個值。git
首先若是每次都選擇佔沒被選中部分的一半以上的方案,至多 $log_{2}^{m}$ 次就能獲得全集。ide
全部當區間長度大於 $log_{2}^{m}$ 的時候直接獲得答案。spa
對於區間長度小的部分暴力求效率是 $O(m^{2}n)$ 。code
至少咱們發現對於一個數字若是不選,意味着全部包含這個數字的那面都得朝下,只有一種。因此咱們去看至少能有幾個數不選。總權值減去最小价值即爲答案。blog
#include<bits/stdc++.h> #define il inline #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=2e6+5; int n,m,Q,a[N],Lg; LL sum,val[N]; vector<int> v[N]; vector<LL> ans[N]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } int main() { n=read();m=read();Q=read();Lg=log2(m)+1; for(int i=1;i<=m;i++)sum+=1ll*i*i; for(int i=1;i<=n;i++){ v[i].resize(m+2); int x=read(); for(int j=1;j<=x;j++)v[i][read()]=1; } for(int l=1;l<=n;l++){ ans[l].resize(Lg+1); for(int i=1;i<=m;i++)a[i]=0; for(int r=l;r<=min(n,l+Lg);r++){ for(int i=1;i<=m;i++)a[i]=(a[i]<<1)|v[r][i],val[a[i]]+=1ll*i*i; LL res=sum; for(int i=0;i<(1<<(r-l+1));i++)res=min(res,val[i]),val[i]=0; ans[l][r-l]=sum-res; } } while(Q--){ int l=read(),r=read(); if(r-l+1>Lg)printf("%lld\n",sum); else printf("%lld\n",ans[l][r-l]); } return 0; }