[队内测试Day10.12]贪心+状压+分块+树状数组

T1

codevs2169零用钱

正解贪心。
在使用钞票最少前提下保证浪费的钱数最少
保证第一条,在还没达到规定钱数时尽可能使用大面值钞票
保证第二条,在现有钞票不满足要求前提下,尽量选面值小的放
综上,代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const int MAXN = 100000 + 50;
struct zt
{
    LL v,b;
}B[MAXN << 1];
int x,y,cnt,n,k,m;
int ans = 0;
bool cmp(zt a,zt b)
{
    return a.v > b.v;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i ++)
    {
        scanf("%d%d",&x,&y);
        if(x > m)ans += y;//面值大于指定钱数的钞票直接放
        else{
            B[++ cnt].v = x;
            B[cnt].b = y;
        }
    }
    sort(B + 1,B + cnt + 1,cmp);
    while(1)
    {
        k = m;
        for(int i = 1;i <= cnt;i ++)
        if(B[i].v <= k && B[i].b)
        {
            int t = min(B[i].b,k/B[i].v);
            B[i].b -= t;
            k -= t * B[i].v;
        }
        if(k > 0)
        {
            for(int i = cnt;i >= 1;i --)
            if(B[i].b && k > 0)
            {
                while(B[i].b && k > 0)
                {
                    k -= B[i].v;
                    B[i].b --;
                }
            }
        }
        if(k > 0)break;
        else ans ++;
    }
    printf("%d",ans);
}

T2

codevs2451互不侵犯
跟炮兵布阵那题好像……

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
#define LL long long
using namespace std;
const int MAXN = 1000 + 50;
#define INF 1061109567
int gs[MAXN],tot,n,K,num[MAXN];
bool check(int x)
{
    if((x << 1) & x)return false;
    return true;
}
void init(int n)
{
    for(int i = 0;i < (1 << n);i ++)
    {
        if(check(i))
        {
            gs[++ tot] = i;
            for(int j = 0;(1 << j) <= i;j ++)
            {
                if((1 << j) & i)num[tot] ++;
            }
        }
    }
}
LL dp[101][101][101];
long long ans;
int main()
{
    freopen("Fking.in","r",stdin);
    freopen("Fking.out","w",stdout);
    scanf("%d%d",&n,&K);
    init(n);
    for(int i = 2;i <= tot;i ++)
    {
        for(int j = 0;j <= K;j ++)
            dp[1][i][j] = -INF;
        dp[1][i][num[i]] = 1;
    }
    dp[1][1][0] = 1;
    for(int k = 2;k <= n;k ++)
    {
        for(int i = 1;i <= tot;i ++)
        {
            for(int j = 1;j <= tot;j ++)
            {
                if((gs[i] & (gs[j] << 1)) || (gs[i] & (gs[j] >> 1)) || (gs[i] & gs[j]))continue;
                for(int t = num[j];t <= K;t ++)
                {
                    //dp[k][j][t] = max(dp[k][j][t],dp[k - 1][i][t - num[j]] + 1);
                    if(dp[k - 1][i][t - num[j]] > 0)
                        dp[k][j][t] += dp[k - 1][i][t - num[j]];
                    //if(gs[j] == 0 && k == 2 && t == 1 && dp[k - 1][i][t - num[j]] == 1)printf("haha%d\n",gs[i]);
                }
            }
        }
    }
    for(int i = 1;i <= tot;i ++)
    if(dp[n][i][K] >= 0)
        ans += dp[n][i][K];
    /*for(int i = 1;i <= n;i ++)
    for(int j = 1;j <= tot;j ++)
    for(int k = 0;k <= K;k ++)
        printf("i=%d,j=%d,k=%d,dp=%d\n",i,gs[j],k,dp[i][j][k]);
    */
    printf("%lld",ans);
    return 0;
}

T3

某校模拟赛原创题,很好玩的数据结构

题面

有一个含有 n 个数字的序列 A, 元素标号 1 到 n。
同时你有 n 个函数,标号为 1 到 n。
第 i 个函数函数值为序列中下标为 Li 到 Ri 的元素和。
现在你需要维护以下两种操作 1 x y : 将序列中下标为 x 的元素修改为 y2
s t : 询问标号为 s 到 t 的函数值的和

输入

第一行一个正整数 n,表示序列和函数的个数。
接下来一行 n 个整数表示序列 A。
接下来 n 行,每行两个整数 Li, Ri,表示第 i 个函数
接下来一行一个整数 q,表示询问次数
下面 q 行,每行一个询问,格式如题面描述

输出

对于每个询问 2, 输出对应答案

样例输入

5
1 2 3 4 5
1 3
2 5
4 5
3 5
1 2
4
2 1 4
1 3 7
2 1 4
2 3 5

样例输出

41
53
28

正解:
树状数组维护原序列前缀和
对函数分块,预处理出每块中函数和以及所有数字在每块中被覆盖次数←差分实现
这样单点修改的时候就可以 delta*(覆盖次数) 的算出每个块的改变值了
还有单点修改树状数组
查询时对于区间完全覆盖的块直接处理
否则利用树状数组暴力求出每个块外函数的值
细节上挺难处理的……尤其是分块那部分……

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define LL unsigned long long
#define lowbit(w) (w & (-w))
using namespace std;
const int MAXN = 100000 + 50;
int n,q;
struct zt
{
    int l,r;
}f[MAXN];
int A[MAXN],x,y,ch;
struct kuai
{
    LL sum;
}B[MAXN];
int cf[350][MAXN];
int sz;
int belong[MAXN];
LL c[MAXN];
LL ask(int w)
{
    LL ans = 0;
    while(w)
    {
        ans += c[w];
        w -= lowbit(w);
    }
    return ans;
}
int num;
void add(int w,LL d)
{
    while(w <= n)
    {
        c[w] += d;
        w += lowbit(w);
    }
}
int main()
{
    freopen("sum.in","r",stdin);
    freopen("sum.out","w",stdout);
    scanf("%d",&n);
    for(int i = 1;i <= n;i ++)
    {
        scanf("%d",&A[i]);
    }
    for(int i = 1;i <= n;i ++)
    {
        scanf("%d%d",&f[i].l,&f[i].r);
    }
    sz = sqrt(n) + 1;
    num = (n - 1)/sz + 1;
    for(int i = 1;i <= n;i ++)
    {
        belong[i] = (i - 1)/sz + 1;
    }
    for(int i = 1;i <= n;i ++)c[i] = A[i];
    for(int i = 1;i <= n;i ++)
     if(i + lowbit(i) <= n)
        c[i + lowbit(i)] += c[i];
    for(int i = 1;i <= n;i ++)
    {
        cf[belong[i]][f[i].l] ++;
        cf[belong[i]][f[i].r + 1] --;
    }
    for(int i = 1;i <= num;i ++)
    {
        for(int j = 1;j <= n;j ++)
        {
            cf[i][j] += cf[i][j - 1];
            B[i].sum += cf[i][j] * 1ULL * A[j];//
        }
    }
    scanf("%d",&q);
    for(int iii = 1;iii <= q;iii ++)
    {
        scanf("%d%d%d",&ch,&x,&y);
        if(ch == 2)
        {
            int k1,k2;
            k1 = belong[x];k2 = belong[y];
            LL ans = 0;
            if(k1 == k2)
            {
                for(int i = x;i <= y;i ++)
                {
                    ans += ask(f[i].r) - ask(f[i].l - 1);
                }
            }
            else
            {
                for(int i = k1 + 1;i < k2;i ++)
                {
                    ans += B[i].sum;
                }
                int lim = sz * k1;
                lim = min(lim,y);
                for(int i = x;i <= lim;i ++)
                    ans += ask(f[i].r) - ask(f[i].l - 1);
                lim = (k2 - 1)*sz + 1;
                lim = max(lim,x);
                for(int i = lim;i <= y;i ++)
                {
                    ans += ask(f[i].r) - ask(f[i].l - 1);
                }
            }
            printf("%llu\n",ans);//
        }
        else
        {
            for(int i = 1;i <= num;i ++)
            {
                B[i].sum -= cf[i][x] * 1ULL * A[x];
                B[i].sum += cf[i][x] * 1ULL * y;
            }
            add(x,-A[x]);
            A[x] = y;
            add(x,A[x]);
        }
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

之前甚至听wyh大佬口胡过正解然而自己太辣鸡于是打次了……
这么辣鸡我怎么还不滚粗

T4

bzoj1017魔兽地图DotR

没看,没写

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值