Codeforces Round #817 (Div. 4) E、F、G

目录

​​​​​​​Problem - E - Codeforces    二维数组的前缀和

Problem - F - Codeforces     DFS

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值