G.Snake Rana
题意: 给出一张 n ∗ m n*m n∗m的地图和 k k k个点,求不包含这些点的所有子矩形。
分析: 先求出 n ∗ m n*m n∗m的所有子矩形,再根据容斥原理减去所有包含这 k k k个点的所有不合法的子矩形。
在一个 n ∗ m n*m n∗m的矩形中,长为 m m m,宽为 n n n,横向长度为 1 1 1的子矩形可以有 m m m种选法,长度为 2 2 2的子矩形可以有 m − 1 m-1 m−1种选法,以此类推,那么横向则有 m + ( m − 1 ) + ( m − 2 ) + ⋯ + 1 = n ∗ ( n + 1 ) 2 m+(m-1)+(m-2)+\cdots+1=\frac{n*(n+1)}{2} m+(m−1)+(m−2)+⋯+1=2n∗(n+1)种选法,纵向则有 n + ( n − 1 ) + ( n − 2 ) + ⋯ + 1 = m ∗ ( m + 1 ) 2 n+(n-1)+(n-2)+\cdots+1=\frac{m*(m+1)}{2} n+(n−1)+(n−2)+⋯+1=2m∗(m+1)种选法,根据乘法计数原理,总数就为 n ∗ ( n + 1 ) ∗ m ∗ ( m + 1 ) 4 \frac{n*(n+1)*m*(m+1)}{4} 4n∗(n+1)∗m∗(m+1)
设每个不合法的所有子矩形的集合为 A 1 , A 2 , A 3 , ⋯ , A k A_1,A_2,A_3,\cdots,A_k A1,A2,A3,⋯,Ak
根据容斥原理,最终结果为
n ∗ ( n + 1 ) ∗ m ∗ ( m + 1 ) 4 − ∑ i = 1 k ∣ A i ∣ + ∑ 1 ≤ i < j ≤ k ∣ A i ∩ A j ∣ − ∑ 1 ≤ i < j < l ≤ k ∣ A i ∩ A j ∩ A l ∣ + ⋯ + ( − 1 ) k + 1 ∣ A 1 ∩ A 2 ∩ ⋯ ∩ A k ∣ \frac{n*(n+1)*m*(m+1)}{4}-\sum_{i=1}^{k} |A_i|+\sum_{1\le i< j\le k}^{}|A_i\cap A_j|-\sum_{1\le i< j< l\le k}^{}|A_i\cap A_j\cap A_l|+\cdots+(-1)^{k+1}|A_1\cap A_2 \cap \cdots \cap A_k| 4n∗(n+1)∗m∗(m+1)−i=1∑k∣Ai∣+1≤i<j≤k∑∣Ai∩Aj∣−1≤i<j<l≤k∑∣Ai∩Aj∩Al∣+⋯+(−1)k+1∣A1∩A2∩⋯∩Ak∣
那么如何求 A 1 , A 2 , A 3 , ⋯ , A k A_1,A_2,A_3,\cdots,A_k A1,A2,A3,⋯,Ak的个数?
在 n ∗ m n*m n∗m的矩形中,假设在枚举过程中从 k k k个点中选了 i i i个点,那么可以求出这 i i i个点围成的最小子矩形,进而求出所有包含这个最小子矩形的子矩形,计算方法是枚举所有在这个最小子矩形之外的点,设最小子矩形的两个点坐标为 ( m i n x , m i n y ) , ( m a x x , m a x y ) (minx,miny),(maxx,maxy) (minx,miny),(maxx,maxy),那么所有选法方案为 m i n x ∗ m i n y ∗ ( n − m a x x − 1 ) ( m − m a x y − 1 ) minx*miny*(n-maxx-1)(m-maxy-1) minx∗miny∗(n−maxx−1)(m−maxy−1)
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int t,inf=1e9;
long long int n,m,k,x[N],y[N];
int main(){
cin>>t;
while(t--){
cin>>n>>m>>k;
for(int i=0;i<k;i++) cin>>x[i]>>y[i];
long long int ans=n*(n+1)/2*m*(m+1)/2;
for(int i=1;i<1<<k;i++){
long long int minx=inf,miny=inf,maxx=-1,maxy=-1;
int cnt=0;
for(int j=0;j<k;j++){
if(i>>j&1){
minx=min(minx,x[j]);
miny=min(miny,y[j]);
maxx=max(maxx,x[j]);
maxy=max(maxy,y[j]);
cnt++;
}
}
long long int res=minx*miny*(n-maxx+1)*(m-maxy+1);
if(cnt&1) ans-=res;
else ans+=res;
}
cout<<ans<<endl;
}
}
I.Mirrored String II
题意: 给定一个长度不超过 1000 1000 1000的字符串,求出只包含 A , H , I , M , O , T , U , V , W , X , Y {A, H, I, M, O, T, U, V, W, X, Y} A,H,I,M,O,T,U,V,W,X,Y的最长回文子串
分析: 首先想到的是马拉车算法,但是一看长度为 1000 1000 1000,暴力就可以做。思路是先把不合法的字符串设为#,到时候特判一下就可以,把奇回文串和偶回文串的最大长度分别求出取 m a x max max就是答案
代码:
#include<bits/stdc++.h>
using namespace std;
string a;
int t;
int main(){
cin>>t;
while(t--){
cin>>a;
for(int i=0;i<a.size();i++){
if(a[i]!='A'&&a[i]!='H'&&a[i]!='I'&&a[i]!='M'&&a[i]!='O'&&a[i]!='T'&&a[i]!='U'&&a[i]!='V'&&a[i]!='W'&&a[i]!='X'&&a[i]!='Y'){
a[i]='#';
}
}
int res=0;
for(int i=0;i<a.size();i++){
if(a[i]=='#') continue;
int cnt=1,m=i,n=i;
while(m-1>=0&&n+1<a.size()&&a[m-1]==a[n+1]&&a[m-1]!='#'&&a[n+1]!='#'){
cnt+=2;
m--,n++;
}
res=max(res,cnt);
}
for(int i=0,j=1;j<a.size();j++,i++){
if(a[i]=='#'||a[j]=='#') continue;
int cnt=2,m=i,n=j;
if(a[m]!=a[n]) continue;
while(m-1>=0&&n+1<a.size()&&a[m-1]==a[n+1]&&a[m-1]!='#'&&a[n+1]!='#'){
cnt+=2;
m--,n++;
}
res=max(res,cnt);
}
cout<<res<<endl;
}
}