冲刺国赛模拟 27
感觉今天 T2 十分的迷惑。复杂度多个
地图编辑
先判无解。首先
剩下的都有解。因为任意局面一定能删一个块使得最短路长度最多
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const int dx[]={1,0,0,-1},dy[]={0,1,-1,0};
int n,m,d,dis[1010][1010];
bool vis[1010][1010];
char s[1010][1010];
pair<int,int>S,T;
queue<pair<int,int> >q;
bool check1(int x,int y){
return x>=1&&x<=n&&y>=1&&y<=m&&s[x][y]!='#'&&dis[x][y]==-1;
}
void bfs(){
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)dis[i][j]=-1;
q.push(S);dis[S.first][S.second]=0;
while(!q.empty()){
pair<int,int> x=q.front();q.pop();
for(int i=0;i<4;i++){
if(check1(x.first+dx[i],x.second+dy[i])){
dis[x.first+dx[i]][x.second+dy[i]]=dis[x.first][x.second]+1;
q.push({x.first+dx[i],x.second+dy[i]});
}
}
}
}
bool check(int x,int y){
return x>1&&x<n&&y>1&&y<m&&!vis[x][y]&&s[x][y]=='#';
}
vector<pair<int,int> >bl;
void dfs(int x,int y){
vis[x][y]=true;bl.push_back(make_pair(x,y));
for(int i=0;i<4;i++){
if(check(x+dx[i],y+dy[i]))dfs(x+dx[i],y+dy[i]);
}
}
int main(){
scanf("%d%d%d",&n,&m,&d);
for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
dis[i][j]=-1;
if(s[i][j]=='S')S=make_pair(i,j);
if(s[i][j]=='F')T=make_pair(i,j);
}
int val=abs(S.first-T.first)+abs(S.second-T.second);
if(d<val||(d&1)!=(val&1)){
puts("No");return 0;
}
bfs();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(dis[i][j]==-1&&s[i][j]!='#'){
puts("nsdd");return 0;
}
}
}
if(dis[T.first][T.second]<d){
puts("No");return 0;
}
puts("Yes");
for(int i=2;i<n;i++){
if(check(i,2))dfs(i,2);
if(check(i,m-1))dfs(i,m-1);
}
for(int i=2;i<m;i++){
if(check(2,i))dfs(2,i);
if(check(n-1,i))dfs(n-1,i);
}
for(int i=2;i<n;i++)for(int j=2;j<m;j++)if(check(i,j))dfs(i,j);
int l=0,r=bl.size();
while(l<r){
int mid=(l+r)>>1;
for(int i=0;i<mid;i++)s[bl[i].first][bl[i].second]='#';
for(int i=mid;i<bl.size();i++)s[bl[i].first][bl[i].second]='.';
bfs();
if(dis[T.first][T.second]>=d)r=mid;
else l=mid+1;
}
for(int i=0;i<l;i++)s[bl[i].first][bl[i].second]='#';
for(int i=l;i<bl.size();i++)s[bl[i].first][bl[i].second]='.';
for(int i=1;i<=n;i++)printf("%s\n",s[i]+1);
return 0;
}
摸底测试
我以为我秒了。结果赛后过题。典。
首先我搬过一个类似的题。先假装我们可以速算
然后考虑速算
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int n,k,ans,f[50010],dfn[100010],cnt[100010];
char s[50010];
struct SAM{
int cnt,last,len[100010],fa[100010],trie[100010][26],mx[100010],mn[100010];
void clear(){
for(int i=1;i<=cnt;++i){
len[i]=fa[i]=mx[i]=0,mn[i]=0x3f3f3f3f;
for(int j=0;j<26;j++)trie[i][j]=0;
}
last=cnt=1;
}
void ins(int ch,int id){
int p=last;last=++cnt;
len[last]=len[p]+1;mx[last]=mn[last]=id;
while(p&&!trie[p][ch])trie[p][ch]=cnt,p=fa[p];
if(!p){
fa[cnt]=1;return;
}
int q=trie[p][ch];
if(len[p]+1==len[q]){
fa[cnt]=q;return;
}
len[++cnt]=len[p]+1;
for(int i=0;i<26;i++)trie[cnt][i]=trie[q][i];
fa[cnt]=fa[q];fa[q]=cnt;fa[last]=cnt;
while(trie[p][ch]==q)trie[p][ch]=cnt,p=fa[p];
}
}sam;
long long val[50010],d[50010];
void update(int l,int r,int k,int D=0){
if(l>r||l<=0||r<=0)return;
if(D==-1)k=r-l+1;
val[l]+=k;
if(!D)val[r+1]-=k;
else d[l+1]+=D,d[r+2]-=D;
}
long long get(int l,int r){
for(int i=l;i<=r;i++)sam.ins(s[i]-'a',i-l+1);
for(int i=0;i<=r-l+1;i++)cnt[i]=val[i]=d[i]=0;
for(int i=1;i<=sam.cnt;i++)cnt[sam.len[i]]++;
for(int i=1;i<=r-l+1;i++)cnt[i]+=cnt[i-1];
for(int i=1;i<=sam.cnt;i++)dfn[cnt[sam.len[i]]--]=i;
for(int i=sam.cnt;i>=2;i--){
int x=dfn[i];
sam.mx[sam.fa[x]]=max(sam.mx[sam.fa[x]],sam.mx[x]);
sam.mn[sam.fa[x]]=min(sam.mn[sam.fa[x]],sam.mn[x]);
}
for(int x=2;x<=sam.cnt;x++){
update(sam.mn[x],sam.mx[x]-sam.len[x]-1,sam.len[x]-sam.len[sam.fa[x]]);
update(max(sam.mx[x]-sam.len[x],sam.mn[x]),sam.mx[x]-sam.len[sam.fa[x]]-1,0,-1);
}
long long ans=0;
for(int i=1;i<=r-l;i++){
d[i]+=d[i-1];
val[i]+=val[i-1]+d[i];
ans+=val[i]*val[i];
}
sam.clear();
return ans;
}
bool check(long long x){
int l,r,i,cnt,len;
for(i=1,cnt=0;i<=n&&cnt<k;i=l+1,cnt++){
for(len=1;i+len-1<=n;len<<=1){
if(get(i,i+len-1)>x)break;
}
if(len==1)return false;
l=i+(len>>1)-1,r=min(i+len-1,n);
while(l<r){
int mid=(l+r+1)>>1;
if(get(i,mid)<=x)l=mid;
else r=mid-1;
}
}
return i>n;
}
signed main(){
scanf("%d%d%s",&n,&k,s+1);
sam.clear();memset(sam.mn,0x3f,sizeof(sam.mn));
long long l=0,r=get(1,n);
while(l<r){
long long mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
printf("%lld\n",l);
return 0;
}
回文之和
论文题。
结论:任意进制
首先一个数的情况是平凡的。三个数的情况可以枚举第一个变成两个的情况。题解说这个枚举的数不会很大。
两个的情况,设
位数相等的时候看起来要枚举最高位是什么数字,但是发现它是不影响的,仍然只有是否进位两种情况,随便填一个数上去就行了。
代码巨大难写。摆了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】