题解:USACO23OPEN-Silver
题解:USACO23OPEN-Silver
T1 Milk Sum
给定一个长度为
每次修改数组后会将序列还原成原样(修改不继承)
有一个显然的结论:对于
所以将序列从小到大排序得到的
所以预先把排好的原序列存下来,对于每次修改只需要二分出修改后应放的位置,然后(1)减掉原来数的贡献,(2)加上现在数的贡献,(3)所有位置后挪1或前挪1的贡献变化
注意二分后查询时的细节(加1减1)。
#include<bits/stdc++.h>
#define F(i,l,r) for(int i=l;i<=r;++i)
#define G(i,r,l) for(int i=r;i>=l;--i)
#define ll long long
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
char buf[100],*p1=buf,*p2=buf;
inline int gc(){ return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100,stdin),p1==p2)?EOF:*p1++; }
inline int rd(){
int x=0; char ch=gc(); bool f=1;
while(!isdigit(ch)) f^=(ch=='-'),ch=gc();
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=gc();
return f?x:-x;
}
const int N=2e5+5;
ll sum[N],tot=0,a[N],b[N],n,q,x,y;
int main(){
// freopen("a.in","r",stdin);freopen("a.out","w",stdout);
n=rd(); F(i,1,n) a[i]=rd(),b[i]=a[i]; sort(b+1,b+n+1);
F(i,1,n) tot+=b[i]*i,sum[i]=sum[i-1]+b[i];
q=rd(); while(q--){
x=rd(),y=rd();
int u=upper_bound(b+1,b+n+1,y)-b,v=lower_bound(b+1,b+n+1,a[x])-b;
if(v>=u) printf("%lld\n",tot-v*a[x]+u*y+sum[v-1]-sum[u-1]);
else printf("%lld\n",tot-v*a[x]+(u-1)*y+sum[v]-sum[u-1]);
}
return 0;
}
T2 Field Day
(又是逆向思维题...)
给出
暴力是
(1)
※(2)最大值不是很好求,考虑倒过来想,转化成求最小值。
(3)与串
一个数可以由多个给出的串通过这样的取反变化得到,但我们只关心至少要改变几个数位才能得到
什么样的操作顺序使我们需要的呢?灵光一现,考虑广搜,先搜出每个串改1个数位能得到的结果,再考虑改2个数,再改3个,4个....一直到
广搜写法:
#include<cstdio>
#include<queue>
using namespace std;
#define ri register int
#define F(i,l,r) for(ri i=l;i<=r;++i)
const int N=1e5+5;
queue<int> q;
int c,n,a[N],f[(1<<18)+100];
char s[22];
bool vis[(1<<18)+100];
int main(){
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
scanf("%d%d",&c,&n);
F(i,1,n){
scanf("%s",s+1);
int sum=0;
F(j,1,c) sum=(sum<<1)+(s[j]=='G');
a[i]=sum; q.push(sum); vis[sum]=1;
}
while(q.size()){
int x=q.front();q.pop();
F(i,1,c){
int y=x^(1<<(i-1));
if(vis[y] || f[y]) continue;
f[y]=f[x]+1;
vis[y]=1; q.push(y);
}
}
F(i,1,n) printf("%d\n",c-f[(1<<c)-1-a[i]]);
return 0;
}
用循环模拟广搜:
#include<cstdio>
using namespace std;
#define ri register int
#define F(i,l,r) for(ri i=l;i<=r;++i)
#define min(x,y) x<y?x:y
const int N=1e5+5;
int sum,c,n,a[N],f[(1<<18)+100];
char s[22];
int main(){
freopen("b.in","r",stdin); freopen("b.out","w",stdout);
scanf("%d%d",&c,&n);
F(i,0,(1<<c)-1) f[i]=99999999;
F(i,1,n){
scanf("%s",s+1);
sum=0;
F(j,1,c) sum=(sum<<1)+(s[j]=='G');
f[sum]=0;
a[i]=sum;
}
F(i,1,c) F(j,0,(1<<c)-1) f[j^(1<<i-1)]=min(f[j^(1<<i-1)],f[j]+1);
F(i,1,n) printf("%d\n",c-f[(1<<c)-1-a[i]]);
return 0;
}
结合两种方法而观之,发现循环其实是dp,广搜其实是记搜...
好好好万物皆可dp是吧
T3 Pareidolia
给定一个仅包含小写字母的字符串
定义函数 bessie
相连的形式(bessiebessiebessie...
),返回bessie
的最大数量。
如
求
两个误区:
(1)一个字符最多只能存在于一个bessie中而非多个。还担心会不会一匹配多,把问题想复杂了
(2)审题不清:没发现任意字母都可以删去,还以为是KMP,写到最后再读题发现问题之后哭死,只剩不到1h,直接失去继续写下去的动力了。。。(想好再下笔!!!)
对我来说,光是如何简明地书写判断是否找到了一个新的bessie都有难度。。。
由于模式串是固定的而且只有六位,直接对于 b,e,s,i
这几种字符记录我所在的bessie串的开头b所在的位置即可。开头记录下来,串的位置当然也就确定啦!而且后面统计答案还要用到
考虑新发现一个bessie串对答案的贡献。记
emm...可以感性理解为:继承没发现这个串之前的答案 + 起点为1-pos,终点固定成i的所有串都会多看到当前这个新串。
最终答案
注意有些字符的更新是有顺序的,不要写挂了。
#include<cstdio>
const int N=3e5+5;
char s[N];
int p[10];
long long f[N],sum=0;
int main(){
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
scanf("%s",s+1);
for(int i=1;s[i];++i){
// F(i,1,6) printf("%d ",p[i]); puts("");
if(s[i]=='b') p[1]=i;
else if(s[i]=='e') p[2]=p[1],p[6]=p[5];
else if(s[i]=='s') p[4]=p[3],p[3]=p[2];//不能写反,否则一个's'会同时更新p[4],p[3]
else if(s[i]=='i') p[5]=p[4];
if(p[6]) f[i]=f[p[6]-1]+p[6];
//f[i]:以i结尾的所有子串的B函数之和
//p[6]:以i结尾的能含有当前这个新增bessie的子串的数量
//p[6]位置以前的所有串还能多包含一个bessie(即当前新增的这个),所以要+f[p[6]-1]
sum+=f[i];
} printf("%lld",sum);
return 0;
}
存疑:为什么下面这种写法是错的???
#include<bits/stdc++.h>
using namespace std;
char c[300005];
unsigned long long p[10];
int main(){
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
scanf("%s",c+1);
unsigned long long lenc=strlen(c+1);
unsigned long long ans=0;
unsigned long long sum=0;
for(unsigned long long i=1;i<=lenc;i++){
if(c[i]=='b') p[1]=i;
if(c[i]=='e'){
p[2]=p[1];
if(p[5]!=p[6]) sum+=p[5];
p[6]=p[5];
}
if(c[i]=='s') p[4]=p[3],p[3]=p[2];
if(c[i]=='i') p[5]=p[4];
ans+=sum;
}
printf("%llu",ans);
return 0;
}
模拟赛总结:
1.感觉T1写了近两个小时有点慢了,如果把找
2.T2部分分拿的还是很稳的,但对于C较小这个性质的运用还是差了些:只想到了用bitset优化异或过程。还有,积累逆向思维的经验:原问题不好想,那就承认它不好想,就大胆考虑倒过来想
(由于正着做不好想,所以我们考虑倒过来想)
3.T3首先审题不清(想好再下笔),第二想复杂了,被吓到了(还是要多手玩几个样例去自己体会题目的要求,不要偷懒 ~ ~ ~)
写在最后:距离NOIP2023仅剩16天,耳边又想起了中考前我的语文老师告诉我的那句话,
“行百里者半九十。”
希望不留遗憾~加油NOIP2023!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具