原 2019牛客暑期多校训练营(第二场)补题记录

总结

自闭场,A、B、F题都没肝出来。今天重感冒,状态不好,烦!
直接开始补题吧。

A:Eddy Walker

先去开的它,在开题20分钟左右就去写了一个打表的dfs,根据每个数的位置出现的比例与N,M的关系应该可以推出这道题。怎料!这个dfs的算法跑当N>=3的就能跑爆,擦…所以我们增加一个二叉树深度判定,当我们深度大于等于30(最差复杂度为2^30,可以跑一跑)。这里给出暴力的测试,当N在2,3,4跑出来的值,大约能判定出0之外其他点的概率是均分(即1/n-1)的。

#include<cstdio>
using namespace std;

int cur[10] = {0};
int vis[10] = {0};
int n;
//const int MAX_kase = 4000000; //最多跑到多少,dfs就要结束,以免递归栈溢出。
int cntx = 0;
void dfs(int cnt,int ind,int deep)      //deep代表递归深度,预测二叉树30层可以接受
{
    //printf("%d ",++kase);
    /*
    cntx++;
    if(cntx>=MAX_kase){
        return;
    }*/
    if(deep>=30) return;
    if(cnt>=n){
        cur[ind]++;
        return ;
    }
    int dx=((ind-1)+n)%n,dy=((ind+1)+n)%n;
    if(!vis[dx]){
        vis[dx]=1;
        dfs(cnt+1,dx,deep+1);
        vis[dx]=0;
    }
    else dfs(cnt,dx,deep+1);
    if(!vis[dy]){
        vis[dy]=1;
        dfs(cnt+1,dy,deep+1);
        vis[dy]=0;
    }
    else dfs(cnt,dy,deep+1);
}

int main()
{
    vis[0] = 1;
    n = 4;
    dfs(1,0,0);
    for(int i=0;i<n;i++){
        printf("%d ",cur[i]);
    }
    return 0;
}

记得特判,N=1时概率为1,N!=1&&M=0概率为0。
所以A题正解:

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

ll inv(ll a)
{
    if(a == 1)
        return 1;
    return inv(MOD%a)*(MOD-MOD/a)%MOD;
}

int main(){
    ll N,M,T,ans;
    scanf("%lld",&T);
    while (T--){
        scanf("%lld%lld",&N,&M);
        ans = 1;
        if (N==1){
            printf("%lld\n",ans);
        } else {
            if (M==0) ans=0;
            else ans=inv(N-1)%MOD;
            printf("%lld\n",ans);
        }
    }
    return 0;
}

B:Eddy Walker 2

递推铁超时…知道了一个新名词,线性代换。
没听懂讲的是什么,可能类似于待定系数求参数吧…
先贴上代码,以后学习(同时测试了一下,递归求inv比费马小定理慢…超时的话考虑上个非递归版的)

#include <bits/stdc++.h>
using namespace std;
constexpr int N = 2048;
constexpr int mod = 1e9 + 7;
constexpr int MOD = 1e9 + 7;
typedef long long LL;
typedef long long ll;
inline int add(int a, int b) {
  a += b;
  return a >= mod ? a - mod : a;
}
inline int sub(int a, int b) {
  a -= b;
  return a < 0 ? a + mod : a;
}
inline int mul(LL a, int b) {
  a *= b;
  return a >= mod ? a % mod : a;
}
inline int mpow(int a, int b) {
  int r = 1;
  while (b) {
    if (b & 1) {
      r = mul(r, a);
    }
    a = mul(a, a);
    b >>= 1;
  }
  return r;
}
inline int inv(int x) {
  return mpow(x, mod - 2);
}

LL n , m, ik;
constexpr int MAX_N = 1024;
ll dp[MAX_N<<1];

inline void pre_dp() {
  LL bdr = min(n + n , m);
  dp[0] = 1;
  for(ll i = 1; i <= bdr; i++) {
    dp[i] = 0LL;
    for (int j = 1 ; j <= n; ++j) {
      if (i - j < 0 ) break;
      dp[i] = (dp[i] + dp[i - j] * ik % MOD) % MOD;
    }
  }
}
inline vector<ll> mul(vector<ll>& v1 , vector<ll>& v2) {
  int sz1 = (int)v1.size();
  int sz2 = (int)v2.size();
  vector<ll> _v(n + n);
  for(int i = 0; i < n + n; i++) _v[i] = 0;
  // expand
  for(int i = 0; i < sz1; i++) {
    for(int j = 0; j < sz2; j++) {
      (_v[i + j + 1] += v1[i] * v2[j] % MOD) %= MOD;
    }
  }
  // shrink
  for(int i = 0; i < n; i++) {
    for(int j = 1; j <= n; j++) {
      (_v[i + j] += _v[i] * ik) %= MOD;
    }
  }
  for(int i = 0; i < n; i++) _v[i] = _v[i + n];
  _v.resize(n);
  return _v;
}
vector<ll> I , A;
inline ll solve() {
  pre_dp();
  if(m <= n + n) return dp[m];
  I.resize(n);
  A.resize(n);
  for(int i = 0; i < n; i++) {
    I[i] = ik;
    A[i] = ik;
  }
  // dp[m] = /Sum_{i=0}^{n-1} A_i * dp[m - i - 1]
  ll dlt = (m - n) / n;
  ll rdlt = dlt * n;
  while(dlt) {
    if(dlt & 1LL) I = mul(I , A);
    A = mul(A , A);
    dlt >>= 1LL;
  }
  ll ans = 0;
  for(int i = 0; i < n; i++) {
    (ans += I[i] * dp[m - i - 1 - rdlt] % MOD) %= MOD;
  }
  return ans;
}

int main() {
  LL n_, k_;
  int t; cin >> t; while (t--) {
    cin >> k_ >> n_;
    n = k_;
    m = n_;
    ik = inv(k_);
    ll ans;
    if (n_ == -1) {
      ans = mul(2, inv(k_ + 1));
    } else {
      ans = solve();
    }
    printf("%lld\n", ans);
  }
}

H:Second Large Rectangle

摘到了RANK1的最大子矩阵的模板。
以后使用的时候修改输入输出,以及work就行。

#include<bits/stdc++.h>
#define F first
#define S second
using namespace std;
typedef pair<int,int> pi;
pi h[1005];
int a[1005][1005],n,m,mx1,mx2,pre[1005],sz[1005],vis[1005],t[1005][1005];
char s[1005];

void work(int x){
    if (mx1<x) mx2=mx1,mx1=x;
    else if (mx2<x) mx2=x;
}

int ffind(int x){
    if (pre[x]==x) return x;
    pre[x]=ffind(pre[x]);
    return pre[x];
}

void _union(int x,int y){
    pre[y]=x;
    sz[x]+=sz[y];
}

void Y_axis_algorithm()
{
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            t[i][j]=(a[i][j]==1)?t[i-1][j]+1:0;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++) vis[j]=0,pre[j]=j,sz[j]=1,h[j]=(pi){t[i][j],j};
        sort(h+1,h+m+1);
        for (int j=m;j;j--){
            int x=h[j].S; vis[x]=1;
            if (vis[x-1]) _union(ffind(x-1),ffind(x));
            if (vis[x+1]) _union(ffind(x),ffind(x+1));
            int len=sz[ffind(x)];
            work(len*h[j].F);
            work(len*(h[j].F-1));
            work((len-1)*h[j].F);
        }
    }
}

void scan()
{
    cin >> n >> m;
    for (int i=1;i<=n;i++){
        cin >> s+1;
        for (int j=1;j<=m;j++) a[i][j]=(s[j]=='0')?0:1;
    }
}

void print()
{
    cout << mx2 << endl;
}

int main(){
    scan();
    Y_axis_algorithm();
    print();

    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值