碎碎念
场上5题铜牌中流,比赛前一晚跟队友打狂父打到一点,早上起来不出意外右手手腕肿了。。(凹了太多次追逐战)
复盘了一下发现确实也只有5题能在场上做出来,实在是时间不够+能力不足捏
目标大概补到8~9题
A
按题意模拟即可,但我写挂了,队友过的
B
一眼看出可以对 xxx 和 yyy 分别二分求解,设左边界为 L=−1000L = -1000L=−1000 ,右边界为 R=1000R = 1000R=1000 ,初始时固定 yyy 为 000,询问 x=Lx = Lx=L 与 x=Rx = Rx=R ,得到左边界与目标点距离 d1d1d1 ,右边界与目标点距离 d3d3d3 ,若 d1<d3d1 < d3d1<d3 可知目标点必定在中点左侧,使 R=L+R2R = \frac{L+R}{2}R=2L+R ,再次询问。否则,可知目标点在中点或中点右侧,由于 intintint 是向下取整,需要使 L=L+R+12L = \frac{L+R+1}{2}L=2L+R+1 ,再次询问,否则可能导致死循环 。距离收敛后,固定 xxx ,对 yyy 进行相同询问即可。
注意询问得到的值为 000 时需立即结束程序,否则会导致 WRONG ANSWER。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define inf 0x3f3f3f3f
int x1,x2,x3;
int y1,y2,y3;
int nowx,nowy;
string s;
int ask(int x,int y)
{
cout<<x-nowx<<' '<<y-nowy<<endl;
fflush(stdout);
nowx=x,nowy=y;
int ans;
cin>>ans;
return ans;
}
void solve()
{
int d0=0,d1=0,d3=0;
int L=-1000,R=1000,MID;
cin>>d0;
if(d0==0) return;
d1=ask(L,0);
if(d1==0) return;
d3=ask(R,0);
if(d3==0) return;
while(L<R)
{
if(d1<d3)
{
MID=(L+R)>>1;
d3=ask(MID,nowy);
if(d3==0) return;
R=MID;
}
else if(d1>d3)
{
MID=(L+R+1)>>1;
d1=ask(MID,nowy);
if(d1==0) return;
L=MID;
}
else
{
MID=(L+R)>>1;
if(ask(MID,nowy)==0) return;
break;
}
}
L=-1000,R=1000;
d1=ask(nowx,L);
if(d1==0) return;
d3=ask(nowx,R);
if(d3==0) return;
while(L<R)
{
if(d1<d3)
{
MID=(L+R)>>1;
d3=ask(nowx,MID);
if(d3==0) return;
R=MID;
}
else if(d1>d3)
{
MID=(L+R+1)>>1;
d1=ask(nowx,MID);
if(d1==0) return;
L=MID;
}
else
{
MID=(L+R)>>1;
if(ask(nowx,MID)==0) return;
break;
}
}
}
main()
{
solve();
}
F
构造方式很简单,按照元素递增的顺序倒着填即可。 若数组为 1 1 2 2 3 3 1 11\ 1\ 2\ 2\ 3\ 3\ 1\ 11 1 2 2 3 3 1 1 ,可以构造出 4 3 6 5 8 7 2 14\ 3\ 6\ 5\ 8\ 7\ 2\ 14 3 6 5 8 7 2 1 。问题在于如何判断非法。有以下三个条件必须满足:
- f[i]≤if[i]\le if[i]≤i
- f[i]≤max(f[j]+1) (1≤j<i)f[i] \le max(f[j]+1)\ \ (1\le j<i)f[i]≤max(f[j]+1) (1≤j<i)
- f[i]≥1f[i]\ge 1f[i]≥1
场上读假题一次,判断非法错了若干次,到最后一小时才通过,令人感叹。。
G
可以用两个队列存双方宝可梦的信息,也是按照题意模拟即可。
场上没有看出来能量是属于每个宝可梦的,而不是属于双方角色的,又喜提3发罚时,乐
H
瞪了40min才看懂题意,其实就是求每个SiS_iSi 在 TiT_iTi 的所有子串的出现次数总和。
对于一个字符串 sss ,假设它在字符串 ttt 中匹配到的位置是 iii (这里指 sss 中最后一个字母在 ttt 中的位置是 iii),则 ttt 的所有子串中包含 sss 的有 (i−∣s∣+2)×(∣t∣−i)(i-|s|+2)\times (|t|-i)(i−∣s∣+2)×(∣t∣−i) 个,且题目需要求总的出现次数,因此即使 ttt 中包含多个 sss ,也只需要将每一个匹配到 sss 时的答案加和即可,不需要去重。由于题目是多个字符串在 ttt 中匹配,因此,需要构建AC自动机进行多模匹配。每次查询TiT_iTi的下一个字符,如果在AC自动机上匹配到 sss ,将答案加上 (i−∣s∣+2)×(∣t∣−i)(i-|s|+2)\times (|t|-i)(i−∣s∣+2)×(∣t∣−i),再沿着 $ fail$ 边接着统计答案。
交了喜提TLE,问题就在于每次匹配到一个字符串后总会沿着 failfailfail 边暴力上跳到这个字符串的最大后缀处,导致了很多重复计算,如果数据够强,这种做法复杂度会被卡到 ∑∣T∣⋅∑∣S∣\sum|T| \cdot \sum|S|∑∣T∣⋅∑∣S∣。想到我们每次相当于查询 TTT 的一个前缀,即 ∣T∣−i|T|-i∣T∣−i 是固定的,如果能求出这个前缀所有后缀的总匹配次数 cntcntcnt 和总字符数 allsizeallsizeallsize ,则当前前缀的所有可匹配后缀的总答案就是 (∣T∣−i)⋅((i+2)⋅cnt−allsize)(|T|-i)\cdot ((i+2)\cdot cnt-allsize)(∣T∣−i)⋅((i+2)⋅cnt−allsize) 。这样就能 O(1)O(1)O(1) 地统计答案。
可以采用类似前缀和的形式求,使用 visvisvis 数组判断当前点是否已经被加和,如果没有,则对 failfailfail 边dfs统计前缀和,并将路径上的 visvisvis 数组设为true。否则,直接计算当前点的答案即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define inf 0x3f3f3f3f
const int N=1e6+100,mod=1e9+7;
int ch[N][26],ne[N],cnt[N],in[N],allsize[N],idx;
bool vis[N];
string s;
vector<int> vec[N];
void insert(string s)
{
int p=0;
for(int i=0;s[i];i++)
{
if(!ch[p][s[i]-'a']) ch[p][s[i]-'a']=++idx;
p=ch[p][s[i]-'a'];
}
cnt[p]++;
allsize[p]+=s.size();
}
void build()
{
queue<int> q;
for(int i=0;i<26;i++)
if(ch[0][i]) q.push(ch[0][i]);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=0;i<26;i++)
{
int v=ch[u][i];
if(v)
{
ne[v]=ch[ne[u]][i],q.push(v);
}
else ch[u][i]=ch[ne[u]][i];
}
}
}
void dfs(int j)
{
if(vis[j]||j<=0) return;
dfs(ne[j]);
vis[j]=1;
if(ne[j]>0)
{
allsize[j]+=allsize[ne[j]];
cnt[j]+=cnt[ne[j]];
}
}
long long query(string s)
{
int ans=0;
for(int k=0,i=0;s[k];k++)
{
i=ch[i][s[k]-'a'];
dfs(i);
ans=(ans+(long long)(s.size()-k)%mod*(cnt[i]*(k+2)-allsize[i])%mod)%mod;
}
return ans;
}
void solve()
{
IOS;
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>s;
insert(s);
}
build();
for(int i=1;i<=m;i++)
{
cin>>s;
cout<<query(s)<<'\n';
}
}
main()
{
solve();
}
K
狠狠地猜结论,输出 1n\frac{1}{n}n1 即可。
L
注意到数据范围很小,刚开始以为是什么差分约束题,一看数据范围直接暴力枚举 AiA_iAi 所有取值,对于每一种情况都统计评委得分,取最大值即可。
文章讲述了在算法竞赛中处理模拟题目(如区间搜索和字符串匹配)的方法,涉及二分查找、AC自动机、动态规划等技术,以及如何优化查询过程以减少重复计算。
3662

被折叠的 条评论
为什么被折叠?



