Preface
最接近橙名的一场,可惜给我一个小时也没想到E的关键点,后面徐神一点拨就懂了
虽然现在这个号已经到渡劫局了但因为之前有场比赛给了ztc一份代码然后他直接没咋改交上去了,估计下次roll Rating的时候这个号要掉200来分了
嘛不过也无所谓反正下次打另一个号冲分,而且像我这种永远写不来Div2 E的人纯靠手速打上2100真的有说服力吗
A. United We Stand
签到题,把最大的数都放在\(c\)即可,当且仅当所有数相等时无解
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=105;
int t,n,a[N],b[N],c[N];
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]);
bool flag=0; for (i=2;i<=n;++i) if (a[i]!=a[1]) flag=1;
if (!flag) { puts("-1"); continue; }
int nb=0,nc=0,mx=0; for (i=1;i<=n;++i) mx=max(mx,a[i]);
for (i=1;i<=n;++i) if (a[i]!=mx) b[++nb]=a[i];
for (i=1;i<=n;++i) if (a[i]==mx) c[++nc]=a[i];
for (printf("%d %d\n",nb,nc),i=1;i<=nb;++i)
printf("%d%c",b[i]," \n"[i==nb]);
for (i=1;i<=nc;++i) printf("%d%c",c[i]," \n"[i==nc]);
}
return 0;
}
B. Olya and Game with Arrays
不难发现由于所有数的最小值一定会在某个序列中造成贡献,那么我们不妨把所有数组中的最小值都扔到一个数组中
维护每个数组的次小值然后找一个最小的减去即可
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=25005;
int t,n,m,x,mi[N],smi[N];
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i,j; for (scanf("%d",&n),i=1;i<=n;++i)
{
scanf("%d",&m); vector <int> num;
for (j=1;j<=m;++j) scanf("%d",&x),num.push_back(x);
sort(num.begin(),num.end());
mi[i]=num[0]; smi[i]=num[1];
}
int allmi=mi[1],mismi=smi[1]; LL sum=0;
for (i=1;i<=n;++i) allmi=min(allmi,mi[i]),mismi=min(mismi,smi[i]),sum+=smi[i];
printf("%lld\n",allmi+sum-mismi);
}
return 0;
}
C. Another Permutation Problem
很有意思的一个题,首先由于数据范围很小我们可以直接暴力枚举\(\max_{j = 1}^{n} p_j \cdot j\)的值
然后贪心地从大到小考虑每个\(p_i\),将它能匹配的数中最大的找出来和它匹配即可
我刚开始的时候用了个set
实现,然后跑了手\(n=250\)发现要跑5s……
但直觉告诉我们\(\max_{j = 1}^{n} p_j \cdot j\)的值肯定不会太小,然后把\(n=250\)的输出来一看大概是\(57000+\)左右,所以就把枚举\(\max_{j = 1}^{n} p_j \cdot j\)的值调整成\([\max(n^2-15000,1),n^2]\)即可
后面问了下ztc发现其实可以把set
那个地方用并查集维护,就是删去一个数的时候把它接到前面的数上,就可以用大致线性的复杂度来做了
但据说这题可以打表发现最优的答案就是把\(\{1,2,3,\cdots,n\}\)的某个后缀翻转,这样就可以枚举后缀然后做到总复杂度\(O(n^2)\)了,不过原理未知
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=255;
int t,n;
inline int solve(CI x)
{
set <int> s; RI i; int ret=0;
for (i=1;i<=n;++i) s.insert(i);
for (i=n;i>=1;--i)
{
auto it=s.upper_bound(x/i);
if (it==s.begin()) return 0;
--it; ret+=*it*i; s.erase(it);
}
return ret;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i,j; int ans=0; for (scanf("%d",&n),i=max(1,n*n-15000);i<=n*n;++i)
ans=max(ans,solve(i)-i); printf("%d\n",ans);
}
return 0;
}
D. Andrey and Escape from Capygrad
首先由于这题传送区间的性质,不难发现答案随着起点的增加是不减的,这就提醒我们可以从大到小递推答案
考虑用类似扫描线的思路维护出每个点被覆盖的区间,那么这些区间的\(f_{b_i}\)中的最大值就可以用来更新答案
离散化下标后用树状数组维护最值即可,总复杂度\(O(n\log n)\)
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=1e6+5;
struct ifo
{
int x,id;
inline ifo(CI X=0,CI ID=0)
{
x=X; id=ID;
}
friend inline bool operator < (const ifo& A,const ifo& B)
{
return A.x>B.x;
}
}o[N]; int t,n,l[N],a[N],b[N],r[N],q,x[N],rst[N],cnt,tot,ans[N];
class Tree_Array
{
private:
int mx[N],lim;
public:
#define lowbit(x) (x&-x)
inline void init(CI n)
{
lim=n; for (RI i=1;i<=lim;++i) mx[i]=0;
}
inline int get(RI x,int ret=0)
{
for (;x;x-=lowbit(x)) ret=max(ret,mx[x]); return ret;
}
inline void add(RI x,CI y)
{
for (;x<=lim;x+=lowbit(x)) mx[x]=max(mx[x],y);
}
#undef lowbit
}BIT;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; for (scanf("%d",&n),cnt=0,i=1;i<=n;++i)
scanf("%d%d%d%d",&l[i],&r[i],&a[i],&b[i]),
rst[++cnt]=l[i],rst[++cnt]=r[i],rst[++cnt]=a[i],rst[++cnt]=b[i];
for (scanf("%d",&q),i=1;i<=q;++i) scanf("%d",&x[i]),rst[++cnt]=x[i];
sort(rst+1,rst+cnt+1); cnt=unique(rst+1,rst+cnt+1)-rst-1;
auto find=[&](CI x)
{
return lower_bound(rst+1,rst+cnt+1,x)-rst;
};
for (tot=0,i=1;i<=n;++i)
{
l[i]=find(l[i]); r[i]=find(r[i]); a[i]=find(a[i]); b[i]=find(b[i]);
o[++tot]=ifo(b[i],i);
}
for (i=1;i<=q;++i) x[i]=find(x[i]),o[++tot]=ifo(x[i],n+i);
for (sort(o+1,o+tot+1),BIT.init(cnt),i=1;i<=tot;++i)
{
int tmp=max(rst[o[i].x],BIT.get(o[i].x));
if (o[i].id<=n) BIT.add(l[o[i].id],tmp); else ans[o[i].id-n]=tmp;
}
for (i=1;i<=q;++i) printf("%d%c",ans[i]," \n"[i==q]);
}
return 0;
}
E. Maximum Monogonosity
首先看到绝对值的式子就考虑拆绝对值,我们分四种情况来转移,最后取\(\max\)后一定能得到正确的答案
考虑朴素的DP,\(f_{i,j}\)表示前\(i\)个数,选的区间长度为\(j\)的最大答案,则转移方程为:
\[f_{k,j}+|a_{k+1}-b_i|+|b_{k+1}-a_i|\to f_{i,j+(i-k)} \]乍一看感觉因为第二个下标的缘故很难维护答案,其实稍作观察就会发现转移只能在\(i-j\)相同的\(f_{i,j}\)之间发生
因此我们对于所有\(i-j\)的值以及\(4\)种情况分别维护最大值即可\(O(1)\)转移了,复杂度\(O(nk)\)
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<unordered_map>
#define int long long
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=3005,INF=1e18,s1[4]={1,1,-1,-1},s2[4]={1,-1,1,-1};
int t,n,k,a[N],b[N],f[N][N],mx[N][4];
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%lld",&t);t;--t)
{
RI i,j,s; for (scanf("%lld%lld",&n,&k),i=1;i<=n;++i) scanf("%lld",&a[i]);
for (i=1;i<=n;++i) scanf("%lld",&b[i]);
for (f[0][0]=0,i=1;i<=k;++i) f[0][i]=-INF;
for (i=1;i<=n;++i) for (j=1;j<=i;++j) f[i][j]=-INF;
auto calc=[&](CI x,CI y,CI tp)
{
return f[x][x-y]+a[x+1]*s1[tp]+b[x+1]*s2[tp];
};
for (s=0;s<4;++s) for (mx[0][s]=calc(0,0,s),i=1;i<=n;++i) mx[i][s]=-INF;
for (i=1;i<=n;++i)
{
for (j=0;j<=k;++j) f[i][j]=f[i-1][j];
for (j=0;j<=min(i,k);++j)
{
int dlt=i-j; for (s=0;s<4;++s)
f[i][j]=max(f[i][j],mx[dlt][s]-b[i]*s1[s]-a[i]*s2[s]);
for (s=0;s<4;++s) mx[dlt][s]=max(mx[dlt][s],calc(i,dlt,s));
}
}
printf("%lld\n",f[n][k]);
}
return 0;
}
Postscript
F题因为今天下午打百度之星所以没时间补了,而且看了一眼感觉不容易就先弃了
标签:892,const,int,typedef,long,Codeforces,Div,include,define From: https://www.cnblogs.com/cjjsb/p/17627282.html