指令 输入 程序 疼痛 疼痛 传递到神经 获取 属于 自己 记忆 本该是 我追求 许久的存在证明
test22
编辑数组edit
首先要求任何时候任何元素不能为负是假的,用加法之后用减法撤销即可。
我们希望差分数组变成 \(0\),首先发现操作是 \(d_{i/i+1}\gets d_{i/i+1}+1,d_{i+1/i}\gets d_{i+1/i}-1\),那么同奇偶的 \(d\) 可以任意流动,特别的操作 \(r-1\) 可以将差分流向不在意的 \(d_{r+1}\),所以枚举计算另一种差分为 \(0\) 的 \(l\) 有多少个即可,大体是一个前缀和相等,注意处理变化了的 \(d_{l}\) 的贡献。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
const int N=100005;
int id, T, n, a[N], s[N], ans;
void mian() {
cin >> n, ans=0;
up(i,1,n) cin >> a[i];
up(i,1,n) s[i]=a[i]-a[i-1]+(i>=2?s[i-2]:0);
unordered_map<int,int> L, R;
++L[0], ++R[0];
up(i,1,n) {
if(i%2==1) ans+=L[s[i]], ++L[s[i]], ++R[s[i-1]-a[i]];
else ans+=R[s[i]], ++R[s[i]], ++L[s[i-1]-a[i]];
if(a[i]==0) --ans;
}
cout << ans << '\n';
}
signed main() {
freopen("edit.in","r",stdin);
freopen("edit.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> id >> T;
while(T--) mian();
return 0;
}
石头rock
首先拿取是区间拓展。设 \(Q(i,p)\) 表示以 \(i\) 为起点 \(p\) 是第几步拿的,显然对于 \(p\) 来说 \(Q(1\to p-1,p)\downarrow\),\((p+1\to n,p)\uparrow\),想办法快速求 \(Q(i,p)\) 之后二分可以求出答案。现在考虑 \(Q(i,p(>i))\) 的求法,考虑 \(a_u\) 是 \(\max\{a_{u+1,\dots,p}\}\),找到 \(i\) 前第一个更大的 \(a\),设这个位置为 \(v\),那么显然是拿完 \([v+1,i-1]\) 之后才会去拿 \([u+1,p]\),答案就是 \(p-(v+1)-1\)。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
const int N=100005, M=17;
int id, n, T, q, a[N], lg[N], st[N][M], pre[N][2], suf[N][2];
int qur(int l,int r) {
if(l>r) return 0;
int k=lg[r-l+1], x=st[l][k], y=st[r-(1<<k)+1][k];
return (a[x]>a[y])?x:y;
}
int check(int mid,int p) {
if(mid==p) return 1;
if(mid<p) {
int u=qur(mid+1,p);
int v=(pre[u][0]==mid)?pre[u][1]:pre[u][0];
return p-(v?v+1:1)+1;
}
int u=qur(p,mid-1);
int v=(suf[u][0]==mid)?suf[u][1]:suf[u][0];
return (v?v-1:n)-p+1;
}
signed main() {
freopen("rock.in","r",stdin);
freopen("rock.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> id >> n >> q, T=log2(n);
up(i,1,n) cin >> a[i];
up(i,1,n) lg[i]=log2(i), st[i][0]=i;
up(j,1,T) up(i,1,n-(1<<j)+1) {
int x=st[i][j-1], y=st[i+(1<<j-1)][j-1];
st[i][j]=(a[x]>a[y])?x:y;
}
up(i,1,n) {
if(a[qur(1,i-1)]>a[i]) {
int p=i-1;
dn(j,T,0) if(p-(1<<j)+1>=1&&a[st[p-(1<<j)+1][j]]<a[i]) p-=(1<<j);
pre[i][0]=p;
if(a[qur(1,p-1)]>a[i]) {
p=p-1;
dn(j,T,0) if(p-(1<<j)+1>=1&&a[st[p-(1<<j)+1][j]]<a[i]) p-=(1<<j);
pre[i][1]=p;
}
}
if(a[qur(i+1,n)]>a[i]) {
int p=i+1;
dn(j,T,0) if(p+(1<<j)-1<=n&&a[st[p][j]]<a[i]) p+=(1<<j);
suf[i][0]=p;
if(a[qur(p+1,n)]>a[i]) {
p=p+1;
dn(j,T,0) if(p+(1<<j)-1<=n&a[st[p][j]]<a[i]) p+=(1<<j);
suf[i][1]=p;
}
}
}
while(q--) {
int p, k, l, r, pl=0, pr=0, ql=0, qr=0, ans=0;
cin >> p >> k;
if(k==1) { cout << 1 << '\n'; continue; }
l=1, r=p-1;
while(l<=r) {
int mid=(l+r)>>1;
if(check(mid,p)<=k) pl=mid, r=mid-1;
else l=mid+1;
}
l=1, r=p-1;
while(l<=r) {
int mid=(l+r)>>1;
if(check(mid,p)>=k) pr=mid, l=mid+1;
else r=mid-1;
}
l=p+1, r=n;
while(l<=r) {
int mid=(l+r)>>1;
if(check(mid,p)>=k) ql=mid, r=mid-1;
else l=mid+1;
}
l=p+1, r=n;
while(l<=r) {
int mid=(l+r)>>1;
if(check(mid,p)<=k) qr=mid, l=mid+1;
else r=mid-1;
}
if(pl&&check(pl,p)==k) ans+=pr-pl+1;
if(ql&&check(ql,p)==k) ans+=qr-ql+1;
cout << ans << '\n';
}
return 0;
}
括号游戏2 bracket
体感有点介于常规题目和 adhoc 之间了,也可能是本可太没有数学直觉惹 /fad
手玩可以发现最终合法的序列时刻合法,证明就是某一个时刻插入了一个不合法的就会永远的隔绝两边的前缀和。
考虑原题目的过程,选择一个前缀和为 \(x\) 的空隙就加入 \(x-1,x/x+1,x\),要求全都 \(\geq 0\)。关心的好像只有空隙前缀和的可重集,但这个显然是记不下来的。考虑 dp 一些本身就带方案数的东西,额就比如某个结尾序列的方案数,考虑一下这个是怎么被操作出来的,会呈现一个奇怪的树形结构,一个灵珠一个魔丸两个点放一对,钦定顺序所以是儿子兄弟表示法这样子的东西,形态和方案数一起 dp 了,设 \(f_{i,j}\) 表示大小为 \(i\) 根对小的是 \(j\) 的方案数,转移枚举灵珠/魔丸的信息然后再乘兄弟即可,要一点点优化嗯对。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
const int N=505, P=998244353;
inline int ksm(int a,int b=P-2) {
int ret=1;
for( ; b; b>>=1) {
if(b&1) ret=ret*a%P;
a=a*a%P;
}
return ret;
}
int T, n, p, q, f[N][N], g[N][N], sub[N][N];
inline void add(int &a,int b) { a=(a+b)%P; }
void mian() {
memset(f,0,sizeof(f)), memset(g,0,sizeof(g));
cin >> n >> p, q=10000, p=p*ksm(q)%P, q=((1-p)%P+P)%P;
up(i,0,n) {
sub[i][0]=sub[i][i]=1;
up(j,1,i-1) sub[i][j]=(sub[i-1][j-1]+sub[i-1][j])%P;
}
up(i,0,n+1) f[0][i]=g[0][i]=1;
up(i,1,n-1) {
up(x,0,n) up(j,0,i-1) add(f[i][x],(f[j][x+1]*p%P+(x>0?f[j][x-1]*q%P:0))*g[i-1-j][x]%P*sub[i-1][j]%P);
up(x,0,n) up(j,0,i) add(g[i][x],f[j][x]*f[i-j][x]%P*sub[i][j]%P);
}
up(j,0,n-1) add(f[n][0],f[j][1]*p%P*g[n-1-j][0]%P*sub[n-1][j]%P);
up(i,1,n) f[n][0]=f[n][0]*ksm(2*i-1)%P;
cout << f[n][0] << '\n';
}
signed main() {
freopen("bracket.in","r",stdin);
freopen("bracket.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
while(T--) mian();
return 0;
}
区间interval
你 lgxq 的数据造错了(没有谴责他的意思他给的题目的质量都非常高他也没有义务给我们出模拟赛然后忘了)。
首先乘积尽量大我们会倾向于多拆出来一些小一点的数,不难发现在这个题目里面 \(v=2/3\),因为更大的肯定可以就在贡献答案的那个区间拆开获得不劣的贡献嗯对。然后就是对于每一个 \(R\) 求 \([i,R]\) 的 \(v=2/3\) 的最小区间,知道的话直接转移就可以惹,但是还要考虑怎么比较 \(2^{x}3^y\) 的大小嗯这个等价于比较 \(2^x,3^y\) 用下取整 \(\geq 1\) 即可预处理,或者可以比较 \(\log_2(2^x),\log_2(3^y)\) 也就是 \(x,y\log_2 3\)。不妨枚举贡献的数的最右边的那一个,最优左端点容易计算,然后跟 \(a_r\) 贡献的肯定是比较接近的至多两边 \(4\) 个数,用线段树维护出前方更小的最大/次大和更大的最小/次小即可,需要写对 \(a_i\) 排序按顺序假如来消掉另一维偏序嗯对,要稍微注意一下常数,像我一样的东西有点跑不过去 /fad
#include<bits/stdc++.h>
#define ll long long
#define ldb long double
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fir first
#define sec second
using namespace std;
const int N=600005, M=1200005, P=998244353, inf=1e9;
const ldb base=1.5849625007;
int id, n, m, tot, l, r, a[N], sp[N], pre[N];
int low[N][2], upr[N][2], pw2[N], pw3[N], f[N], g2[N], g3[N];
pii tr[M];
vector<int> add[N], del[N];
bool fc(int l2,int l3,int r2,int r3) {
int d2=min(l2,r2), d3=min(l3,r3);
l2-=d2, r2-=d2, l3-=d3, r3-=d3;
if(l2&&l3) return 1; if(!l2&&!l3) return 0;
return (!l2)?(base*l3>r2):(l2>base*r3);
}
inline pii merge(pii i,pii j) {
if(i.fir>j.fir) return mp(i.fir,max(i.sec,j.fir));
return mp(j.fir,max(j.sec,i.fir));
}
inline pii Merge(pii i,pii j) {
if(i.fir<j.fir) return mp(i.fir,min(i.sec,j.fir));
return mp(j.fir,min(j.sec,i.fir));
}
void updata(int x,int p=1,int s=1,int e=n) {
if(s==e) { tr[p]=mp(a[s],0); return; }
int mid=(s+e)>>1;
if(x<=mid) updata(x,ls(p),s,mid);
if(x>mid) updata(x,rs(p),mid+1,e);
tr[p]=merge(tr[ls(p)],tr[rs(p)]);
}
void Updata(int x,int p=1,int s=1,int e=n) {
if(s==e) { tr[p]=mp(a[s],inf); return; }
int mid=(s+e)>>1;
if(x<=mid) Updata(x,ls(p),s,mid);
if(x>mid) Updata(x,rs(p),mid+1,e);
tr[p]=Merge(tr[ls(p)],tr[rs(p)]);
}
pii lower(int l,int r,int p=1,int s=1,int e=n) {
if(l<=s&&e<=r) return tr[p];
int mid=(s+e)>>1; pii x=mp(0,0), y=mp(0,0);
if(l<=mid) x=lower(l,r,ls(p),s,mid);
if(r>mid) y=lower(l,r,rs(p),mid+1,e);
return merge(x,y);
}
pii upper(int l,int r,int p=1,int s=1,int e=n) {
if(l<=s&&e<=r) return tr[p];
int mid=(s+e)>>1; pii x=mp(inf,inf), y=mp(inf,inf);
if(l<=mid) x=upper(l,r,ls(p),s,mid);
if(r>mid) y=upper(l,r,rs(p),mid+1,e);
return Merge(x,y);
}
signed main() {
freopen("interval.in","r",stdin);
freopen("interval.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> id >> n >> m;
up(i,1,n) cin >> a[i], sp[i]=a[i];
up(i,1,m) cin >> l >> r, r=min(r,n), add[l].pb(l), del[r].pb(l);
multiset<int> qwq;
up(i,1,n) {
for(int u:add[i]) qwq.insert(u);
if(qwq.size()) pre[i]=*qwq.begin();
for(int u:del[i]) qwq.erase(qwq.find(u));
}
sort(sp+1,sp+1+n,[](int i,int j){return a[i]<a[j];});
up(u,1,n) {
int i=sp[u];
if(!pre[i]) continue;
pii ran=lower(pre[i],i);
low[i][0]=ran.fir;
low[i][1]=ran.sec;
updata(i);
}
up(i,1,4*n) tr[i]=mp(inf,inf);
dn(u,n,1) {
int i=sp[u];
if(!pre[i]) continue;
pii ran=upper(pre[i],i);
if(ran.fir<=n) upr[i][0]=ran.fir;
if(ran.sec<=n) upr[i][1]=ran.sec;
Updata(i);
}
up(i,1,n) {
if(low[i][0]) pw2[a[i]]=max(pw2[a[i]],low[i][0]);
if(upr[i][0]) pw2[upr[i][0]]=max(pw2[upr[i][0]],a[i]);
if(low[i][1]) pw3[a[i]]=max(pw3[a[i]],low[i][1]);
if(upr[i][1]) pw3[upr[i][1]]=max(pw3[upr[i][1]],a[i]);
if(low[i][0]&&upr[i][0]) pw3[upr[i][0]]=max(pw3[upr[i][0]],low[i][0]);
}
f[0]=1, g2[0]=g3[0]=0;
int j=0, k=0;
up(i,1,n) {
f[i]=1, g2[0]=g3[0]=0;
j=max(j,pw2[i]), k=max(k,pw3[i]);
if(j&&fc(g2[j-1]+1,g3[j-1],g2[i],g3[i])) f[i]=(ll)f[j-1]*2%P, g2[i]=g2[j-1]+1, g3[i]=g3[j-1];
if(k&&fc(g2[k-1],g3[k-1]+1,g2[i],g3[i])) f[i]=(ll)f[k-1]*3%P, g2[i]=g2[k-1], g3[i]=g3[k-1]+1;
cout << f[i] << ' ';
}
return 0;
}