总之就是 | ZROI NOIP联测 Day4
「0.0」序言
目前我还不会 T3(因为大概涉及一些多项式卷积的知识,然而我不会)
因为懒的造了所以就用原题目名了。
「1.0」签到题
其实最少有 \(40\) pts 来着,但没交上。
之所以正解挂成 \(40\) 是因为 \(998244353\) 写成了 \(99824353\)(
「1.1」题目简述
你的左手可以输入 A
或 B
,右手可以输入 B
或 C
,每次换手的代价为 \(1\),现在需要让你用左右手交替的方法输出由 A,B,C
组成的字符串 \(T\) 的每一个字串,求输出的每个字串最小代价之和。
\(|T| \le 5 \times 10^{6}.\)
「1.2」思路简述
设 \(f(x)\) 表示输出到第 \(x\) 位时的最小代价,下面来考虑什么时候需要换手。
因为左右手都可以输入 B
,所以当前位置为 B
的时候不需要换手,直接继承上一位的值,也就是 f(i) = f(i-1).
而当前位为 A
和 C
时,对于上一个对应的 C
和 A
的值,需要换手。
「1.3」Code
#include <iostream>
#include <stdio.h>
#include <cstring>
#define Heriko return
#define Deltana 0
#define Romanno 1
#define S signed
#define LL long long
#define R register
#define I inline
#define CI const int
#define mst(a, b) memset(a, b, sizeof(a))
#define ON std::ios::sync_with_stdio(false);cin.tie(0)
#define Files() freopen("RNMTQ.in","r",stdin);freopen("RNMTQ.out","w",stdout)
using namespace std;
CI MXX(5e6+1),MOD(998244353);
int ans,f[MXX],n,lsta,lstc;
char c[MXX];
S main()
{
Files();
ON;cin>>(c+1);n=strlen(c+1);
for(int i(1);i<=n;++i)
if(c[i]=='A') f[i]=(lstc+f[lstc])%MOD,lsta=i;
else if(c[i]=='B') f[i]=f[i-1];
else if(c[i]=='C') f[i]=(lsta+f[lsta])%MOD,lstc=i;
for(int i(1);i<=n;++i) (ans+=f[i])%=MOD;
cout<<(ans+MOD)%MOD;
Heriko Deltana;
}
「2.0」\(n^3\) 过一万
然而标题好像只是暗示了这个题是个大约 \(O(n^3)\) 的题。
「2.1」题目简述
给出 \(n\) 个数(\(n\) 为偶数),每次可以删除相邻的两个数 \(a,b\),代价为 \(cost(a,b).\)
求问用 \(\frac{n}{2}\) 轮删完这些数字的代价最大值最小为多少?
「2.2」思路简述
这个问题的形式很明显需要二分答案了,那么我们对于每次二分的最大值行区间 DP。
f(l,r)
表示 \(l\) 和 \(r\) 在最大值为能不能被删除,如果可以,就让 \(f(l,~) \operatorname{or} f(r+1,~).\)
因为都是一个布尔状态,所以可以用 bitset
来优化复杂度。
「2.3」Code
template<typename J>
I void fr(J &x)
{
short f(1);x=0;char c=getchar();
while(c<'0' or c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while (c>='0' and c<='9')
{
x=(x<<3)+(x<<1)+(c^=48);
c=getchar();
}
x*=f;
}
template<typename J>
I void fw(J x,bool k)
{
if(x<0) x=-x,putchar('-');
static short stak[35];short top(0);
do
{
stak[top++]=x%10;
x/=10;
}
while(x);
while(top) putchar(stak[--top]+'0');
k?puts(""):putchar(' ');
}
CI MXX(4005);
bitset<MXX> f[MXX];
int a[MXX][MXX],n;
I bool Checker(int lmt)
{
for(int l(n);l;--l)
for(int r(l+1);r<=n;++r)
if(f[l][r]) continue;
else
{
if(r==l+1) f[l][r]=(a[l][r]<=lmt);
else f[l][r]=(f[l+1][r-1]&(a[l][r]<=lmt));
if(f[l][r]) f[l]|=f[r+1];
}
Heriko f[1][n];
}
S main()
{
Files();
mst(a,0x3f);fr(n);
for(int i(1);i<=n;++i)
for(int j(i+1);j<=n;j+=2)
fr(a[i][j]);
int l(1),r((n*n)>>2),ans(0);
while(l<=r)
{
int mid((l+r)>>1);mst(f,0);
if(Checker(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
fw(ans,1);
Heriko Deltana;
}
「3.0」被 djq 加 0 了
咕着。
「4.0」加了三个零
不知道题目和题有啥关系,难道是数据范围加了三个零(?)
「4.1」题目简述
你有一个 \(1\) 到 \(n\) 的排列 \(p1,p2,…,pn\)。
现在你可以执行如下操作一次。
选择一个非负整数 \(k≥0\),和 \(2k\) 个端点 \(1≤l1<r1<l2<r2<⋯<lk<rk≤n\),然后对于每个 \(i\),我们都将 \(p_{l_{i}},p_{l_{i+1}},…,p_{r_{i}}\) 这些元素按升序排序。
问操作之后,可能可以得到多少种不同的排列。由于答案很大,输出对 \(998244353\) 取模的结果。
「4.2」Code
思路见代码罢。
template<typename J>
I J Hmax(const J &x,const J &y) {Heriko x>y?x:y;}
CI MXX(2e5+5),MOD(998244353),INF(0x7fffffff);
int n,pw[MXX][20];
LL t[MXX];
#define lowbit(x) ((x)&(-x))
I void UPD(int x,int v) {while(x<=n) (t[x]+=v)%=MOD,x+=lowbit(x);}
I LL QUE(int x)
{
LL res(0);
while(x) (res+=t[x])%=MOD,x-=lowbit(x);
Heriko (res%MOD+MOD)%MOD;
}
I void Pre()
{
for(int i(1);i<=n;++i) fr(pw[i][0]);
for(int i(0);i<20;++i) pw[0][i]=INF;
for(int j(1);j<20;++j)
for(int i(1);i<=n;++i)
if(i-(1<<j)+1>0) pw[i][j]=Hmax(pw[i][j-1],pw[i-(1<<(j-1))][j-1]);
else pw[i][j]=INF;
}
LL f[MXX];
int s[MXX],fst;
S main()
{
Files();
fr(n);Pre();
f[0]=1;UPD(1,1);
for(int i(1);i<=n;++i)
{
while(fst and pw[s[fst]][0]>pw[i][0]) --fst;
int now(s[fst]);
for(int j(19);j>=0 and now>=0;--j)
if(pw[now][j]<pw[i][0])
now-=(1<<j);
if(now<0) now=0;
f[i]=((QUE(i)-QUE(s[fst]))%MOD+MOD)%MOD;
if(now)
{
int val(lower_bound(s+1,s+1+fst,now)-s);
f[i]=((f[i]+f[s[val]]-(QUE(s[val])-QUE(now)))%MOD+MOD)%MOD;
}
UPD(i+1,f[i]);s[++fst]=i;
}
fw(f[n],1);
Heriko Deltana;
}
「5.0」尾声
也快 CSP 二轮了,但是为什么我还在爆零(?)