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);
}