ZROI week2

\[ZROI week2\]

除草机

首先考虑最少的拐点肯定是那种螺旋形状的,然后手玩几个数据发现和列数(行数)有关,且每增加1就是上一个状态加2,直接\(O(1)\)公式即可

吐槽:为啥\(n,m\)不给成\(10^{18}\)次方??

收集隔膜

一眼就能看出双向搜索,首先打了个暴力企图对拍,先交了上去,\(WA?\),发现和本地输出不一样,搞这个搞了半个小时还是没搞出为什么,然后我用其他的\(IDE\)测发现还是这个毛病,我的双向搜索就没敢交,也不知道改了哪里一个暴力就交过了。

最终得了60分。

  • 巧妙的思路:由于贡献是一定的,所以考虑预处理出贡献,一遍\(dfs\)即可。
  • 正解的思路:双向搜索,二分查找统计贡献。

翻转序列

想了一会儿想了个线段树的办法,然后疯狂写,一个半小时过去,死了

考虑一个对称中心\(T\),统计出至少多少个字母对称就会产生一个贡献,显然信息量是\(O(N)\)的,这个统计完了之后可以用线段树区间加和区间\(max\)去求解。

然后就死了

事实证明我的方法还是对的

正解就是把线段树统计换成一些奇奇怪怪的,例如前缀和一类的东西。

当我写到这个题已经没时间了(10min),想了一会儿想出了正解,对于每条边建立两个点,链内同向,链间反向,在\(LCA\)处统计贡献即可。

懒得写了

还是敲了一手暴力交了上去,本想再拿点分发现没时间了。

正解其实和我思路差不多,考虑把没有贡献的地方缩成一个点,然后快速幂计算即可。

总结与心得

会的总是拿不上分有点难受,希望下次更加努力。

作业

bzoj 4800

题目大意:有\(n\)个物品,\(m\)块钱,给定每个物品的价格,求买物品的方案数

范围:\(n \leq 40,m \leq 10^{18}\)

题解:

如果直接凑是\(2^{40}\)的复杂度,发现贡献是可以合并的,考虑双向搜索,每一半用\(2^{20}\)去搞,最后合并起来即可。

复杂度:\(O(2^{20} + 2^{20})\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 1e6 + 10;
ll a[50];
int lim;
int cnt1;
int cnt2;
ll A[MAXN];
ll B[MAXN];
int n;  
ll m;
ll ans;
int mid;

void dfs1(int now,ll sum) {
    if(now > mid) {
        A[++cnt1] = sum;
        return;
    }
    dfs1(now + 1,sum);
    if(sum + a[now] <= m) {
        dfs1(now + 1,sum + a[now]);
    }
}

void dfs2(int now,ll sum) {
    if(now > lim) {
        B[++cnt2] = sum;
        return;
    }
    dfs2(now + 1,sum);
    if(sum + a[now] <= m) {
        dfs2(now + 1,sum + a[now]);
    }
}

signed main () {
    scanf("%d %lld",&n,&m);
    for(int i = 1;i <= n; ++i) {
        scanf("%lld",&a[++lim]);
        if(a[lim] > m) --lim;
    }
    mid = lim >> 1;
    dfs1(1,0);
    dfs2(mid + 1,0);
    sort(A + 1,A + cnt1 + 1);
    sort(B + 1,B + cnt2 + 1);
    for(int i = 1,j = cnt2;i <= cnt1; ++i) {
        while(A[i] + B[j] > m and j) --j;
        if(j == 0) break;
        ans += j;
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/akoasm/p/10166948.html