CSP25
挂分大赛
警钟长鸣
总计,挂了至少155
T1输出忘考虑负数 挂80
T3全\(RE\)挂75
T1
题目
线段树暴力能过
注意考虑负数啊,挂了\(80\)
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
// #define endl '\n'
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define ull unsigned long long
#define pb push_back
#define ts cout<<"----------------"<<endl;
#define bs bitset<65>
using namespace std;
const int N = 1e5+5,mod=998244353;
int n,m;ll a[N];
int tot;
int op[N],tms;
struct ST
{
int st,id;
};
struct Q
{
int l,r,x,op;
}q[N];
struct T
{
ll l,r;ll w,lz;
}st[N<<2];
inline void pushup(int rt)
{
st[rt].w=(st[lid].w+st[rid].w)%mod;
}
inline void pd(int rt)
{
if(st[rt].lz)
{
ll lz=st[rt].lz%mod;st[rt].lz=0;
st[lid].lz=(st[lid].lz+lz)%mod;
st[rid].lz=(st[rid].lz+lz)%mod;
st[lid].w=(st[lid].w+lz*(st[lid].r-st[lid].l+1)%mod)%mod;
st[rid].w=(st[rid].w+lz*(st[rid].r-st[rid].l+1)%mod)%mod;
}
}
inline void build(int rt,int l,int r)
{
st[rt].l=l;st[rt].r=r;
if(l==r)
{
st[rt].w=a[l];return;
}
int mid=(l+r)>>1;
build(lid,l,mid);build(rid,mid+1,r);
pushup(rt);
}
void update(int rt,int l,int r,ll v)
{
if(l<=st[rt].l&&st[rt].r<=r)
{
st[rt].w=(st[rt].w+v*(st[rt].r-st[rt].l+1)%mod)%mod;
st[rt].lz=(st[rt].lz+v)%mod;return;
}
int mid=(st[rt].l+st[rt].r)>>1;
pd(rt);
if(l<=mid)update(lid,l,r,v);
if(r>mid)update(rid,l,r,v);
pushup(rt);
}
ll query(int rt,int l,int r)
{
if(l<=st[rt].l&&st[rt].r<=r)
{
return st[rt].w;
}
int mid=(st[rt].l+st[rt].r)>>1;
pd(rt);
ll ans=0;
if(l<=mid)ans=(ans+query(lid,l,r))%mod;
if(r>mid)ans=(ans+query(rid,l,r))%mod;
// pushup(rt);
return ans;
}
stack <int> Q;
int main()
{
speed();
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
build(1,1,n);
int now=0;
for(int i=1;i<=m;i++)
{
cin>>q[i].op;
if(q[i].op==1)
{
cin>>q[i].l>>q[i].r>>q[i].x;
update(1,q[i].l,q[i].r,q[i].x);
now++;
Q.push(i);
}else if(q[i].op==2)
{
cin>>q[i].l>>q[i].r;
cout<<(query(1,q[i].l,q[i].r)+mod)%mod<<endl;
}else
{
cin>>q[i].x;
now-=q[i].x;
while(Q.size()!=now&&Q.size())
{
int id=Q.top();Q.pop();
// cout<<id<<endl;
update(1,q[id].l,q[id].r,-q[id].x);
}
}
}
return 0;
}
T2
题目
我们可以先去掉\(Qie\)的边,然后只在\(Lun\)边上跑一边\(Tarjan\)找到所有的环,然后不是环的去掉就行了,剩下只需要构造一颗生成树,用并查集维护连通性,注意割边一定要删掉
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
// #define endl '\n'
#define pii pair<int,int>
#define ull unsigned long long
#define pb push_back
#define ts cout<<"----------------"<<endl;
#define bs bitset<65>
using namespace std;
const int N = 2e5+5;
int n,m;
struct node
{
int v,w,id;
};
vector <node> edge[N];
struct node2
{
int u,v,w,id;
};
vector <node2> e;
vector <int> ans;
int dfn[N],dfs_clock,low[N],belong[N],cnt,s[N],top;
bool del[N];stack <int> stk;
inline void Tarjan(int u,int id)
{
// cout<<u<<endl;
dfn[u]=low[u]=++dfs_clock;
stk.push(u);
for(auto [to,w,i]:edge[u])
{
if(i==id)continue;
if(!dfn[to])
{
Tarjan(to,i);
low[u]=min(low[u],low[to]);
}else
{
low[u]=min(low[u],dfn[to]);
}
}
if(low[u]==dfn[u])
{
del[id]=1;//删割边
int x=0;
++cnt;
do
{
x=stk.top();stk.pop();
belong[x]=cnt;
}while(x!=u);
}
}
int fa[N];
int find(int u)
{
if(u!=fa[u])fa[u]=find(fa[u]);
return fa[u];
}
bool un(int u,int v)
{
u=find(u),v=find(v);
if(u!=v)
{
fa[u]=v;
return 1;
}
return 0;
}
int main()
{
speed();
// freopen("puzzle13.in","r",stdin);
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
cin>>n>>m;
int u,v;
char op[10];e.pb({0,0});
for(int i=1;i<=m;i++)
{
cin>>u>>v>>op;
if(op[0]=='L')
{
e.pb({u,v,1,i});
edge[u].pb({v,1,i});edge[v].pb({u,1,i});
}else
{
e.pb({u,v,2,i});
}
}
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=n;i++)
{
if(!dfn[i])Tarjan(i,0);
}
for(int i=1;i<=m;i++)
{
if(e[i].w==1&&!del[i])
{
int u=e[i].u,v=e[i].v;
if(belong[u]==belong[v])
{
un(u,v);
ans.pb(i);
}
}
}
// if(!ans.size())
// {
// cout<<"NO"<<endl;return 0;
// }
for(int i=1;i<=m;i++)
{
if(e[i].w==2)
{
int u=e[i].u,v=e[i].v;
if(un(u,v))ans.pb(i);
}
}
int fs=find(1);
for(int i=2;i<=n;i++)
{
if(find(i)!=fs)
{
cout<<"NO"<<endl;return 0;
}
}
cout<<"YES"<<endl;
// if(ans.size()!=n-1)
// {
// cout<<"NO"<<endl;return 0;
// }
// for(int i=1;i<=n;i++)
cout<<ans.size()<<endl;
for(auto v:ans)
{
cout<<e[v].u<<" "<<e[v].v<<endl;
}
return 0;
}
/*
./spj in.in out.out out.out
*/
用树状数组会飞快
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
// #define endl '\n'
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define ull unsigned long long
#define pb push_back
#define ts cout<<"----------------"<<endl;
#define bs bitset<65>
using namespace std;
const ll N = 5e5+5,mod=998244353;
int n,m;ll a[N];
int tot;
int op[N],tms;
inline int read()
{
int x=0,f=1;char ch=getchar_unlocked();
for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
inline void write(int x)
{
return x<0?(putchar_unlocked('-'),write(-x),void(0)):(x==0?void(0):(write(x/10),putchar_unlocked((x%10)|48),void(0)));
}
struct ST
{
int st,id;
};
struct Q
{
int l,r,x,op;
}q[N];
ll c[N],c1[N];
int lowbit(int x)
{
return x&-x;
}
void update(int x,ll v)
{
ll v1=x*v;
while(x<=n)
{
(c[x]+=v);
(c1[x]+=v1);
x+=lowbit(x);
}
}
ll query(int x)
{
ll tmp=x,ans=0,res1=0;
while(x)
{
(ans+=c[x]);
(res1+=c1[x]);
x-=lowbit(x);
}
return (ans*(tmp+1)-res1);
}
stack <int> Q;
int main()
{
// speed();
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
update(i,a[i]-a[i-1]);
}
int now=0;
for(int i=1;i<=m;i++)
{
q[i].op=read();
if(q[i].op==1)
{
q[i].l=read();q[i].r=read();q[i].x=read();
update(q[i].l,q[i].x);
update(q[i].r+1,-q[i].x);
now++;
Q.push(i);
}else if(q[i].op==2)
{
q[i].l=read();q[i].r=read();
write(query(q[i].r)-query(q[i].l-1));
putchar_unlocked('\n');
// cout<<((query(q[i].r)-query(q[i].l-1))%mod+mod)%mod<<endl;
}else
{
q[i].x=read();
now-=q[i].x;
while(Q.size()!=now&&Q.size())
{
int id=Q.top();Q.pop();
// cout<<id<<endl;
update(q[id].l,-q[id].x);
update(q[id].r+1,q[id].x);
}
}
}
return 0;
}
T3
题目
考虑\(dp_{i,j}\),表示构造长为\(i\)的序列,最后一个数为\(j\),\(O(nm^2)\)转移
用前缀和优化一下,优化到\(O(nm)\),数组别开太大,挂了\(75\)分
如果要打表,可以\(vscode\)和\(sublime\)并用,尽早开始啊
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
// #define endl '\n'
#define pii pair<int,int>
#define ull unsigned long long
#define pb push_back
#define ts cout<<"----------------"<<endl;
#define bs bitset<65>
using namespace std;
const int mod=998244353,N=1e6+5;
int n,m,mo[N];int dp[2][N];ll sum[2][N][3];
int main()
{
speed();
// freopen("in.in","r",stdin);
// freopen("out1.out","w",stdout);
cin>>n>>m;
if(m==n-1)
{
cout<<1<<endl;return 0;
}
if(n>m)
{
cout<<0<<endl;
return 0;
}
for(int i=0;i<=m;i++)dp[1][i]=1,sum[1][i][i%3]=(sum[1][i][i%3]+1)%mod;
for(int j=0;j<=m;j++)
{
sum[1][j][0]=(sum[1][j-1][0]+sum[1][j][0])%mod;
sum[1][j][1]=(sum[1][j-1][1]+sum[1][j][1])%mod;
sum[1][j][2]=(sum[1][j-1][2]+sum[1][j][2])%mod;
mo[j]=j%3;
}
// dp[0][0]=1;
for(int i=2;i<=n;i++)
{
// for(int j=0;j<=m;j++)
for(int j=0;j<=m;j++)
{
dp[i&1][j]=0,sum[i&1][j][0]=sum[i&1][j][1]=sum[i&1][j][2]=0;
ll tmp=0;
if(j>0)tmp=sum[(i-1)&1][j-1][0]*(mo[j]!=0)+sum[(i-1)&1][j-1][1]*(mo[j]!=1)+sum[(i-1)&1][j-1][2]*(mo[j]!=2);
// cout<<tmp<<endl;
tmp=(tmp%mod+mod)%mod;
dp[i&1][j]=(dp[i&1][j]+tmp)%mod;
sum[i&1][j][mo[j]]=(sum[i&1][j][mo[j]]+dp[i&1][j])%mod;
// cout<<i<<" "<<j<<" "<<dp[i&1][j]<<endl;
}
for(int j=1;j<=m;j++)
{
sum[i&1][j][0]=(sum[i&1][j-1][0]+sum[i&1][j][0])%mod;
sum[i&1][j][1]=(sum[i&1][j-1][1]+sum[i&1][j][1])%mod;
sum[i&1][j][2]=(sum[i&1][j-1][2]+sum[i&1][j][2])%mod;
}
}
ll ans=0;
for(int i=n-1;i<=m;i++)ans=(ans+dp[n&1][i])%mod;
cout<<ans<<endl;
return 0;
}
/*
0 0 0
0 1 1
0 2 2
0 3 2
0 4 3
1 0 0
1 1 0
1 2 1
1 3 3
1 4 4
8
*/
其实,还可以优化,就是比较\(n,m\)大小关系,然后卡紧左右边界即可
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
// #define endl '\n'
#define pii pair<int,int>
#define ull unsigned long long
#define pb push_back
#define ts cout<<"----------------"<<endl;
#define bs bitset<65>
using namespace std;
const int mod=998244353,N=1e7+5;
int n,m,mo[N],l[N],r[N];int dp[2][N];int sum[2][N][3];
int main()
{
speed();
// freopen("in.in","r",stdin);
// freopen("out1.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
l[i]=i-1,r[i]=m-(n-i);
if(m==n-1)
{
cout<<1<<endl;return 0;
}
if(n>m)
{
cout<<0<<endl;
return 0;
}
for(int i=0;i<=m;i++)dp[1][i]=1,sum[1][i][i%3]=(sum[1][i][i%3]+1)%mod;
for(int j=0;j<=m;j++)
{
sum[1][j][0]=(sum[1][j-1][0]+sum[1][j][0])%mod;
sum[1][j][1]=(sum[1][j-1][1]+sum[1][j][1])%mod;
sum[1][j][2]=(sum[1][j-1][2]+sum[1][j][2])%mod;
mo[j]=j%3;
}
// dp[0][0]=1;
for(int i=2;i<=n;i++)
{
for(int j=l[i]-1;j<=r[i];j++)dp[i&1][j]=0,sum[i&1][j][0]=sum[i&1][j][1]=sum[i&1][j][2]=0;
for(int j=l[i];j<=r[i];j++)
{
ll tmp=0;
if(j>0)tmp=sum[(i-1)&1][j-1][0]*(mo[j]!=0)+sum[(i-1)&1][j-1][1]*(mo[j]!=1)+sum[(i-1)&1][j-1][2]*(mo[j]!=2);
// cout<<tmp<<endl;
tmp=(tmp%mod+mod)%mod;
dp[i&1][j]=(dp[i&1][j]+tmp)%mod;
sum[i&1][j][mo[j]]=(sum[i&1][j][mo[j]]+dp[i&1][j])%mod;
// cout<<i<<" "<<j<<" "<<dp[i&1][j]<<endl;
}
for(int j=l[i]+1;j<=r[i];j++)
{
sum[i&1][j][0]=(sum[i&1][j-1][0]+sum[i&1][j][0])%mod;
sum[i&1][j][1]=(sum[i&1][j-1][1]+sum[i&1][j][1])%mod;
sum[i&1][j][2]=(sum[i&1][j-1][2]+sum[i&1][j][2])%mod;
}
}
ll ans=0;
for(int i=l[n];i<=r[n];i++)ans=(ans+dp[n&1][i])%mod;
cout<<ans<<endl;
return 0;
}
/*
0 0 0
0 1 1
0 2 2
0 3 2
0 4 3
1 0 0
1 1 0
1 2 1
1 3 3
1 4 4
8
*/
观察可得:\(a_{i+1}-a_i>0\)
\(a_i\not \equiv a_{i+1} \mod 3\)
考虑差分,差分后有\(n\)位
其中第一位\(b_0\)可以为\(0,1,2\)
其他的\(b_i\in {1,2}\)且由于\(a_n<=m\)则\(\sum_{i=0}^{n-1}b_i<=m\)
我们可以枚举\(1或2\),枚举一个确定另一个数量,设\(b_0=i\),假设枚举\(j\)个\(2\),则\(\sum b=n-1-j+2j+i=n+j-1+i<=m\)
每三个数出现一次\(\mod 3=0\)所以可以插入的\(3\)的个数最多为\(\lfloor{\frac{m-(n+j-1+i)}{3}}\rfloor\),所以答案为枚举\(2\)的方案乘上\(3\)的方案,\(3\)的方案数可以插空,一共\(n-1\)个空,注意可以一个空插多个,即为\(C_{n+cnt-1}^{n-1}\),所有\(ans=\sum_{i=0}^2\sum_{j=0}^{n-1}C_{n-1}^jC_{n+cnt_3-1}^{cnt_3-1}\)
注意要线性求阶乘逆元,即为\(\frac{1}{(i+1)!}\times (i+1)\),\(inv_{i}=inv_{i+1}\times (i+1)\)
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
// #define endl '\n'
#define pii pair<int,int>
#define ull unsigned long long
#define pb push_back
#define ts cout<<"----------------"<<endl;
#define bs bitset<65>
using namespace std;
const int mod=998244353,N=2e7+5;
int n,m;
int jie[N],inv[N],s[N];
inline int qpow(int a,int b)
{
int ans=1;
while(b)
{
if(b&1)ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return ans;
}
inline int C(int n,int m)
{
if(n<m)return 0;
// if(!m)return 1;
return 1ll*jie[n]*inv[n-m]%mod*inv[m]%mod;
}
int main()
{
speed();
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
cin>>n>>m;
jie[0]=1;inv[0]=1;s[0]=1;
for(int i=1;i<=2*m;i=-~i)
{
jie[i]=1ll*jie[i-1]*i%mod;
}
inv[2*m]=qpow(jie[2*m],mod-2);
for(int i=2*m-1;i>=1;i--)
{
inv[i]=1ll*inv[i+1]*(i+1)%mod;
}
for(int i=1;i<=m;i++)
{
s[i]=(s[i-1]+C(n+i-1,n-1))%mod;
}
ll ans=0;
for(int i=0;i<=2;i++)
{
for(int j=0;j+i<=m-n+1&&j<n;j++)
ans=(ans+1ll*C(n-1,j)*s[(m-n-j-i+1)/3]%mod)%mod;
}
cout<<ans;
return 0;
}
/*
0 0 0
0 1 1
0 2 2
0 3 2
0 4 3
1 0 0
1 1 0
1 2 1
1 3 3
1 4 4
8
*/
T4
题目
后记
9G拉着我写线段树2,被硬控了,乐
易错:因为有加和乘法两种操作,先乘法后加,用乘法\(lz\)传给儿子的乘法以及加法\(lz\)标记,还有,为了避免顺序搞乱,\(pushdown\)放最上面
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
// #define endl '\n'
#define pii pair<int,int>
#define ull unsigned long long
#define pb push_back
#define lid (rt<<1)
#define rid (rt<<1|1)
#define ts cout<<"----------------"<<endl;
#define bs bitset<65>
using namespace std;
const int N = 1e5+5;
int n,q,mod,a[N];
struct
{
int l,r;ll lzsum,lzmul,w;
}st[N<<3];
struct SegTree
{
inline void pu(int rt)
{
st[rt].w=(st[lid].w+st[rid].w)%mod;
}
inline void pdsum(int rt)
{
if(st[rt].lzsum)
{
ll lz=st[rt].lzsum;st[rt].lzsum=0;
(st[lid].lzsum+=lz)%=mod;
(st[rid].lzsum+=lz)%=mod;
(st[lid].w+=lz*(st[lid].r-st[lid].l+1)%mod)%=mod;
(st[rid].w+=lz*(st[rid].r-st[rid].l+1)%mod)%=mod;
}
}
inline void pdmul(int rt)
{
// cout<<st[rt].lzmul<<endl;
if(st[rt].lzmul!=1)
{
ll lz=st[rt].lzmul;st[rt].lzmul=1;
(st[lid].lzmul*=lz)%=mod;
(st[rid].lzmul*=lz)%=mod;
(st[lid].lzsum*=lz)%=mod;
(st[rid].lzsum*=lz)%=mod;
(st[lid].w*=lz)%=mod;
(st[rid].w*=lz)%=mod;
}
}
inline void build(int rt,int l,int r)
{
st[rt].l=l;st[rt].r=r;
st[rt].lzmul=1;
if(l==r)
{
st[rt].w=a[l];return;
}
int mid=l+r>>1;
build(lid,l,mid);build(rid,mid+1,r);
pu(rt);
}
inline void updatesum(int rt,int l,int r,ll v)
{
pdmul(rt);pdsum(rt);
if(l<=st[rt].l&&st[rt].r<=r)
{
st[rt].w=(st[rt].w+v*(st[rt].r-st[rt].l+1)%mod)%mod;
st[rt].lzsum=(st[rt].lzsum+v)%mod;return;
}
int mid=(st[rt].l+st[rt].r)>>1;
if(l<=mid)updatesum(lid,l,r,v);
if(r>mid)updatesum(rid,l,r,v);
pu(rt);
}
inline void updatemul(int rt,int l,int r,ll v)
{
pdmul(rt);pdsum(rt);
if(l<=st[rt].l&&st[rt].r<=r)
{
st[rt].w=st[rt].w*v%mod;
st[rt].lzmul=(st[rt].lzmul*v)%mod;
return;
}
int mid=(st[rt].l+st[rt].r)>>1;
if(l<=mid)updatemul(lid,l,r,v);
if(r>mid)updatemul(rid,l,r,v);
pu(rt);
}
inline ll query(int rt,int l,int r)
{
// cout<<rt<<" "<<st[rt].l<<" "<<st[rt].r<<endl;
pdmul(rt);pdsum(rt);
if(l<=st[rt].l&&st[rt].r<=r)
{
return st[rt].w;
}
int mid=(st[rt].l+st[rt].r)>>1;
ll ans=0;
if(l<=mid)ans=(ans+query(lid,l,r))%mod;
if(r>mid)ans=(ans+query(rid,l,r))%mod;
// pushup(rt);
return ans;
}
}T;
int main()
{
speed();
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
cin>>n>>q>>mod;
for(int i=1;i<=n;i++)cin>>a[i];
int op,x,y,k;
T.build(1,1,n);
// cout<<T.query(1,1,n)<<endl;
while(q--)
{
cin>>op;
if(op==1)
{
cin>>x>>y>>k;
T.updatemul(1,x,y,k%mod);
}else if(op==2)
{
cin>>x>>y>>k;
T.updatesum(1,x,y,k%mod);
}else
{
cin>>x>>y;
cout<<T.query(1,x,y)<<endl;
}
}
return 0;
}