BestCoder Round #36 HDU(5198 - 5201)

人生第一次ak了bc, 当然要写个题解装逼一下。。(其实是题水。。。)


Hdu 5198 Strang Class

水题。。 不过wa了两发。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <map>
using namespace std;

#define mxn 100020
#define LL long long
#define inf 0x3f3f3f3f
#define MP make_pair


char s[mxn];
int n;
bool check(int l, int r) {
    for(int i = l; i <= r; ++i)
        if(s[i] != s[l]) return 0;
    return 1;
}
int main() {
    while(scanf("%s", s + 1) != EOF) {
        n = strlen(s + 1);
        if(n % 3 != 0) {
            puts("NO");
            continue;
        }
        int x = n / 3 + 1;
        int y = n / 3 * 2 + 1;
        int z = n / 3;
        if(check(1, 1 + z - 1) && check(x, x + z - 1) && check(y, y + z - 1)) {
            if(s[1] != s[x] && s[1] != s[y] && s[x] != s[y])
                puts("YES");
            else
                puts("NO");
        }
        else
            puts("NO");
    }
    return 0;
}


Hdu 5199 Gunner

也是水题, 离散化一下, 再加个输入挂就ok了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <map>
using namespace std;

#define mxn 1000200
#define LL long long
#define inf 0x3f3f3f3f
#define MP make_pair


int n, m;
int a[mxn];

int readint() {
    char c;
    while((c = getchar()) && !(c >= '0' && c <= '9'));
    int ret = c - '0';
    while((c = getchar()) && (c >= '0' && c <= '9'))
        ret = ret * 10 + c - '0';
    return ret;
}
int san[mxn], cnt;
bool vis[mxn];

int f(int v) {
    int k = lower_bound(a + 1, a + n + 1, v) - a;
    if(k > n || a[k] != v)
        return 0;
    return 1;
}

int main() {
    while(scanf("%d%d", &n, &m) != EOF) {
        for(int i = 1; i <= n; ++i) a[i] = readint();
        memset(vis, 0, sizeof vis);
        sort(a + 1, a + n + 1);
        while(m--) {
            int v;
            v = readint();
            if(f(v) == 0) {
                puts("0");
                continue;
            }
            int p = lower_bound(a + 1, a + n + 1, v) - a;
            if(vis[p]) {
                puts("0");
                continue;
            }
            else {
                int y = upper_bound(a + 1, a + n + 1, v) - a;
                vis[p] = 1;
                printf("%d\n", y - p);
            }
        }
    }
    return 0;
}

Hdu 5200 Trees

题意:
给n个数, 树高为hi, q次询问, 每次询问把小于等于v的树都去掉, 剩下的树分成了几块。
思路:
正向处理的话用线段树是比较麻烦的, 但是如果离线的话, 按照询问从小到达来处理就比较容易。
把一个树去掉的话, 如果它的旁边没有树的话, 分块数要减少1, 如果有两棵树的话, 分块数加1, 否则不变。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <map>
using namespace std;

#define mxn 50020
#define LL long long
#define inf 0x3f3f3f3f
#define MP make_pair
#define ls (i << 1)
#define rs (ls | 1)
#define md ((ll + rr) >> 1)


struct query {
    int x, id, ans;
    bool operator < (const query &b) const {
        return x < b.x;
    }
}s[mxn];
bool cmp(query a, query b) {
    return a.id < b.id;
}
int n, q;
struct node {
    int h, p;
    bool operator < (const node &b) const {
        return h < b.h;
    }
}a[mxn];

bool c[mxn];

int main() {
    while(scanf("%d%d", &n, &q) != EOF) {
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a[i].h);
            a[i].p = i;
        }
        sort(a + 1, a + n + 1);
        for(int i = 1; i <= q; ++i) {
            scanf("%d", &s[i].x);
            s[i].id = i;
        }
        sort(s + 1, s + q + 1);
        int ans = 1;
        memset(c, true, sizeof c);
        int j = 1;
        for(int i = 1; i <= q; ++i) {
            while(j <= n && a[j].h <= s[i].x) {
                int h = a[j].p;
                int cnt = 0;
                if(h > 1 && c[h-1]) ++cnt;
                if(h < n && c[h+1]) ++cnt;
                if(cnt == 2) ++ans;
                else if(cnt == 0) --ans;
                c[h] = 0;
                ++j;
            }
            s[i].ans = ans;
        }
        sort(s + 1, s + q + 1, cmp);
        for(int i = 1; i <= q; ++i)
            printf("%d\n", s[i].ans);
    }
    return 0;
}

Hdu 5201 The Monkey King

题意:
要把n个桃子分给m个猴子, 其中第一个猴子的桃子要严格最多的, 问方案数。
思路:
可以枚举分多少个桃子给第一个猴子, 假设为x, 那么分给其他猴子的桃子假设为a[i], 那么
a[2] + a[3] + ... + a[m-1] = n - x, 如果没有限制的话, 答案就是f(n-x, m-1), f(x, y) 表示把x个桃子分给y个猴子的方案,显然f(x, y) = C(x + y - 1, x), C是组合数。
有限制的话, 可以根据容斥, 算出总的,然后减去1个猴子比第一个猴子的桃子多的方案,然后加上2个猴子比第一个猴子多的方案。。。
k个猴子比第一个猴子多的方案是C(m-1, k) * f(n - (k + 1) * x, m - 1)。
然后加起来就可以了。
刚开始sb了, 以为这么算复杂度是n^2。
其实每个x, 都是只有O(n/x)次计算的, 因为n - (k + 1) * x < 0时候就跳出循环, 所以复杂度和筛法那样。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <map>
using namespace std;

#define mxn 200020
#define LL long long
#define inf 0x3f3f3f3f
#define MP make_pair
#define ls (i << 1)
#define rs (ls | 1)
#define md ((ll + rr) >> 1)
#define mod 1000000007

LL fac[mxn], nfac[mxn];

LL qpow(LL x, int k) {
    LL ret = 1;
    while(k) {
        if(k & 1) ret = ret * x % mod;
        x = x * x % mod;
        k >>= 1;
    }
    return ret;
}
void init() {
    fac[0] = fac[1] = nfac[0] = nfac[1] = 1;
    for(int i = 2; i < mxn; ++i) {
        fac[i] = fac[i-1] * i % mod;
        nfac[i] = qpow(fac[i], mod - 2);
    }
}
int n, m;

LL C(int x, int y) {
    if(y < 0 || y > x) return 0;
    return fac[x] * nfac[y] % mod * nfac[x-y] % mod;
}
LL f(int r, int k) {
    return C(r + k - 1, r);
}
LL calc(LL x) {
    LL ret = 0;
    for(int k = 0; (k + 1) * x <= n; ++k) {
        LL t = C(m - 1, k) * f(n - (k + 1) * x, m - 1) % mod;
        if(k & 1)
            ret = ((ret - t) % mod + mod) % mod;
        else
            ret = (ret + t) % mod;
    }
    return ret;
}
int main() {
    init();
    int cas;
    scanf("%d", &cas);
    while(cas--) {
        scanf("%d%d", &n, &m);
        if(m == 1) {
            printf("%d\n", 1);
            continue;
        }
        int t = n / m;
        if(n % m == 0) ++t;
        else if(n % m != 1) t += 2;
        LL ans = 0;
        for(int i = max(1, t); i <= n; ++i) {
            ans = (ans + calc(i)) % mod;
        }
        printf("%I64d\n", ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值