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

E. Counting Rectangles

标签:二维前缀和

题意:

  • 给出n个长方形的长和宽,q次询问 (1≤n≤1e5; 1≤q≤1e5)
  • 每次询问给出两个长方形A,B的长和宽(1<=x<=1000)
  • 遍历前n个长方形,若长方形A能含于该长方形且该长方形能含于长方体B中, ans += 该长方体面积
  • 返回ans

思路:

(nq)一定超时,暴力不行,考虑到长宽较小,采用二维前缀和来写就行
怎么写二维前缀和?把它当作面积来转移就好

代码:

#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#define ll long long 
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
const int mod=1e9+7;
ll sum[1005][1005],a[1005][1005]; 
void solve(){
    int n,q;
    cin>>n>>q;
    memset(a,0,sizeof(a));
    int x,y;
    for(int i=1;i<=n;i++){
        cin>>x>>y;
        a[x][y] += x*y;
    }
    for(int i=1;i<=1000;i++){
        for(int j=1;j<=1000;j++){
            sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i][j];
        }
    }
    int a,b,c,d;
    while(q--){
        cin>>a>>b>>c>>d;
        if(a>=c||b>=d) cout<<"0"<<le;
        else cout<<sum[c-1][d-1]-sum[c-1][b]-sum[a][d-1]+sum[a][b]<<le;
        //宽小于等于a,长小于等于b的都不能取到
    }
}

int main() {
    int t; cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

F. L-shapes

标签:暴力 模拟

题意:

  • 给出n行m列的矩阵,*表示有方格,.表示空着
  • 2*2的矩阵,若有三个方格,则成为L形
  • 若矩阵中只有L型且L型之间不共享边不共享角,或者为空, 则输出YES,反之则NO
  • 请添加图片描述

思路:

这题我看标签里有dfs,但其实可以直接暴力,因为矩阵挺小(5050)
首先通过遍历查2 * 2的格子,若有L型,判断是否与其他L型相接触,若不接触,则将L型的每个
赋值为’1‘,表示为已经访问过的L型,最后再扫一遍矩阵,看看有没有多余的*号

代码:

#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#define ll long long 
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
const int mod=1e9+7;
char a[55][55];

void solve(){
    int n,m;
    cin>>n>>m;
    memset(a,0,sizeof(a));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
    bool f1 = 1,f2 = 1;//f1表示是否只由L构成或者为空,f2表示是否存在不合法的L
    int cnt;
    for(int i =1;i<=n-1;i++){
        for(int j=1;j<=m-1;j++){
            cnt = 0;
            if(a[i][j]=='*') cnt++;
            if(a[i+1][j+1]=='*') cnt++;
            if(a[i][j+1]=='*') cnt++;
            if(a[i+1][j]=='*') cnt++;
            if(cnt==3){
                for(int x=i;x<=i+1;x++){
                    for(int y=j;y<=j+1;y++){
                        if(a[x][y]=='*'){
                            for(int u=x-1;u<=x+1;u++){
                                for(int v=y-1;v<=y+1;v++){
                                    if(a[u][v]=='1') f2 = 0;//查该方格一圈有无其他L
                                }
                            }
                        }
                    }
                }

                if(f2){
                    for(int x=i;x<=i+1;x++){
                        for(int y=j;y<=j+1;y++){
                            if(a[x][y]=='*') a[x][y] = '1';
                        }
                    }  
                }    
            }

            if(cnt==4){
                f2 = 0;
            }
        }
    }

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i][j]=='*') f1 = 0;
        }
    }

    if(f1&&f2) cout<<"YES"<<le;
    else cout<<"NO"<<le;
}
int main() {
    fst;
    int t; cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

G. Even-Odd XOR

标签:构造

题意:

  • 给出一个n,让你构造一个数列,要求数列中的数个不行同,且所有奇数位异或运算结果和偶数为相同

思路:

一眼丁真,鉴定为构造题,主要难的地方在于找出规律
当k为4的倍数时 k & (k+3) == (k+1)&(k+2)
请添加图片描述
接着按模的结果分类讨论构造即可

代码:

#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#define ll long long 
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
const int mod=1e9+7;
 
void solve(){
	ll n;
	cin>>n;
	ll k=4;
	if(n%4==1){
		cout<<"0 ";
		n--;
	}
	else if(n%4==2){
		cout<<"4 1 2 12 3 8 ";//样例6
		n-=6;
		k=16;
	}
	else if(n%4==3){
		cout<<"1 3 2 ";
		n-=3;
	}
	while(n>0){
		cout<<k<<" "<<k+1<<" "<<k+3<<" "<<k+2<<" ";
		k+=4;
		n-=4;
	}
	cout<<le;
}


int main() {
    int t; cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值