2023.7.12

记录一下启发性较大的题组,特别是P_2340_USACO_03_FALL_Cow_Exhibition_G.cpp思路和细节处理感觉很有启发性(01背包变形)

//cf/Codeforces Round 853 (Div. 2)/C_Serval_and_Toxel_s_Arrays.cpp

//题意:给定n个数,执行m个操作:将p位置元素修改为v,每执行一个操作,产生一个新数组,数组两两比较,贡献值为不同元素的个数,求总贡献值

//思路:因为保证每个数组元素不同,所以统计每个元素的出现次数个数就能统计该元素在多少个数组,比较的两个数组都含有该元素的贡献值为C(2,m)

//比较的两个数组都只有一个含有该元素的贡献值为m(n-m),总贡献值C(2,m)+m(n-m),统计个数可以用一个数组记录某一个数上一次出现的位置,

//当这个数被修改时,即可用当前位置与上一次位置相减得到一个重复出现次数,再借助一个数组记录累计值即可。

#include<bits/stdc++.h>

using namespace std;



#define endl '\n'

#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)

typedef pair<int,int> pr;



#define int long long

#define fr(i,l,r) for(int i=l;i<=r;i++)

#define pb(x) push_back(x)

#define all(a) a.begin(),a.end()

#define fi first

#define se second



const int N = 1e6+10;

const int mod=998244353,inf=LONG_LONG_MAX;

int dx[]={0,0,-1,0,1},dy[]={0,-1,0,1,0};

int n,m;



int a[N];

int cnt[N], st[N];

void solve()

{

    cin>>n>>m;

    fr(i,1,n+m){

        cnt[i] = 0, st[i] = 0;

    }

    fr(i,1,n){

        cin>>a[i];

    }

    fr(i,1,m){

        int p,v;

        cin>>p>>v;

        if (v != a[p]){      //不等于

           cnt[a[p]] += i - st[p], st[p] = i;

        }

        a[p]=v;

    }

    fr (i,1,n) {

        cnt[a[i]] += m - st[i] + 1;

    }

    int ans=0;

    fr(i,1,n+m) {

        ans += 1ll * cnt[i] * (m + 1 - cnt[i]);

        ans += 1ll * cnt[i] * (cnt[i] - 1) / 2;

    }

    cout << ans << '\n';

}

signed main()

{

//    ios;

    int t=1;

    cin>>t;

    while(t--) solve();

    return 0;

}

//luogu/线性dp题组/P_2285_HNOI_2004_打鼹鼠.cpp

//题意:给定n*n的网格,和m只地鼠出现的时间及位置,可以操控机器人在初始时刻出现在任意位置,1秒只能向上下左右移动一个位置,求打地鼠最多的数量

//思路:首先明确dp打地鼠的数量,因为dp网格或时间都无从下手,因为机器人总是从上一个打地鼠的地方过来,所以dp[i]表示打第i个地鼠的时候最多打了几个地鼠,判断一下能否从上个地方转移而来

//于是考虑曼哈顿距离,<时间差可以转移

#include<bits/stdc++.h>

using namespace std;



#define endl '\n'

#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)

typedef pair<int,int> pr;



#define int long long

#define fr(i,l,r) for(int i=l;i<=r;i++)

#define pb(x) push_back(x)

#define all(a) a.begin(),a.end()

#define fi first

#define se second



const int N = 1e6+10;

const int mod=998244353,inf=LONG_LONG_MAX;

int dx[]={0,0,-1,0,1},dy[]={0,-1,0,1,0};

int n,m;



int a[N];



struct node{

    int t,x,y;

}d[N];

int dp[N];

void solve()

{

     cin>>n>>m;

     fr(i,1,m){

        cin>>d[i].t>>d[i].x>>d[i].y;

        dp[i]=1;

     }

     fr(i,1,m){

        fr(j,1,i-1){

            if(abs(d[i].x-d[j].x)+abs(d[i].y-d[j].y)<=abs(d[i].t-d[j].t)){

                dp[i]=max(dp[i],dp[j]+1);

            }

        }

     }

   int ans=0;

   fr(i,1,m){

    ans=max(ans,dp[i]);

   }

   cout<<ans<<'\n';



}



signed main()

{

//    ios;

    int t=1;

    //cin>>t;

    while(t--) solve();

    return 0;

}

//luogu/线性dp题组/P_2340_USACO_03_FALL_Cow_Exhibition_G.cpp

//题意:给定n个奶牛的情商与智商,选定n个奶牛使得情商+智商总和最大,但情商或智商不能小于0

//思路:非常好的01背包问题变形,将奶牛的个数看成物品种类,智商为背包体积,情商为价值,dp[i][j]为智商为j时情商的最大值,于是得到转移方程 dp[j]=max(dp[j],dp[j-x[i]]+y[i]);

//x[i]可能为负,造成j-x[i]>j,所以当x[i]为负时,正着dp,由于可能x[i]为负,y[i]也为负,可能造成数组越界,于是向右移动maxn位

//总结:这里是枚举数据范围内所有的智商值情况下的最大情商值,同时在数组下标为负的情况下,右移下标可以防止下标越界

#include<bits/stdc++.h>

using namespace std;



#define endl '\n'

#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)

typedef pair<int,int> pr;



#define int long long

#define fr(i,l,r) for(int i=l;i<=r;i++)

#define ufr(i,n,z) for(int i = n;i >= z; i--)

#define pb(x) push_back(x)

#define all(a) a.begin(),a.end()

#define fi first

#define se second



const int N = 1e6+10;

const int mod=998244353,inf=LONG_LONG_MAX;

int dx[]={0,0,-1,0,1},dy[]={0,-1,0,1,0};



const int maxn=4e5+10;

int a[N];

int x[N],y[N];

int dp[N];

void solve(){

    int n;

    cin>>n;

    fr(i,1,n){

       cin>>x[i]>>y[i];

    }

    memset(dp,-0x3f,sizeof(dp));

    dp[maxn]=0;    //初始

    fr(i,1,n){      //枚举奶牛

        if(x[i]>=0){

            ufr(j,2*maxn,x[i]){        

                dp[j]=max(dp[j],dp[j-x[i]]+y[i]);

            }

        }

        else{

             fr(j,0,2*maxn+x[i]){

              dp[j]=max(dp[j],dp[j-x[i]]+y[i]);

            }

        }

    }

    int ans=0;

    fr(i,maxn,2*maxn){

        if(dp[i]>0){

            ans=max(ans,i+dp[i]-maxn);

        }

    }

  cout<<ans<<'\n';

}



signed main()

{

//    ios;

    int t=1;

    //cin>>t;

    while(t--) solve();

    return 0;

}

这几天没学什么新算法,主要还是补题,和刷之前学的算法在洛谷上的题组,

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值