Codeforces Round #626 B. Count Subrectangles(思维)

传送门

题意:

两个数组a,b(仅有0,1)一个整数k
c i , j = a i b j c_{i,j}=a_i*b_j
找出所有c矩阵的子矩阵的大小为k且里面的值都为1

思路:

很显然 a [ i ] = 0 a[i]=0 时,第i行的数全为 0 b [ i ] = 0 0,b[i]=0 时,第i列的数全为0
我们把 a , b a,b 数组处理一下,把连续的1放在一起,相当于把数组压缩一下
然后处理出来 k k 的因子
假设其中一对为 r , c r c = k r,c(r*c=k)
a r , f 1 我们看刚才压缩的a数组里面的值有几个大于r,假设f1个
b c , f 2 压缩的b数组里面的值有几个大于c,假设f2个
+ = f 1 f 2 结果+=f1*f2即可
看代码应该就懂了

我做的时候,压缩之后想着把所有的矩阵枚举出来,找符合组成大小为k的矩阵的个数
很明显会超时
那样是一个一个加的
实际应该就是上面的做法,找到相应的个数直接把f1*f2即可
在这里插入图片描述
如果我的想法的话需要,找 c n t 1 c n t 2 cnt1*cnt2 次,每次找到一个,刚找到6个
正确做法:找cnt1+cnt2次,列找到f1个,行找到f2个,找到 f 1 f 2 = 6 f1*f2=6

summary

虽然想到很简单,但我就是菜啊,菜哭了~~~~
对于矩阵,找到一段满足,往下一列(或者往右一行都应该满足)

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <map>
#include <queue>
#include <set>
#include <stack>
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
typedef long long ll;
using namespace std;
const int MAXN=4e4+50;
const int inf=0x3f3f3f3f;
const int M=5000*4;
int a[MAXN],b[MAXN];
int aa[MAXN],bb[MAXN],p[MAXN];
int n,m,k;
int cnt1=0,cnt2=0,cnt=0;
int cmp(int a,int b){
    return a>b;
}
ll solve(int r,int c){
    ll f1=0,f2=0;
    for(int i=1;i<=cnt1;i++)
        if(aa[i]>=r) f1++;
        else break;//因为排过序
    for(int i=1;i<=cnt2;i++)
        if(bb[i]>=c) f2++;
        else break;
    return f1*f2;
}
int main()
{

    cin>>n>>m>>k;

    int x=0;
    rep(i,1,n){
        scanf("%d",&a[i]);
        x+=a[i];
        if(a[i]==0){
            x=0;
            continue;
        }
        aa[++cnt1]=x;//对a的压缩,里面的是连续1的个数
    }
    x=0;
    rep(i,1,m){
        scanf("%d",&b[i]);
        x+=b[i];
        if(b[i]==0){
            x=0;
            continue;
        }
        bb[++cnt2]=x;
    }
    sort(aa+1,aa+cnt1+1,cmp);//从大到小排序
    sort(bb+1,bb+cnt2+1,cmp);
    if(cnt1==0||cnt2==0){
        cout<<0<<endl;
        return 0;
    }
    for(int i=1;i*i<=k;i++){//分解k的因子
        if(k%i==0)p[++cnt]=i;
    }
    ll ans=0;
    for(int i=1;i<=cnt;i++){
        int r=p[i],c=k/p[i];
        if(r==c)ans+=solve(r,c);//如果r==c,只能算一次,否则会算重复
        else ans+=solve(r,c)+solve(c,r);

    }
    printf("%lld\n",ans);
    return 0;
}
/*

*/
发布了158 篇原创文章 · 获赞 15 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44091178/article/details/104724297
今日推荐