Loading

CSP 后多校十六

A. 饥饿的狐狸

很显然是一个贪心,讲真的考场上我没想出来正解.
于是我选择了多跑几个正确率达不到 %\(100\) 的错解,然后就 \(A\) 了.

画在数轴上更加形象.

不难发现如果一段距离可以被贡献多次,那么一定要贡献多次.

每个饼干至少贡献 \(val_i-W\),于是每次取 \(max\) 就好了.

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
	#define int long long 
	#define lf long double
	#define pb push_back
	#define kap make_pair
	#define lb lower_bound
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof(x))
	#define Copy(x,y) memcpy(x,y,sizeof(y))
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
		while(!isdigit(ch)) cit|=(ch=='-'),ch=getchar();
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?(-w):w;
	};
}using namespace BSS;

const int N=1e5+21;

int m,n,cx,cy,minw,maxw;
int ret[N],pos[N];
int val[3][N];
namespace Rude{
	int per[N];
	struct I { int w,op; } p[N];
	inline short main(){
		for(int i=1;i<=n;i++) p[i].w=val[2][i],	p[i].op=1;
		for(int i=1;i<=n;i++) per[i]=i;
		do{
			int lst=m,cnt=0,res=0;
			for(int i=1;i<=n;i++) res+=max(abs(p[per[i]].w-lst),abs(p[per[i]].w-m)),lst=p[per[i]].w;
			maxw=max(maxw,res);
		}while(next_permutation(per+1,per+1+n));
		printf("%lld %lld\n",minw,maxw);
		exit(0);
	}
};
auto Work1=[]()->void{
	int i=1,j=1,k=m,res=0;
	for(;i<=cx and j<=cy;i++,j++){
		res+=abs(val[0][i]-k)+abs(val[0][i]-val[1][i]),k=val[1][i];
	}
	if(cx>cy){
		for(;i<=cx;i++) res+=abs(val[0][i]-k),k=m;
	}
	else{
		for(k=m;j<=cy;j++) res+=abs(val[1][j]-k),k=m;
	}
	maxw=max(maxw,res);
};
auto Work2=[]()->void{
	int i=1,j=1,k=m,res=0;
	for(;i<=cy and j<=cx;i++,j++){
		res+=abs(val[1][i]-k)+abs(val[0][i]-val[1][i]),k=val[0][i];
	}
	if(cy>cx){
		for(;i<=cy;i++) res+=abs(val[1][i]-k),k=m;
	}
	else{
		for(k=m;j<=cx;j++) res+=abs(val[0][j]-k),k=m;
	}
	maxw=max(maxw,res);
};
auto Work3=[]()->void{
	int i=1,j=n,k=m,wi,wj,res=0;
	while(i<=j){
		wi=max(abs(val[2][i]-k),abs(val[2][i]-m));
		wj=max(abs(val[2][j]-k),abs(val[2][j]-m));
		// cout<<wi<<' '<<wj<<" "<<res<<endl;
		if((wi^abs(val[2][i]-m)) and (wj^abs(val[2][j]-m))){
			if(wi>wj) res+=wi,k=val[2][i++];
			else res+=wj,k=val[2][j--];
		}
		else{
			if((wi^abs(val[2][i]-m)) and wj==abs(val[2][j]-m)){
				res+=wi,k=val[2][i++]; continue;
			}
			if(wi==abs(val[2][i]-m) and (wj^abs(val[2][j]-m))){
				res+=wj,k=val[2][j--]; continue;
			}
			if(wi>wj) res+=wi,k=val[2][i++];
			else res+=wj,k=val[2][j--];
		}
		
	}
	maxw=max(maxw,res);
};
signed main(){
	File(a);
	n=read(),m=read(); int w;
	for(int i=1;i<=n;i++){
		w=read(),val[2][i]=w;
		w>=m ? val[1][++cy]=w : val[0][++cx]=w ;
	}
	sort(val[0]+1,val[0]+1+cx,[](int i,int j){return i>j;});
	sort(val[1]+1,val[1]+1+cy,[](int i,int j){return i<j;});
	for(int i=1,j=m;i<=cx;i++) minw+=abs(j-val[0][i]),j=val[0][i];
	for(int i=1,j=m;i<=cy;i++) minw+=abs(j-val[1][i]),j=val[1][i];
	if(n<=10) return Rude::main();
	sort(val[0]+1,val[0]+1+cx,[](int i,int j){return i<j;});
	sort(val[1]+1,val[1]+1+cy,[](int i,int j){return i>j;});
	sort(val[2]+1,val[2]+1+n,[](int i,int j){return i<j;});
	Work1(),Work2(),Work3();
	sort(val[2]+1,val[2]+1+n,[](int i,int j){return i>j;});
	Work1(),Work2(),Work3();
	printf("%lld %lld\n",minw,maxw);
	exit(0);
}

B. 保险箱

考场上基本就没有往正解思路上靠拢,根本不知道 \(k\) 的值域对于解题的影响.

一个显然的结论:如果 \(x\) 合法,那么 \(gcd(x,n)\) 也一定合法;反之亦然.

另外有一个显然但没利用起来的结论:如果 \(x\) 合法,那么 \(k*x(mod\ n)\) 一定也合法.

于是考虑把所有可能构成 \(m_i(i<k)\) 的数的因子全都排斥掉,其实就是排斥 \(gcd(m_i(i<k),n)\) 的因子(不妨称之为非法因子).

考虑少去排斥一些没有用的东西,发现其实只需要排斥同时也是 \(gcd(m_k,n)\) 因子的非法因子.

于是就变成了排斥 \(gcd(m_k,m_i(i<k),n)\) 的因子,基本上这样复杂度就合法了.

知识小贴士:一个数的因子大概只有 \(\huge n^{\frac{1.066}{ln\ ln\ n}}\) 个.

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
	#define int long long 
	#define lf long double
	#define pb push_back
	#define kap make_pair
	#define lb lower_bound
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof(x))
	#define Copy(x,y) memcpy(x,y,sizeof(y))
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
		while(!isdigit(ch)) cit|=(ch=='-'),ch=getchar();
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?(-w):w;
	};
}using namespace BSS;

const int N=3e5+21,M=1e7+21;

#define gcd aasas
int m,n,s,cnt,ans;
int pri[M],val[M];
set<int> st;
void ban(int x){
	if(st.find(x)==st.end()) return ;
	st.erase(x);
	for(int i=1;i<=cnt;i++)
		if(x%pri[i]==0) ban(x/pri[i]);
}
auto gcd=[](int x,int y)->int{
	if(!(x and y)) return x|y;
	for(int z=y;z;z=y) y=x%y,x=z;
	return x;
};
signed main(){
	File(b);
	n=read(),m=read();
	for(int i=1;i<m;i++) val[i]=read();
	s=read(),s=gcd(s,n); int w=s;
	for(int i=2,lmi=sqrt(s);i<=lmi;i++){
		if(w%i) continue;
		pri[++cnt]=i; while(w%i==0) w/=i;
	}
	if(w^1) pri[++cnt]=w;
	for(int i=1,lmi=sqrt(s);i<=lmi;i++){
		if(s%i) continue;
		st.insert(i),st.insert(s/i);
	}
	for(int i=1;i<m;i++) ban(gcd(s,val[i]));
	// for(auto i : st) assert(i%(*st.begin())==0);
	printf("%lld\n",n/(*st.begin()));
	exit(0);
}

C. 追逐

原题.

C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define p() printf("Pass")
	#define ll long long int
	#define re register ll 
	#define lf double
	#define mp make_pair
	#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define fill(x,y) memset(x,y,sizeof x);
	#define copy(x,y) memset(y,x,sizeof x);
	#define pass() printf("Pass")
	inline void read(ll &ss)
	{
		ss=0; bool cit=0; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		if(cit) ss=-ss;
	}
	inline void write(ll ss)
	{
		static int stas[35]; int topps=0;
  		if(ss<0) putchar('-'),ss=-ss;
  		do{stas[++topps]=ss%10,ss/=10;}while(ss);
  		while(topps) putchar(stas[topps--]+48); puts("");
	}
} using namespace BSS;

const ll N=1e5+50;

ll n,m,ts,ans;
ll head[N],val[N],alls[N];
ll g[N][150],f[N][150];
ll que[N*2];
struct I { ll u,v,w,nxt; } e[N*2];
inline void add(ll u,ll v)
{
	e[++ts].u=u;
	e[ts].v=v;
	e[ts].nxt=head[u];
	head[u]=ts;
}
void dfs(ll now,ll dad)
{	
	for(re i=1;i<=m;i++)
	{
		f[now][i]=alls[now];
		g[now][i]=alls[now]-val[dad];
	}
	for(re i=head[now];i;i=e[i].nxt)
	{
		if(e[i].v==dad) continue;
		dfs(e[i].v,now);
		for(re j=0;j<=m;j++) ans=max(f[now][j]+g[e[i].v][m-j],ans);
		for(re j=1;j<=m;j++)
		{
			f[now][j]=max(f[now][j],max(f[e[i].v][j],f[e[i].v][j-1]+alls[now]-val[e[i].v]));
			g[now][j]=max(g[now][j],max(g[e[i].v][j],g[e[i].v][j-1]+alls[now]-val[dad]));
		}
	}
	for(re i=1;i<=m;i++)
	{
		f[now][i]=alls[now];
		g[now][i]=alls[now]-val[dad];
	}
	ll top=0,v;
	for(re i=head[now];i;i=e[i].nxt)
	{
		if(e[i].v==dad) continue;
		que[++top]=i;
	}
	while(top)
	{
		re i=que[top--];
		for(re j=0;j<=m;j++) ans=max(f[now][j]+g[e[i].v][m-j],ans);
		for(re j=1;j<=m;j++)
		{
			f[now][j]=max(f[now][j],max(f[e[i].v][j],f[e[i].v][j-1]+alls[now]-val[e[i].v]));
			g[now][j]=max(g[now][j],max(g[e[i].v][j],g[e[i].v][j-1]+alls[now]-val[dad]));
		}
	}
	return ;
}
signed main()
{
    freopen("c.in","r",stdin),freopen("c.out","w",stdout);
	read(n); read(m);
	for(ll i=1;i<=n;i++)
	{
		read(val[i]);
	}
	ll u,v,w;
	for(ll i=1;i<=n-1;i++)
	{
		read(u); read(v);
		add(u,v); add(v,u);
		alls[u]+=val[v];
		alls[v]+=val[u];
	}
	dfs(1,0);
	printf("%lld",ans);
	return 0;
}

D. 字符串

暴力的贪心过程同样可以应用到正解上.

每次一旦遇到一个 \(pre<0\) 的就要删去,于是考虑满足 \(pre\) 的时候对 \(suf\) 的影响.

把贡献拆解,式子推出来之后发现答案就是区间最大值减去区间和.

D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
	// #define int long long 
	#define lf long double
	#define pb push_back
	#define kap make_pair
	#define lb lower_bound
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof(x))
	#define Copy(x,y) memcpy(x,y,sizeof(y))
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
		while(!isdigit(ch)) cit|=(ch=='-'),ch=getchar();
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?(-w):w;
	};
}using namespace BSS;

#define ls (x<<1)
#define rs (x<<1|1)
const int N=5e5+21;

char ch[N];
int m,n;
int val[N];
struct I { int lc,rc,mx,sum; } tr[N<<2];
auto put=[](int x)->void{
	cout<<x<<' '<<tr[x].lc<<' '<<tr[x].rc<<' '<<tr[x].mx<<' '<<tr[x].sum<<endl;
};
auto pushup=[](int x,int lson,int rson)->void{
	I z; z.sum=tr[lson].sum+tr[rson].sum;
	z.mx=max(max(tr[lson].mx,tr[rson].mx),tr[lson].rc+tr[rson].lc);
	z.lc=max(tr[lson].lc,tr[lson].sum+tr[rs].lc);
	z.rc=max(tr[rson].rc,tr[rson].sum+tr[ls].rc);
	tr[x]=z;
};
void build(int x,int l,int r){
	if(l==r){
		tr[x].mx=tr[x].sum=val[l];
		tr[x].lc=tr[x].rc=val[l];
		// cout<<l<<' '<<r<<' ',put(x);
		return void();
	}
	int mid=(l+r)>>1; build(ls,l,mid),build(rs,mid+1,r);
	pushup(x,ls,rs);
	// cout<<l<<' '<<r<<' ',put(x);
}
void qry(int x,int l,int r,int ql,int qr){
	if(l>=ql and r<=qr) return pushup(0,0,x),void();
	int mid=(l+r)>>1; 
	if(ql<=mid) qry(ls,l,mid,ql,qr);
	if(qr>mid) qry(rs,mid+1,r,ql,qr);
}
signed main(){
	File(d);
	n=read(),scanf("%s",ch+1); int l,r,mx,sum;
	for(int i=1;i<=n;i++) val[i]=(ch[i]=='C' ? 1 : -1);
	build(1,1,n);
	for(int Ts=read();Ts;Ts--){
		l=read(),r=read(); 
		tr[0].lc=tr[0].rc=tr[0].sum=tr[0].mx=0;
		qry(1,1,n,l,r);
		printf("%d\n",tr[0].mx-tr[0].sum);
	}
	exit(0);
}
posted @ 2021-11-17 21:29  AaMuXiiiiii  阅读(37)  评论(0编辑  收藏  举报