记录一下启发性较大的题组,特别是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
using namespace std;
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
typedef pair 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
using namespace std;
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
typedef pair 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<>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
using namespace std;
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
typedef pair 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<>t;
while(t--) solve();
return 0;
}
这几天没学什么新算法,主要还是补题,和刷之前学的算法在洛谷上的题组,