如果说,生命的脚步终有一天被时间的尘埃|

OoXiao_QioO

园龄:2年3个月粉丝:15关注:7

平邑集训(补题)

Day 1

A 咕咕

题目描述



解法

DP,设 dpi,j 表示从 (1,1) 走到 (n,m) 的方案数。

转移的时候,需要按照给定的限制走,如果一个点的(2)(3)限制冲突了,那么就标记一下,经过他的时候绕过他,时间复杂度 O(nm)

代码

点击查看代码
int n,m,t;
int f[3001][3001];
int dp[3001][3001];
void solve()
{
cin>>n>>m>>t;
int i,j;
while(t--)
{
int a,b,c,d;
cin>>a>>b>>c>>d;
bool flag = 0;
if(a==n&&b==m)
continue;
if((c==a+1&&d==b)||(d==b+1&&a==c))
flag = 1;
if(!flag||f[a][b]==-1)
{
f[a][b] = -1;
continue;
}
if(c==a+1)
{
if(f[a][b]==2)
f[a][b] = -1;
else
f[a][b] = 1;
}
else if(d==b+1)
{
if(f[a][b]==1)
f[a][b] = -1;
else
f[a][b] = 2;
}
}
if(f[1][1]==-1)
{
cout<<0<<endl;
return;
}
dp[1][1] = 1;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
if(f[i][j]==-1)
dp[i][j]=0;
else
{
if(f[i-1][j]!=2)
dp[i][j] += dp[i-1][j];
if(f[i][j-1]!=1)
dp[i][j] += dp[i][j-1];
dp[i][j] %= mod;
}
}
cout<<dp[n][m]<<endl;
return;
}

B 找子串

题目描述

解法

  • Subtask 1

每次删掉 T 后重新暴力再找第一个 T,时间复杂度 O(|S||T||S||T|)

  • Subtask 2

每次删掉 T 后用 kmp 或哈希找到第一个 T,时间复杂度 O(|S||T||S|)

  • Subtask 3

每次删掉 T 后,从删掉位置之前的 T 个位置开始,用 kmp 或哈希找 T,时间复杂度 O(|S||T|)

  • 满分做法

用 kmp 从 S 中找 T 时,对于 S 中的每一个位置 i,记录以 i 为结尾的子串,和 T 最多匹配到哪里,可以用一个数组记录下来,比如 match

举个例子:若 S="gogoododgoodluck",T="good".
match0=0,因为 S 中的 gT 中的 g 匹配。
match1=1,因为 S 中的 goT 中的 go 匹配。
match2=0,因为 S 中的 gT 中的 g 匹配。
match3=1,因为 S 中的 goT 中的 go 匹配。
match4=2,因为 S 中的 gooT 中的 goo 匹配。
match5=3,因为 S 中的 goodT 中的 good 匹配。

在上面的例子中,如果将第一个 goodS 中删除后,没有必要从头开始找 good,因为以前就知道 match1=1,因此从 S1 处继续 kmp 即可,可以通过栈来实现。

代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 7;
char s[maxn], t[maxn];
char sta[maxn];
int fail[maxn], fail1[maxn], n, m, top;
void init()
{
for (int i = 2, j = 0; i <= m; i++)
{
while (j && t[i] != t[j + 1])
{
j = fail[j];
}
if (t[i] == t[j + 1])
j++;
fail[i] = j;
}
}
void kmp()
{
for (int i = 1, j = 0; i <= n; i++)
{
sta[++top] = s[i];
while (j && sta[top] != t[j + 1])
{
j = fail[j];
}
if (sta[top] == t[j + 1])
j++;
fail1[top] = j;
if (j == m)
{
top -= m;
j = fail1[top];
}
}
}
int main()
{
scanf("%s", s + 1);
scanf("%s", t + 1);
n = strlen(s + 1);
m = strlen(t + 1);
init();
kmp();
for (int i = 1; i <= top; i++)
printf("%c", sta[i]);
return 0;
}

C LCS 问题

题目描述

思路

  • 对于前 60% 的数据

因为序列长度最多为 5000,所以可以暴力 LCS。考虑 dp,fi,j 表示 a 数组前 i 个数和 b 数组前 i 个数的最长公共子序列。

如果 ai=bj,那么 fi,j=max(fi1,j,fi,j1,fi1,j1+1)

然后 fi,j=max(fi1,j,fi,j1)

时间复杂度为 O(n2)

  • 满分做法

关键在于保证 1 nn 个数在 a,b 中分别出现 5 次。枚举 i,同时维护 fj 表示 a 数组前 i 个数和 b 数组前 j 个数的最长公共子序列。同时要求这个最长公共子序列在 b 中必须以 bj 结尾。

一开始对于每个 x,用二维数组存下数值 xb 中的所有位置。枚举 i 时,枚举数值 aib 中的所有位置 k。这时候所有的 fj 都是 a 数组中前 i 个数和 b 数组中前 j 个数的最长公共子序列。

我们令 gk=maxi=1k1fi+1,那么 gk 也就是 a 数组中前 i 个数和 b 数组中前 k 个数的最长公共子序列。

对于 bjaij,显然 gj=fj,也就是说 fj 不用改动。

那么我们现在就要单点修改,求前缀最大值,用树状数组维护 fj 的前缀最大值,时间复杂度 O(nlogn)

代码

点击查看代码
inline int lowbit(int x)
{
return x&(-x);
}
inline void change(int x,int y)
{
for(int i=x;i<=N;i+=lowbit(i))
f[i]=max(f[i],y);
return;
}
inline int query(int x)
{
int res=0;
for(int i=x;i;i-=lowbit(i))
res=max(f[i],res);
return res;
}
for(int i=1;i<=n5;i++)
{
int x=read();
c[x][++cnt[x]]=i;
}
for(int i=1;i<=n5;i++)b[i]=read();
for(int i=1;i<=n*5;i++)
for(int j=5;j;j--)
{
int res=query(c[b[i]][j]-1);
change(c[b[i]][j],res+1);

D 舞步

题目描述

Farmer John 的奶牛们正在炫耀她们的最新舞步!

最初,所有的 N 头奶牛(2N105)站成一行,奶牛 i 排在其中第 i 位。舞步序列给定为 K1K2×105)个位置对 (a1,b1),(a2,b2),,(aK,bK)。在舞蹈的第 i=1K 分钟,位置 aibi 上的奶牛交换位置。同样的 K 次交换在第 K+12K 分钟发生,在第 2K+13K 分钟再次发生,以此类推,周期性地持续共 M 分钟(1M1018)。换言之,

  • 在第 1 分钟,位置 a1b1 上的奶牛交换位置。
  • 在第 2 分钟,位置 a2b2 上的奶牛交换位置。
  • ……
  • 在第 K 分钟,位置 aKbK 上的奶牛交换位置。
  • 在第 K+1 分钟,位置 a1b1 上的奶牛交换位置。
  • 在第 K+2 分钟,位置 a2b2 上的奶牛交换位置。
  • 以此类推……

对于每头奶牛,求她在队伍中会占据的不同的位置数量。

注意:本题每个测试点的时间限制为默认限制的两倍。

输入格式

输入的第一行包含 NKM。以下 K 行分别包含 (a1,b1)(aK,bK)1ai<biN)。

输出格式

输出 N 行,第 i 行包含奶牛 i 可以到达的不同的位置数量。

提示

7 分钟之后,各个位置上的奶牛为 [3,4,5,2,1,6]

  • 奶牛 1 可以到达位置 {1,2,3,4,5}
  • 奶牛 2 可以到达位置 {1,2,3,4}
  • 奶牛 3 可以到达位置 {1,2,3}
  • 奶牛 4 可以到达位置 {2,3,4}
  • 奶牛 5 可以到达位置 {3,4,5}
  • 奶牛 6 从未移动,所以她没有离开过位置 6

测试点性质:

  • 测试点 1-5 满足 N100,K200
  • 测试点 6-10 满足 M=1018
  • 测试点 11-20 没有额外限制。

我们先考虑弱化版,即将 周期性地持续共 M 分钟 改为 无限循环

弱化版

考虑经过 k 分钟后,每头牛会途径某些点到达另一个点,假如 Ax 位置走到了 y 位置,Bx 走到了 x,那么再经过一轮,B 也会走到 y 位置。

也就是说 B 的运动轨迹会和 A 一样,只不过落后 k 分钟罢了。同时 B 经过的点也和 A 一样,所以像 A,B 一样的有相同运动轨迹的牛,它们的运动轨迹将会在 k 分钟之内构成一个环。

而环可以用并查集维护。接下来用 vector 记录每个点经过的点,对于一个环内的牛,用 set 统计每个点经过了多少个点,设为 x,则环内每一个牛能经过的点数也就是 x

时间复杂度 O(n+k)

普通版

也就是多了个时间限制。

times=mk 表示一个点开始走会完整走 t 轮,w=mkt 表示走完 t 轮还需要走 w 步。

手动模拟一下,发现类似滑动窗口,每次暴力加入 w 步,计算答案,再删除当前点,把加入 w 步的点剩下的都加进去,时间复杂度为 O(n+k)

注意 times=0 的情况和特判环大小 times 的情况。

(补)

Day 2

A 江桥的均衡区间

题目描述

解法

  • Subtask 1 & Subtask 2

枚举 i,然后往后扩展,每次遇到一个数把他扔进去

  • Subtask 3

枚举区间的起点终点,左右端点为 j,i(j<i)

p1ip1j1=p2ip2j1,移项,p1ip2i=p1j1p2j1

代码

posted @   OoXiao_QioO  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起