csp-s模拟5
A. 光
来自 \(K8\) 的神奇做法,根据贪心思想,一个点减四个亮度可以收益最大化,所以枚举四个灯亮度都不足4时的最终态,然后
看剩下需要亮度需要减的次数,每次选最大的那个操作就行,复杂度 \(O(16n)\)
点击查看代码
#include<bits/stdc++.h>
const int maxn=1e5+10;
using namespace std;
int A,B,C,D,ans,x,y,z,s;
int solve(int x,int y,int z,int h)
{
int temp=0;
while(x>0||y>0||z>0||h>0)
{
temp++;
int t=max(max(x,y),max(z,h));
if(x==t)
{
x-=4;y-=2;z-=2,h-=1;
}
else if(y==t)
{
y-=4;x-=2;h-=2,z-=1;
}
else if(z==t)
{
z-=4;x-=2;h-=2,y-=1;
}
else
{
h-=4;y-=2;z-=2,x-=1;
}
}
return temp;
}
int main()
{
freopen("light.in","r",stdin);
freopen("light.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>A>>B>>C>>D;
int sum=A+B+C+D;
ans=sum;
for(int i=0;i<=3;i++)
{
for(int j=0;j<=3;j++)
{
for(int k=0;k<=3;k++)
{
for(int s=0;s<=3;s++)
{
ans=min(ans,i+j+k+s+solve(A-i-j/2-k/2,B-j-i/2-s/2,C-k-i/2-s/2,D-s-j/2-k/2)*4);
}
}
}
}
cout<<ans;
return 0;
}
/*
400 400 400 400
*/
B. 爬
二进制拆分,计算每个点在每一位的贡献,记每个节点的直接儿子在这一位是1的个数是 \(tot\) ,则当奇数个蚂蚁爬上来时能
合成这个数,总情况 \(2^{tot-1}\) 种,不想写证明了,不会的问,还要考虑直接儿子中不是好蚂蚁的点,和其他节点的蚂蚁
他们对这个节点的这一位都没有贡献,所以他们提供了2的幂次方种方案数。还要特判根节点和只有一只蚂蚁的情况
点击查看代码
#include<bits/stdc++.h>
#define int long long
const int mod=1e9+7;
const int maxn=1e5+10;
using namespace std;
int n,a[maxn],to[maxn<<1],nxt[maxn<<1],head[maxn],tot,ans,sum[maxn];
int cnt[maxn][33];
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void addm(int x,int y)
{
add(x,y);add(y,x);
}
void lsx(int x,int fa)
{
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa) continue;
lsx(y,x);
for(int j=0;j<=30;j++)
{
if(a[y]&(1<<j)) cnt[x][j]++;
sum[x]+=cnt[x][j];
}
}
if(x==1) return ;
for(int i=0;i<=30;i++)
{
if(a[x]&(1<<i)) cnt[x][i]++;
}
}
int qpow(int x,int y)
{
if(y<0) return 0;
int temp=1;
while(y)
{
if(y&1)temp=1ll*temp*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return temp;
}
void solve(int x,int fa)
{
int tot=(x!=1);
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa) continue;
tot++;
solve(y,x);
}
int temp=0;
for(int i=0;i<=30;i++)
{
if(x==1)
{
if(a[x]&(1<<i))
{
if(!cnt[x][i]) temp=(temp+1ll*(1<<i)*(qpow(2,tot)-1)%mod)%mod;
else temp=(temp+1ll*(1<<i)*(qpow(2,cnt[x][i]-1)*qpow(2,tot-cnt[x][i])%mod-1+mod)%mod)%mod;
}
else
{
if(!cnt[x][i])continue;
temp=(temp+1ll*(1<<i)*qpow(2,cnt[x][i]-1)%mod*qpow(2,tot-cnt[x][i])%mod)%mod;
}
}
else
{
if(!cnt[x][i])continue;
temp=(temp+1ll*(1<<i)*(qpow(2,cnt[x][i]-1)*qpow(2,tot-cnt[x][i])%mod-cnt[x][i]+mod)%mod)%mod;
}
}
ans=(ans+1ll*temp*qpow(2,n-1-tot)%mod)%mod;
}
signed main()
{
freopen("climb.in","r",stdin);
freopen("climb.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=2;i<=n;i++)
{
int x;
cin>>x;
addm(x,i);
}
lsx(1,0);
solve(1,0);
cout<<ans;
return 0;
}
/*
3
1 2 4
1 2
*/
C. 字符串
粘个题解吧,挺详细的
点击查看代码
#include<bits/stdc++.h>
const int maxn=110;
using namespace std;
int t,N,M,A,B,C;
int main()
{
freopen("string.in","r",stdin);
// freopen("1.out","w",stdout);
freopen("string.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--)
{
int ans=0;
cin>>N>>M>>A>>B>>C;
for(int i=1,temp=0;i<=min(N,M/C);i++)
{
temp=0;
int n=N,m=M,a=A,b=B,c=C;
n-=i,m-=c*i;
temp+=2*i;
if(n)n--,temp++;
temp+=n/a;
if(m)m--,temp++;
// cout<<temp<<endl;
if(b<c) temp+=i*floor((c-1)/b);
// cout<<i<<" "<<temp<<endl;
if(m)
{
if(b>=c)
{
int s=(b+1-c);
// cout<<m<<endl;
if(s*i>=m) temp+=m/s;
else temp+=i+(m-i*s)/b;
}
else
{
int s=(c-1)%b;
int k=b-s;
if(k*i>=m) temp+=m/k;
else temp+=i+(m-i*k)/b;
}
}
// cout<<temp<<" "<<i<<endl;
ans=max(ans,temp);
}
if(!(M/C))
{
ans=2+(N-1)/A+(M-1)/B;
}
cout<<ans<<'\n';
}
return 0;
}
/*
1
10 10 6 2 4
*/
D. 奇怪的函数
分块,维护每一个块的分段函数的转折点,查询直接每个块判一下与转折点的位置就知道答案,修改就直接推平重构
点击查看代码
#include<bits/stdc++.h>
#define int long long
const int maxn=1e5+10;
using namespace std;
int n,q,sum[maxn],shu,len,l[501],r[501],blo[maxn],up[501],down[501],f[501];
struct lsx
{
int opt,val;
}a[maxn];
void build()
{
for(int i=1;i<=shu;i++)
{
l[i]=(i-1)*len+1;
r[i]=i*len;
}
if(r[shu]<n)shu++,l[shu]=r[shu-1]+1,r[shu]=n;
for(int i=1;i<=shu;i++)
{
for(int j=l[i];j<=r[i];j++)blo[j]=i,up[i]=1e15,down[i]=-1e15;
for(int j=l[i];j<=r[i];j++)
{
if(a[j].opt==1) up[i]+=a[j].val,down[i]+=a[j].val,f[i]+=a[j].val;
if(a[j].opt==2) up[i]=min(up[i],a[j].val),down[i]=min(down[i],a[j].val);
if(a[j].opt==3) up[i]=max(up[i],a[j].val),down[i]=max(down[i],a[j].val);
}
}
}
void solve(int x)
{
up[x]=1e15,down[x]=-1e15,f[x]=0;
for(int i=l[x];i<=r[x];i++)
{
if(a[i].opt==1) up[x]+=a[i].val,down[x]+=a[i].val,f[x]+=a[i].val;
if(a[i].opt==2) up[x]=min(up[x],a[i].val),down[x]=min(down[x],a[i].val);
if(a[i].opt==3) up[x]=max(up[x],a[i].val),down[x]=max(down[x],a[i].val);
}
}
void lsx(int x)
{
for(int i=1;i<=shu;i++)
{
if(x+f[i]>=up[i]) x=up[i];
else if(x+f[i]<=down[i]) x=down[i];
else x=x+f[i];
}
cout<<x<<'\n';
}
signed main()
{
freopen("function.in","r",stdin);
freopen("function.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
int x,y;
cin>>x>>y;
a[i]={x,y};
}
shu=(int)pow(n*1.0,1.0/2*1.0);
len=(int)(n*1.0/shu*1.0);
build();
cin>>q;
for(int i=1;i<=q;i++)
{
int op,x,y;
cin>>op>>x;
if(op==4)
{
lsx(x);
continue;
}
cin>>y;
a[x]={op,y};
solve(blo[x]);
}
return 0;
}
/*
10
1 48
1 50
1 180
2 957
1 103
1 100
1 123
3 500
1 66
1 70
3
4 20
4 50
4 700
*/