atcoder新手赛261:补题

atcoder新手赛261:补题

 https://atcoder.jp/contests/abc261/tasksContest 261icon-default.png?t=M7J4https://atcoder.jp/contests/abc261/tasks

D:动态规划

硬币正面,cnt值++,价值+a[i]元;

反面,cnt=0,价值不变;

当cnt==c[i]时,价值+y[i];

  1. 利用:c[x]=y;存当cnt达到某一个值时价值所增加量;

  2. dp[i][j]表示:硬币第i次、当下的cnt为j时的最大价值
for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)//正面
        {
            dp[i][j]=dp[i-1][j-1]+a[i]+c[j];//若此时j达不到计数器标准则加0;
        } 
        dp[i][0]=0;//当硬币反面,cnt归0;
        for(int k=0;k<i;k++)
        {
            dp[i][0]=max(dp[i][0],dp[i-1][k]);//枚举从0-i的最大值
        }
    }//

4.

在所有的dp[n][i]里找到最大值;
记得long long;

E:位运算:按位拆分

输入:n x

n行:t[i],a[i]; 如果t==1,原数x=x&a[i]; t==2,x=x|a[i], t==3,x=x^a[i]; 分别打印n个数,x进行前1个操作后打印,进一步进行前2个操作打印。。。。。

目的:求最终的x;

思路:x,a[i],最多30位,每位初值只能是0、1;先预处理出每位初始分别为0、1时进行前i次操作后的值,就可以很快求出任意数进行前i次操作后的值;为什么只有0-0、1-1两种:

 

  1. 对于每一位预处理出每次操作的影响。

  2. c(i,j)表示当前位初始值为j(j属于0、1)进行前i次操作后的值

  3. dp(i,j)表示j经过第i次操作后的值;

  4. 由此得:c(i,0)=dp(c(i-1,0),i,a); c(i,1)=dp(c(i-1,1),i,a);

  5. 统计答案:用一个变量p表示当前位的值,p初值为题中c该位的值;遍历1-n,当遍历到i时,p=c(i,p) ;累加答案;

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+5;
    int n,x;
    int t[N],a[N],c[N][2],ans[N];
    int op(int p,int i,int q)
    {
        if(t[i]==1)return p&q;
        if(t[i]==2)return p|q;
        if(t[i]==3)return p^q;
    }
    int main()
    {
        cin>>n>>x;
        for(int i=1;i<=n;i++)
        cin>>t[i]>>a[i];
        for(int k=0;k<30;k++)//按位进行操作; 
        {
            c[1][0]=op(0,1,a[1]>>k&1);
            c[1][1]=op(1,1,a[1]>>k&1);//预处理首位 
            for(int i=2;i<=n;i++)
        {
            c[i][0]=op(c[i-1][0],i,a[i]>>k&1);
            c[i][1]=op(c[i-1][1],i,a[i]>>k&1);//预处理
        }
        int p=x>>k&1;//初始 0、1; 
        for(int i=1;i<=n;i++)
        {
            p=c[i][p];
            ans[i]+=(p<<k);
        }
        }
        for(int i=1;i<=n;i++)
        cout<<ans[i]<<endl;
        return 0;
    }

    F:树状数组

    题目:n个球,属性:颜色、数字;对相邻的两个球进行交换时,若颜色不同,花费代价1,求:将球排成数字不降序的顺序时,所花费的最小代价;

    思路:所求的最小代价即是颜色不同的逆序对数量;则:求不考虑颜色时的逆序对数量减去对各个颜色,

    颜色相同的逆序对数量;求逆序对:使用树状数组;

    #include<bits/stdc++.h>
    using namespace std;
    const int N=3e5+10;
    #define ll long long
    ll c[N];
    ll tree[N],n;
    vector<int>v[N];
    int lowbit(int x)
    {
        return x&(-x);
    }
    void add(int x,int c)
    {
        for(int i=x;i<=n;i+=lowbit(i))
        {
            tree[i]+=c;
        }
    }
    ll sum(int x)
    {
        ll res=0;
        for(int i=x;i;i-=lowbit(i))
        res+=tree[i];
        return res; 
    }
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        cin>>c[i];
        for(int i=1;i<=n;i++)
        {
            int x;
            cin>>x;
            v[0].push_back(x);//存储不考虑颜色的值求不考虑颜色时的逆序对 
            v[c[i]].push_back(x);//存储考虑颜色时的值求考虑相同颜色的逆序对 
        }
        ll ans=0;
        for(int i=0;i<=n;i++)
        {
            for(auto& x:v[i])
            {
                ans=ans+(i?-1:1)*(sum(n)-sum(x));
                add(x,1);
            }
            for(auto& x:v[i])
            add(x,-1);//在相同颜色中找到逆序对;
        }
        cout<<ans<<endl;
        return 0;
    }

     

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值