暑假7.29 Test

似乎是打表+暴力专场,可惜我什么规律也找不出来,一题模拟乱搞,二三题神仙打表。

T1懒得写题面了 一句话题意,就是问你在一个n*m的01矩阵中有多少个k*k的子矩阵包含1

正解二维前缀和,考试的时候我想的是暴力模拟,把所有子矩阵扫一遍,打标记就得了。暴力模拟也挺好做,虽然自己造的大数据炸掉了,但是交上去手动开O2+读优就可以艹过去。复杂度O(n*m)对于这道题足够了。

代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=1550;
inline void read(int &re)
{
    char ch;
    while((ch=getchar())<'0'||ch>'1');
    re=ch-48;
}
int n,m,k;
int jz;
int sx,sy,ex,ey;
long long tot;
long long spe;
int x[N],y[N];
int cnt;
int flag1[N][N];
int flag2[N][N];
int main(){
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    for(register int i=1;i<=n;i++){
        for(register int j=1;j<=m;j++){
            read(jz);//一定要读优
            if(jz==1){
                spe++;
                x[++cnt]=j;
                y[cnt]=i;
            }
        }
    }
    if(k==1){//等于1直接输出
        printf("%lld\n",spe);
        return 0;
    }
    sx=1,sy=1,ex=k,ey=k;
    while(ex<=m&&ey<=n){
        for(register int i=1;i<=cnt;i++){
            if(x[i]>=sx&&y[i]>=sy&&x[i]<=ex&&y[i]<=ey&&((!flag1[sx][sy])||(!flag2[ex][ey]))){//在范围内
                tot++;
                if(!flag1[sx][sy]) flag1[sx][sy]=1;//打标记
                if(!flag2[ex][ey]) flag2[ex][ey]=1;
            }
        }
        sx+=1;
        ex+=1;
        if(sx>m-k+1){//扫下一行
            sx=1;
            ex=k;
            sy+=1;
            ey+=1;
        }
    }
    printf("%lld\n",tot);
    return 0;
} 
View Code

不敢保证是完全正确的,给出std:

#include <bits/stdc++.h>
using namespace std;
const int N = 1033;
char s[N][N];
int n, m, k, a[N][N];
int main() {
    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout);
  scanf("%d%d%d", &n, &m, &k);
  for (int i = 1; i <= n; i++) {
    scanf("%s", s[i] + 1);
  }
  int all = (n + 1 - k) * (m + 1 - k);
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      if (s[i][j] == '1') {
        a[i][j] = 0;
      } else {
        a[i][j] = min(a[i - 1][j - 1], min(a[i - 1][j], a[i][j - 1])) + 1;
      }
      if (a[i][j] >= k) {
        all--;
      }
    }
  }
  printf("%d\n", all);
}
View Code

T2 就是问你1-n中约数的约数个数和最大的数是谁 打表可做,不过n的范围过大。而且我巨臭的打表只能打前两个点。题解如下:

std:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int pri[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
ll n, coef, cur, ans, ans2;

void dfs(int p, ll cur, ll coef, int last) {
  assert(cur > 0 && coef > 0);
  if (coef > ans) {
    ans = coef;
    ans2 = cur;
  } else if (coef == ans) {
    ans2 = min(ans2, cur);
  }
  for (int i = 1; i <= last && cur <= n / pri[p] && cur * pri[p] <= n; i++) {
    cur *= pri[p];
    dfs(p + 1, cur, coef * ((i + 2) * (i + 1) / 2), i);
  }
}

int main() {
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
  scanf("%lld", &n);
  dfs(0, 1, 1, 999);
  printf("%lld\n%lld\n", ans2, ans);
}
View Code

T3 先给出递推式,不过面对如此大的数据范围递推也没办法,正解是真的神仙,几个位运算判断一波就搞了,%%%%%

std:

#include <bits/stdc++.h>
using namespace std;
int n;
long long f0, f1;
int main() {
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
  scanf("%d", &n);
  int tg = 0;
  for (int i = 30; ~i; i--) {
    if (tg) {
      if ((n >> i) & 1) {
        f0 = f0 * 3 + f1 * 2 + 1;
      } else {
        f0 = f0 * 3 + 1;
        f1 = f1 * 2;
      }
    } else if ((n >> i) & 1) {
      tg = 1;
      f1++;
    }
  }
  printf("%lld\n", (f0 + f1) * 2 + 1);
}
View Code

%%%%% deco&sxk dalao 300pts AK

猜你喜欢

转载自www.cnblogs.com/LJB666/p/11266547.html