CF1394 Div.1 做题记录
A
诈骗简单题
看到题被诈骗了,一眼贪心,用一个大于 \(m\) 的数和 \(d+1\) 个小于等于 \(m\) 的数的和比较,选择较大的部分。但被卡掉了。
发现可以直接枚举用 \(x\) 个大于 \(m\) 的数,选的肯定是最大的 \(x\) 个数。这 \(x\) 个数要造成贡献,总共要用掉 \((x-1)\times (d+1)+1\) 个数,先用掉大于 \(m\) 的数,再从小到大用小于等于 \(m\) 的数,剩下的数的和可以用前缀和维护,最后对于所有的答案取 \(\max\) 即可。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=1e5+10;
int n,d,m,a[N],s[N],q1[N],q2[N],cnt,tot;
bool cmp(int x,int y){
return x>y;
}
void solve(){
read(n),read(d),read(m);
for(int i=1;i<=n;i++){
read(a[i]);
}
sort(a+1,a+n+1);
int pos=n+1;
for(int i=1;i<=n;i++){
if(a[i]>m){
q2[++tot]=a[i];
}
else{
q1[++cnt]=a[i];
}
}
sort(a+1,a+cnt+1,cmp);
for(int i=1;i<=cnt;i++){
s[i]=s[i-1]+a[i];
}
int sum=0,ans=0;
for(int i=1;i<=tot;i++){
sum+=a[n-i+1];
int day=(i-1)*(d+1)+1;
if(day>n){
break;
}
ans=max(ans,sum+s[min(n-day,cnt)]);
}
ans=max(ans,s[cnt]);
write_endl(ans);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
B
先考虑一个怎样的方案是合法的。因为对于每个点都要能从这个点出发,又回到这个点,所以每个点出入度均为 \(1\),又因为根据题意,每个点只有一条出边,所以每个点都在一个环内。
观察到 \(k\) 很小,可以直接 \(n!\) 枚举每个 \(k\) 元组,判断是否合法。对于剩下判合法性的问题,我们想到了[CSP-S 2022] 星战,通过 xor-hashing 判断是否所有点的出边的入度集合为 \(1\sim n\)。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=2e5+10;
int n,m,k,val[N],f[100][100],id[100],S,ans;
mt19937_64 rnd(time(NULL));
struct edge{
int v,w;
bool operator <(const edge &rhs){
return w<rhs.w;
}
};
void dfs(int i){
if(i>k){
int res=0;
for(int i=1;i<=k;i++){
res^=f[i][id[i]];
}
if(res==S){
ans++;
}
return;
}
for(int j=1;j<=i;j++){
id[i]=j;
dfs(i+1);
id[i]=0;
}
}
vector<edge>e[N];
void solve(){
read(n),read(m),read(k);
for(int i=1;i<=m;i++){
int u,v,w;
read(u),read(v),read(w);
e[u].pb(edge{v,w});
}
for(int i=1;i<=n;i++){
val[i]=rnd();
S^=val[i];
sort(e[i].begin(),e[i].end());
}
for(int i=1;i<=n;i++){
for(int j=1;j<=e[i].size();j++){
f[e[i].size()][j]^=val[e[i][j-1].v];
}
}
dfs(1);
write_endl(ans);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
C
先做转化,两个字符串相似等同于两个字符串中的字符 B 和 N 的数量均相等。那么我们将一个字符串中的 B 和 N 的数量所组成的二元组 \((x,y)\) 看作它的坐标。那么操作相当于延 \((1,0),(1,1),(0,1),(0,-1),(-1,-1),(-1,0)\) 中的一个方向走一步。当从 \((x,y)\) 开始,走 \(z\) 步,可以到达点组成的图形为一个边长为 \(2z\) 的正方形,去掉左上角和右下角的边长为 \(z\) 的等腰直角三角形。当且仅当这 \(n\) 个图形有交集时,该步数有解。
所以我们考虑二分移动步数,令竖直方向的坐标为 \(y\),水平方向的坐标为 \(x\),斜方向的坐标为 \(x-y\),令其为 \(z\)。得到交集图形在竖直方向上的坐标在 \([yl,yr]\) 内,水平方向上的坐标在 \([xl,xr]\) 内,斜方向上的坐标为 \([zl,zr]\) 内。有解当且仅当三个集合均不为空且 \([zl,zr]\cup[xl-yr,xr-yl]\not=\empty\)。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=5e5+10,inf=1e9;
char s[N];
int x[N],y[N],n,l,r,ansx,ansy;
bool check(int delta){
int mnx=-inf,mny=-inf,mxx=inf,mxy=inf,mndelta=-inf,mxdelta=inf;
for(int i=1;i<=n;i++){
mxx=min(mxx,x[i]+delta);
mnx=max(mnx,x[i]-delta);
mxy=min(mxy,y[i]+delta);
mny=max(mny,y[i]-delta);
mxdelta=min(mxdelta,x[i]-y[i]+delta);
mndelta=max(mndelta,x[i]-y[i]-delta);
}
if(mxx<mnx||mxy<mny||mxdelta<mndelta||min(mxx-mny,mxdelta)<max(mndelta,mnx-mxy)){
return 0;
}
ansx=min(mxx,mxy+mxdelta);
ansy=min(mxy,ansx-mndelta);
return 1;
}
void solve(){
read(n);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
int len=strlen(s+1);
r=max(r,len);
for(int j=1;j<=len;j++){
x[i]+=(s[j]=='B');
y[i]+=(s[j]=='N');
}
}
int ans=r;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)){
r=mid-1;
ans=mid;
}
else{
l=mid+1;
}
}
write_endl(ans);
for(int i=1;i<=ansx;i++){
putchar('B');
}
for(int i=1;i<=ansy;i++){
putchar('N');
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
D
虽然边的方向不定,但我们可以让它定下来。令所有 \(b_u\not=b_v\) 的边 \((u,v)\),边的方向为从 \(b\) 权值大的点到 \(b\) 权值小的点,那么我们只需要处理 \(b_u=b_v\) 的边 \((u,v)\) 即可。
处理这些没定向的边,考虑树形dp。令 \(f_{u,0/1}\) 表示点 \(u\) 和父亲相连的边为 \(u\) 的入边/出边的最小贡献,\(s_1\) 表示有多少确定方向且为 \(u\) 点的出边的边,\(s_2\) 表示有多少确定方向且为 \(u\) 点入边的边,\(s_3\) 表示有多少还没确定方向的边。我们假定这 \(s_3\) 条边中有 \(x\) 条边为 \(u\) 点入边,那么通过将 \(u\) 点的入边和出边相拼接,可以得到 \(u\) 点造成的贡献为 \(\max(s_1+s_3-x,s_2+x)\times a_u\),别忘了处理父边带来的贡献。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=2e5+10;
int n,a[N],b[N],f[N][2];
vector<int>e[N];
void dfs(int u,int fa){
int s=0,s1=0,s2=0;
vector<int>num;
for(auto v:e[u]){
if(v==fa){
continue;
}
dfs(v,u);
if(b[v]==b[u]){
num.pb(f[v][1]-f[v][0]);
s+=f[v][0];
}
else if(b[v]>b[u]){
s+=f[v][1];
s2++;
}
else{
s+=f[v][0];
s1++;
}
}
sort(num.begin(),num.end());
for(int i=0;i<=num.size();i++){
f[u][0]=min(f[u][0],s+max((int)(s1+num.size()-i),s2+i+(fa>0))*a[u]);
f[u][1]=min(f[u][1],s+max((int)(s1+num.size()-i)+(fa>0),s2+i)*a[u]);
if(i<num.size()){
s+=num[i];
}
}
}
void solve(){
read(n);
for(int i=1;i<=n;i++){
read(a[i]);
}
for(int i=1;i<=n;i++){
read(b[i]);
}
for(int i=1,u,v;i<n;i++){
read(u),read(v);
e[u].pb(v);
e[v].pb(u);
}
memset(f,0x3f,sizeof(f));
dfs(1,0);
write_endl(min(f[1][0],f[1][1]));
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}

浙公网安备 33010602011771号