题解-牛客IOI周赛25
A-字符串修改
模拟
注意加减法的取模就行了
#include<bits/stdc++.h>
using namespace std;
int n;
char a[100005];
int main(){
scanf("%d",&n);
scanf("%s",a);
for (int i=1;i<=n;i++){
int x=a[i-1]-'a';
if (i&1)x=x+i;
else x=x-i;
x+=2600000;
printf("%c",x%26+'a');
}
} B-学姐的编码1.0 序列自动机+dp
f[i]表示以i所代表的的字符为结尾的合法编码方案数,每次从最近的合法前置进行答案更新,可以保证不重复统计
复杂度O(16*n)
十六进制只有0~9,A~F共16种情况,最后枚举十六种情况,f[i]累加就是答案
#include<bits/stdc++.h>
using namespace std;
int n;
int g[50];
int f[1000005];
char a[1000005];
int main(){
scanf("%s",a);
n=strlen(a);
memset(f,0,sizeof(f));
for (int i=0;i<16;i++)g[i]=-1;
for (int i=0;i<n;i++){
int x;
if (a[i]<='9')x=a[i]-48;
else x=a[i]-55;
for (int j=0;j<x;j++)
if (g[j]!=-1)f[i]+=f[g[j]];
g[x]=i;f[i]++;
}
int ans=0;
for (int i=0;i<16;i++)
if (g[i]!=-1)ans+=f[g[i]];
printf("%d\n",ans);
return 0;
} C-学姐的编码2.0 序列自动机+dfs
这里涉及到一个关于答案量的计算,16进制,按位递增,满足这两个条件的合法编码最大方案数是2^16-1,所以只要不重复统计,在复杂度上是不会出现问题的
这里先序列自动机有一个复杂度O(16*n)的预处理,然后后面是一个复杂度O(16*方案数)的dfs
搞清楚递归调用的机制,倒序预处理,递归输出后正好就是字典序递增的答案
#include<bits/stdc++.h>
using namespace std;
const char p[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char a[1000005];
int n,nt[1000005][20],g[20];
void dfs(int x,int y,string s){
if (y==n+1)return;
cout<<s+p[x]<<endl;
for (int i=x+1;i<16;i++)dfs(i,nt[y][i],s+p[x]);
}
int main(){
scanf("%s",a);
n=strlen(a);
for (int i=0;i<=9;i++)g[i]=n+1;
for (int i='A';i<='F';i++)g[i-55]=n+1;
for (int i=n;i>=1;i--){
int x;
if (a[i-1]>='0'&&a[i-1]<='9')x=a[i-1]-'0';
else x=a[i-1]-55;
for (int j=0;j<16;j++)nt[i][j]=g[j];
g[x]=i;
}
for (int i=0;i<16;i++)dfs(i,g[i],"");
} D-迷阵 枚举答案+验证
分成两部分操作
验证:如果给定上界Max和下界Min,可以确定极差dt=Max-Min,把[Min,Max]作为限制条件从(1,1)开始遍历,如果(n,n)能被遍历到说明dt=Max-Min是一个合法解,复杂度O(n*n)
枚举答案:双指针l,r枚举上下界,l,r的初始值为矩阵里的最小值和最大值(一个没什么大影响的优化,直接设l=0,r=3000也没有关系),如果(l,r)是一对合法解r--,缩小答案,如果不合法把整个区间向右平移一位,即l++,r++,复杂度是线性的,即O(区间长度)
#include<bits/stdc++.h>
using namespace std;
const int p[4][2]={{0,-1},{0,1},{1,0},{-1,0}};
bool vis[105][105];
int n,l,r,ans;
int a[105][105];
bool pd(int x,int y){
if (x<1||y<1||x>n||y>n)return 0;
if (vis[x][y])return 0;
return 1;
}
void pa(int x, int y, int xx, int yy){
vis[x][y]=1;
if (vis[n][n])return;
for (int i=0;i<4;i++)
if (pd(x+p[i][0],y+p[i][1]))
if (a[x+p[i][0]][y+p[i][1]] >= xx&&a[x + p[i][0]][y + p[i][1]] <= yy)pa(x + p[i][0], y + p[i][1], xx, yy);
}
int main(){
scanf("%d",&n);
l=3001;r=-1;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
l=min(l,a[i][j]);r=max(r,a[i][j]);
}int p=r;ans=r-l;r--;
while (l<=r){
if (r>p||l>a[1][1]||l>a[n][n])break;
while (l<=r){
if (r<a[1][1]||r<a[n][n])break;
memset(vis,0,sizeof(vis));
pa(1,1,l,r);
if (vis[n][n]) ans=r-l,r--;
else break;
}
l++;r++;
}
printf("%d\n",ans);
return 0;
} 
