目录
Problem - E - Codeforces 二维数组的前缀和
Problem - G - Codeforces 按位与的结论特点
Problem - E - Codeforces 二维数组的前缀和
大意:对于每个询问给出了两个矩形(一大一小,小的那个会被大的完全包含住),找到给出的n个矩形中能包含小矩形又能被大矩形包含的矩形(边重合不算包含),求出所有满足情况的矩形的和。
那么很容易我们就可以知道满足题意的矩形应该是红色的那一块,也就是(wb,hb)与(ws,hs)之间的部分,这很明显就是一个二维前缀和的差分的板子了。
1、因为我们最后要求所有满足题意的矩形的面积和,所以用一个二维数组a存储宽为w,高为h的矩形的面积和。
2、再用一个二维数组pre记录前缀和(板子)。
pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+a[i][j];
3、最后根据询问去计算它对应的前缀和的差分(板子)。
pre[wb-1][hb-1]-pre[ws][hb-1]-pre[wb-1][hs]+pre[ws][hs];
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll a[1005][1005];
ll pre[1005][1005];
void solve(){
ll n,q,i,hs,ws,hb,wb,h,w,j;
cin>>n>>q;
memset(a,0,sizeof(a));
for(i=0;i<n;i++){
cin>>h>>w;
a[w][h]+=w*h;
}
//求二维前缀和数组
for(i=1;i<=1000;i++){
for(j=1;j<=1000;j++){
pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+a[i][j];
}
}
//求二维前缀和数组的差分
for(i=0;i<q;i++){
cin>>hs>>ws>>hb>>wb;
cout<<pre[wb-1][hb-1]-pre[ws][hb-1]-pre[wb-1][hs]+pre[ws][hs]<<endl;
}
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
Problem - F - Codeforces DFS
大意:判断给出的测试样例是否符合题意:连接起来的*可以组成‘L’型、每个‘L’型之间不会相邻(相邻不仅仅是上下左右,而是周围一圈8个位置)。
很明显,此题想到用DFS可以解决,最直观的想法就是在找到一个*后,DFS去遍历它周围的八个元素,找到*继续递归DFS,那么我们就可以知道最初的那个*周围有几个*,一旦超过了3个,那么就说明周围一定会有‘L’型是相邻的,那么就不符合题意了;如果没有达到3个,说明根本就没有形成‘L’型;本以为这样就可以,但是看第三个测试样例,*确实达到了3个,但它没有组成‘L’型,所以也不符合题意;所以在*达到3个时,不能直接得结论,还要进一步去判断它们3个到底是不是‘L’型。
那么我们就可以在DFS的时候专门用一个pair数组去存储*的坐标,在*达到3个的时候,通过这个pair数组去判断它们有没有形成‘L’,我们可以发现:‘L’型各个*的横坐标之间的差值均不超过1,纵坐标也是,像样例3,第一个*与第三个*的纵坐标之间就相差了2,所以我们就可以完成判断了。
#include<bits/stdc++.h>
using namespace std;
string s[55];
int n,m,sum=0;
int des[8][2]={0,1,0,-1,-1,0,1,0,1,1,1,-1,-1,-1,-1,1};
pair<int,int>c[3];
//判断有无相邻
bool dfs(int x,int y){
s[x][y]='.';
sum++;
if(sum>3){
return false;
}
c[sum-1].first=x;
c[sum-1].second=y;
int k,nx,ny;
for(k=0;k<8;k++){
nx=x+des[k][0];
ny=y+des[k][1];
if(nx>=0&&nx<n&&ny>=0&&ny<m){
if(s[nx][ny]=='*'){
dfs(nx,ny);
}
if(sum>3) return false;
}
}
return true;
}
//判断是否是L
bool checkL(){
int i,j;
for(i=0;i<3;i++){
for(j=i+1;j<3;j++){
if(abs(c[i].first-c[j].first)>1||abs(c[i].second-c[j].second)>1){
return false;
}
}
}
return true;
}
void solve(){
int i,j,k;
cin>>n>>m;
for(i=0;i<n;i++){
cin>>s[i];
}
for(i=0;i<n;i++){
for(j=0;j<m;j++){
if(s[i][j]=='*'){
sum=0;
if(!dfs(i,j)||sum<3||!checkL()){
cout<<"NO"<<endl;
return;
}
}
}
}
cout<<"YES"<<endl;
}
int main(){
ios::sync_with_stdio(false);
cout.tie(0);cin.tie(0);
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
Problem - G - Codeforces 按位与的结论特点
大意:给出n个数,让所有奇数位的数的按位与和所有偶数位的数的按位与相同。
我们多写几个连续的数的二进制形式,并对它们做按位与,我们可以发现每四个连续的数(从0开始)的按位与最后一定等于0。
4k⊕4k+1⊕4k+2⊕4k+3=0,
因为x⊕x=0
所以4k,4k+1,4k+2,4k+3任选几个数,剩下没选的数的按位与一定和所选的数的按位与相同。
按本题奇数位与偶数位的要求,所以我们选择4k⊕4k+2=4k+1⊕4k+3。
我们要让它们不断添这样的4个数,所以分四种情况,n%4=0,n%4=1,n%4=2,n%4=3。
题目中已经给出了n=4,n=5,n=6,n=3,所以我们只需要在n对应情况下不断往后添这样的4个数,由于每个数均不同,我们这里任选k=25,从100开始往后补,直至数目达到n个。
#include<bits/stdc++.h>
using namespace std;
vector<vector<int>>v={{2, 1, 3, 0},
{2,0,4,5,3},
{4,1,2,12,3,8},
{2,1,3}};
void solve(){
int n,i;
cin>>n;
int k=n%4,sum=0;
for(i=0;i<v[k].size();i++){
cout<<v[k][i]<<' ';
}
while(sum!=n-v[k].size()){
cout<<100+sum<<' ';
sum++;
}
cout<<endl;
}
int main(){
ios::sync_with_stdio(false);
cout.tie(0);cin.tie(0);
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}