9月13日模擬賽
阿新 • • 發佈:2021-09-13
考試
,求出兩個值:
\[q_0= \sum ^{i} R_i \; (1\leq i\leq n,k_i \mod 2=0,a_i=1)
\]
\[
\]
前言
A. [2019.10長郡集訓day12]古代龍人的謎題
題目
思路
把這個 \(01\) 序列稱為序列 \(a\) 。那麼可以觀察到,答案的貢獻來源於兩個部分:
-
對於合法區間 \([a_i,a_j]\) , \(a_i,a_j\) 為 \(1\) 。稱其為基本的區間。
-
由基本區間向外擴充套件得到的區間。
-
兩面包夾芝士,由一堆 \(0\) 包圍的 \(1\)
三種情況如圖:
對於以上三種情況,處理出每個 \(1\) 到前一個 \(1\) 中間有多少個 \(0\) (記做 \(L\)) ,再處理出每個 \(1\) 到後一個 \(1\) 中間有多少個 \(0\) (記做 \(R\)),就可以解決 情況三 。在解決 情況一 的基礎上就可以解決 情況二 。
根據乘法原理(\(n,m\)的意義如圖):
情況三的貢獻為: \(n\times m\)
情況二的貢獻為:\((n+1)\times (m+1)\)
現在考慮怎麼解決情況一,只考慮左右端點皆為 \(1\) 的情況:
假設序列 \(a\) (黑色部分)如下:
把所有的 \(1\) 按照從左到右的順序排號,對於 \(a_i\) 稱它的序號為 \(k_i\) 。(紅色部分)
有一條顯而易見的結論是一個合法的區間中,\(1\) 的個數是奇數。
假設有一個合法區間 \([a_i,a_j]\) 那麼,\(k_i\) 和 \(k_j\) 的奇偶性是相同的。
對於這一點,預處理出每個 \(a_i=1\) 的 \(R_i\)
和
\[q_1= \sum ^{i} R_i \; (1\leq i\leq n,k_i \mod 2=1,a_i=1) \]這兩個值的作用馬上揭曉。
對於序列 \(a\) 中的每個 \(1\) ,嘗試計算(它作為左端點的貢獻(情況一二) \(+\) 它在情況三下的貢獻)
於是有(假設這個數為 \(a_i\), \(VAL_{i,j}\) 表示區間\([a_i,a_j]\) 的貢獻 ):
\[VAL_{i,j}=(L_i+1)\times(R_j+1)+(L_i\times R_i) \]那麼他的總貢獻為:
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+105;
int opt,n,cnt1,a[N],r[N],q0,q1,ans;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
inline int spread(){
int x=0;char ch=getchar();
while(!isdigit(ch)){ch=getchar();}
if(isdigit(ch))x=ch-'0';
return x;
}
signed main(){
opt=read();
if(opt>=0){
n=read();
for(int i=1;i<=n;i++)a[i]=spread(),cnt1+=a[i];
int k=cnt1;
for(int i=n,j=0;i>=1;i--){j++;if(a[i]==1){r[k--]=j;j=0;}}
for(int i=1;i<=cnt1;i++){if(i%2==0) q0+=r[i];else q1+=r[i];}
k=1;
for(int i=1,j=0;i<=n;i++){
j++;
if(a[i]==1)
if(k%2==0)
{ans+=(j-1)*(r[k]-1)+j*(q0-r[k]);q0-=r[k];k++;j=0;}
else
{ans+=(j-1)*(r[k]-1)+j*(q1-r[k]);q1-=r[k];k++;j=0;}
}
printf("%lld",ans);
}
return 0;
}
我講得真的很清楚,真的……