2023.1.13测试结题报告及问题反思
首先声明,作者菜鸡一个,如有错误欢迎指出。
Secret Message 秘密信息
读题,会发现题目就让球两个玩意:1. 给定字符串,求其是多少个字符串的前缀。2.给定字符串,求其有多少个字符串是他的前缀。
这两个玩意,第一个可以维护
#define N 505005
int t[N<<2][2],ed[N<<2],siz[N<<2],cnt=1,n,m;
char c[105005];
void insert(char a[],int len){
int p=1;
for(int i=1;i<=len;i++){
int x=a[i]-'0';
if(!t[p][x])t[p][x]=++cnt;
p=t[p][x];
siz[p]++;
}
ed[p]++;
}
int find(char a[],int len){
int p=1,ans=0;
for(int i=1;i<=len;i++){
int x=a[i]-'0';
if(!t[p][x])return ans;
p=t[p][x];
ans+=ed[p];
}
ans+=siz[p]-ed[p];
return ans;
}
int main(){
//freopen("secret.in","r",stdin);
//freopen("secret.out","w",stdout);
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
int k;cin>>k;
for(int j=1;j<=k;j++)cin>>c[j];
insert(c,k);
}
for(int i=1;i<=m;i++){
int k;cin>>k;
for(int j=1;j<=k;j++)cin>>c[j];
cout<<find(c,k)<<"\n";
}
return 0;
}
子序列
Magic简化版,套路地运用异或前缀和,设
然后问题化为:求满足
显然枚举一个solve(s,t)
表示对于
设
对于答案的计算,可以将其分为两部分:可以在当前位解决的和留在后续解决的。
则我们设指针
分类讨论:
。此时,我们若想要保持 的可能,就需要让 的第 位为1,也即我们填上 ,此时我们无法计算出答案 ,类比情况一,填上 ,此时我们将 填为 ,当填为 时,第 位无论填什么都可以对答案产生贡献,所以直接累加上 的贡献并将 填为 即可。 ,类比情况三,可以得到算上 的贡献然后将 填为0即可。
Code:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define N 5050500
#define int long long
int t[N<<2][2],siz[N<<2],n,m,cnt=1,s[N<<1],ans;
void insert(int k){
int p=1;
for(int i=54;i>=0;--i){
int x=(k>>i)&1;
if(!t[p][x])t[p][x]=++cnt;
p=t[p][x];
siz[p]++;
}
return ;
}
int find(int s,int tt){
int ans=0,p=1;
for(int i=54;i>=0;--i){
if(!p)return ans;
int x=(s>>i)&1,y=(tt>>i)&1;
if(!y){
ans+=siz[t[p][x^1]];
p=t[p][x];
}
else {
p=t[p][x^1];
}
}
return ans;
}
void read(int &x){
int s=0,w=1;
char ch=getchar();
while(ch>'9'||'0'>ch){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch>='0'&&'9'>=ch){
s=s*10+ch-'0';
ch=getchar();
}
x=s*w;
return ;
}
signed main(){
//freopen("subsequence.in","r",stdin);
//freopen("subsequence.out","w",stdout);
read(n),read(m);
for(int i=1;i<=n;i++)read(s[i]);
for(int i=1;i<=n;i++)s[i]^=s[i-1];
insert(0);
for(int i=1;i<=n;i++)insert(s[i]);
for(int i=1;i<=n;i++){
ans+=find(s[i],m-1);
}
ans+=find(0,m-1);
cout<<ans/2;
return 0;
}
播放列表
首先明确一个性质:设
很显然的对吧。
那么,就可以求出所有的
所以可以设
那么维护一个单调队列搞最大值,不满足要求的就出队,然后
接着,我们再将
所以代码非常简洁。需要注意的是,由于需要跑两圈,所以应该复制为三倍。
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i+n]=a[i+n+n]=a[i];
ans[i+n]=ans[i+n+n]=ans[i]=-1;
}
for(int i=1;i<=3*n;i++){
while(h<=t&&a[q[h]]>a[i]*2)ans[q[h++]]=i;
while(h<=t&&a[q[t]]<=a[i])f[q[t]]=i,t--;
q[++t]=i;
}
for(int i=3*n;i;--i)if(f[i])ans[i]=ans[f[i]];
for(int i=1;i<=n;i++){ans[i]-=i;if(ans[i]<0)ans[i]=-1;}
for(int i=1;i<=n;i++)cout<<ans[i]<<" ";
特别行动队
板子题,划分区间。
设
按照斜率优化套路,整理式子,提出仅含
稍微整理,设
可以得到:
注意到
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define N 1006060
#define int long long
int q[N],h=1,t=1,n,m,a,b,c,s[N],f[N];
int X(int x){
return 2*s[x];
}
int Y(int x){
return f[x]+a*s[x]*s[x]-b*s[x];
}
int up(int i,int j){
return Y(i)-Y(j);
}
int down(int i,int j){
return X(i)-X(j);
}
long double slope(int i,int j){
return down(i,j)==0?1e18:1.0*up(i,j)/down(i,j);
}
void get(int i,int j){
// cout<<i<<" "<<j<<endl;
f[i]=f[j]+a*(s[i]-s[j])*(s[i]-s[j])+b*(s[i]-s[j])+c;
}
void read(int &x){
int s=0,w=1;
char ch=getchar();
while(ch>'9'||'0'>ch){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch>='0'&&'9'>=ch){
s=s*10+ch-'0';
ch=getchar();
}
x=s*w;
}
signed main(){
//freopen("special.in","r",stdin);
//freopen("special.out","w",stdout);
read(n),read(a),read(b),read(c);
for(int i=1;i<=n;i++)f[i]=-0x3f3f3f3f3f3f3f;
for(int i=1;i<=n;i++)read(s[i]);
for(int i=1;i<=n;i++)s[i]+=s[i-1];
for(int i=1;i<=n;i++){
while(h<t&&slope(q[h],q[h+1])>=1.0*a*s[i])h++;
get(i,q[h]);
while(h<t&&slope(q[t],q[t-1])<=slope(i,q[t]))t--;
q[++t]=i;
}
cout<<f[n];
return 0;
}
CF631E
首先,设
设
所以,分类讨论。
第一个情况,
第二个情况,
二者等价,都为:
所以,设
套路:比较决策
进行移项,变式,设
则
小于号,下凸壳。
需要注意的是,
而在此题中有特殊情况,也即所有的
这里有两种处理方式,第一种是对
#include<bits/stdc++.h>
using namespace std;
#define N 500500
#define int long long
int n,f[N],g[N],q[N],s[N],h=1,t=1,a[N],S;
int Y(int x){
return s[x];
}
int X(int x){
return x;
}
int up(int i,int j){
return Y(i)-Y(j);
}
int down(int i,int j){
return X(i)-X(j);
}
long double slope(int i,int j){
return down(i,j)==0?1e18:1.0*up(i,j)/down(i,j);
}
void get1(int i,int j){
// cout<
f[i]=s[i]-s[j]+(j-i)*a[i];
}
void read(int &x){
int s=0,w=1;
char ch=getchar();
while(ch>'9'||'0'>ch){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch>='0'&&'9'>=ch){
s=s*10+ch-'0';
ch=getchar();
}
x=s*w;
}
inline int find (int val){//二分找斜率
int L=h+1, R=t, cur=1;
while(L<=R){
int mid=(L+R)>>1;
if(slope(q[mid],q[mid-1])<=1.0*val)L=mid+1,cur=mid;//注意这个二分别挂掉了。
else R=mid-1;
}
return q[cur];
}
signed main(){
//freopen("maxweight.in","r",stdin);
//freopen("maxweight.out","w",stdout);
read(n);
for(int i=1;i<=n;i++)read(a[i]);
for(int i=1;i<=n;i++)S+=a[i]*i,s[i]=s[i-1]+a[i];
for(int i=1;i<=n;i++){
while(h<t&&slope(i,q[t])<=slope(q[t],q[t-1]))--t;//下凸壳,斜率递减
q[++t]=i;
}
for(int i=1;i<=n;i++){
get1(i,find(a[i]));
}
int ans=0;
for(int i=1;i<=n;i++)ans=max(ans,f[i]);
cout<<S+ans;
return 0;
}
总结
事实上,在本次测试中,鄙人呈现出以下错误:
-
粗心大意,T2并未注意到答案需要
long long
,100->15 -
盲目自信,在调试T5时对自己推的式子过于自信,导致调试1h+无果,事实上下来重新推一次式子轻松AC
-
转化能力弱,思维能力弱,需要加强,在T3并未发现性质,导致对于自己的单调队列做法过分怀疑,只打了暴力
解决方案:
- 每次考试预留10min左右时间检查答案是否爆int,数组大小是否不当,函数返回值是否没写,能否通过编译,使用函数的头文件是否写上去了,是否存在越界风险和除0,
- 在检查代码无问题后,若无果,需要对思路重新进行梳理
- 多练题,独立思考
- 每次对拍必须搞几组极限数据
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!