多校冲刺 NOIP 20211105 模拟 (23)
考试经过
开始感觉T1不是那么很可做,于是就去看T2,发现左边的CBX已经开始敲键盘了,看来这是有思路了,有点小慌张
然后发现B哥已经开始码T2了,更jb慌了,心想着这是不是两道我不会的签到题。。。。。然后就开始仔细研究T2
然后发现我都不知道快排的原理是啥。。。。于是先照着他给的那个程序打,结果还过了样例。。。只是大样例给T了
然后发现这就是个sb题,瞎搞了一会,半个小时A掉了。然后看T3,又是构造题,我是构造超级弱者,开始瞎手玩
然后手玩出了一个当时认为很对的结论:从小到大排序,然后让答案接近0着选就好了。。。。最扯的是大样例还过了
然后就交了。然后再看T4,发现有44分是白给的,先拿到手了,想了半个小时,没啥进展,就又回去看T1了
越看越有思路。。。。然后设计了一个\(n^3\)的dp,其实我当时都不知道这是坐标dp,并且觉得我当时很天才
发现\(define\ int\ long long\)之后数组开不下,就滚了一维,心想着已经350了,不低了,不低了,就开始罚坐了
结果出来就成了100+100+28+44=272,T3结论假了emmm。。。。还不如打个背包暴力呢。。。。
T1 回文
设\(dp_{i,j,k}\)表示距离出发点为\(i\),横坐标为\(j\),与距离终点距离为\(i\),横坐标为\(k\)配对的方案数,
转移的话就瞎转移就行了
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int mod=993244853;
int f[2][505][505],n,m,goal,nw;
char s[505][505];
vector<pii>v1[1005],v2[1005];
inline void solve(pii x,int le)
{
for(auto y:v2[le+1])
{
if(s[y.fi][y.se]==s[x.fi+1][x.se]&&(x.fi+1<=y.fi&&x.se<=y.se))
{
if(s[y.fi+1][y.se]==s[x.fi][x.se]) (f[nw^1][x.fi+1][y.fi]+=f[nw][x.fi][y.fi+1])%=mod;
if(s[y.fi][y.se+1]==s[x.fi][x.se]) (f[nw^1][x.fi+1][y.fi]+=f[nw][x.fi][y.fi])%=mod;
}
if(s[y.fi][y.se]==s[x.fi][x.se+1]&&(x.fi<=y.fi&&x.se+1<=y.se))
{
if(s[y.fi+1][y.se]==s[x.fi][x.se]) (f[nw^1][x.fi][y.fi]+=f[nw][x.fi][y.fi+1])%=mod;
if(s[y.fi][y.se+1]==s[x.fi][x.se]) (f[nw^1][x.fi][y.fi]+=f[nw][x.fi][y.fi])%=mod;
}
}
}
signed main()
{
freopen("palin.in","r",stdin);
freopen("palin.out","w",stdout);
n=read();m=read(); goal=(n+m-1)/2;
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
if(s[1][1]!=s[n][m]){puts("0");return 0;}
f[nw][1][n]=1;int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
v1[i+j-1].push_back(mp(i,j));
v2[n-i+(m-j)+1].push_back(mp(i,j));
}
}
if((n+m-1)&1)
{
for(int i=1;i<=goal;i++){
for(auto x:v1[i]) solve(x,i);nw^=1;
memset(f[nw^1],0,sizeof(f[nw^1]));
}
for(auto x:v1[goal+1])ans+=f[nw][x.fi][x.fi];
}
else
{
for(int i=1;i<goal;i++){
for(auto x:v1[i]) solve(x,i);nw^=1;
memset(f[nw^1],0,sizeof(f[nw^1]));
}
for(auto x:v1[goal])for(auto y:v2[goal])ans+=f[nw][x.fi][y.fi];
}
printf("%lld\n",ans%mod);
}
T2 快速排序
我们发现\(nan\)无论和谁比较都是\(false\)
那么这个排序的实质就是从左到右枚举,这个区间严格小于它的数放到它的前面,单调队列维护即可
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int maxn=5e5+5;
struct node{
bool isnan;int shu,id;
node(){isnan=0;shu=0;id=0;}
friend bool operator < (node a,node b){
if(a.isnan||b.isnan) return false;
return a.shu<b.shu;
}
}p[maxn],b[maxn];
int n;
char s[15];
struct data{
int val,id;
friend bool operator < (data a,data b){
if(a.val==b.val) return a.id>b.id;
return a.val>b.val;
}
};
priority_queue<data>q;
bool bo[maxn];
int que[maxn],top;
signed main()
{
freopen("qsort.in","r",stdin);
freopen("qsort.out","w",stdout);
int t=read();
while(t--)
{
n=read();top=0;
for(int i=1;i<=n;i++)bo[i]=0,p[i].isnan=0;
for(int i=1;i<=n;i++)
{
p[i].id=i;
scanf("%s",s+1);
if(s[1]=='n'){p[i].isnan=1;}
else
{
p[i].isnan=0;p[i].shu=0;
int l=strlen(s+1);
for(int j=1;j<=l;j++)
p[i].shu=p[i].shu*10+(s[j]-'0');
q.push((data){p[i].shu,i});
}
}
for(int i=1;i<=n;i++)
{
if(p[i].isnan){que[++top]=i;bo[i]=1;continue;}
else if(bo[i]) continue;
bo[i]=1;
while(!q.empty()&&q.top().val<p[i].shu)
{
if(!bo[q.top().id])
que[++top]=q.top().id;
bo[q.top().id]=1;q.pop();
}
que[++top]=i;
}
while(!q.empty())q.pop();
for(int i=1;i<=n;i++)
{
if(p[que[i]].isnan)printf("nan ");
else printf("%d ",p[que[i]].shu);
}
puts("");
}
}
T3 混乱邪恶
高联2试的一个改编题目,所以证明就不讲了(主要是我不会),那么直接排序,两两一组维护差值,贪心将差值干到0
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int maxn=1e6+5;
int n,sum,m;
struct node{
int id,x,ans;
friend bool operator <(node a,node b){
return a.x<b.x;
}
}p[maxn];
vector<int>vec[maxn];
bool cmp(node a,node b){return a.id<b.id;}
signed main()
{
freopen("chaoticevil.in","r",stdin);
freopen("chaoticevil.out","w",stdout);
n=read();m=read();puts("NP-Hard solved");
for(int i=1;i<=n;i++)p[i].x=read(),p[i].id=i;
sort(p+1,p+1+n);
for(int i=1+(n&1);i<=n;i+=2)
{
sum+=(p[i+1].x-p[i].x);
p[i].ans=-1;p[i+1].ans=1;
vec[p[i+1].x-p[i].x].push_back(i);
}
if(n&1)sum-=p[1].x,p[1].ans=-1;
for(int i=m/3;i>=1;i--)
{
if(!vec[i].size()||sum<i*2)continue;
for(auto y:vec[i]) if(sum>=2*i)
sum-=2*i,swap(p[y].ans,p[y+1].ans);
}
sort(p+1,p+1+n,cmp);
for(int i=1;i<=n;i++)printf("%d ",p[i].ans);
}
T4 校门外歪脖树上的鸽子
一道sb数据结构题,干了一下午加半个晚上,树剖一下,开两棵线段树维护自己兄弟的标记
线段树就支持区间加和区间求和就好了
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define LL long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int maxn=4e5+5;
int n,m,rt,ch[maxn][2],top[maxn],dfn[maxn],siz[maxn],dep[maxn],fa[maxn],son[maxn];
int tp[maxn],le[maxn],dfa[maxn],u1[maxn],u0[maxn],ha[maxn],p1[maxn],p2[maxn],cnt;
map<pii,int>mp;
inline void dfs1(int x,int f)
{
fa[x]=f;dep[x]=dep[f]+1;siz[x]=le[x]=1;p1[x]=p2[x]=x;
if(!f)u0[x]=u1[x]=x; else u0[x]=!tp[x]?u0[f]:x,u1[x]=tp[x]?u1[f]:x;
if(x>n) dfs1(ls(x),x),dfs1(rs(x),x),son[x]=siz[ls(x)]>siz[rs(x)]?ls(x):rs(x),
siz[x]+=siz[ls(x)]+siz[rs(x)],le[x]=le[ls(x)]+le[rs(x)],p1[x]=p1[ls(x)],p2[x]=p2[rs(x)];
mp[make_pair(p1[x],p2[x])]=x;
}
inline void dfs2(int x,int tp)
{
dfn[x]=++cnt;dfa[cnt]=x;top[x]=tp;
if(x>n) dfs2(son[x],tp);else return;
if(ls(x)==son[x]) dfs2(rs(x),rs(x));
else dfs2(ls(x),ls(x));
}
inline int LCA(int x,int y)
{
while(top[x]!=top[y])
{if(dep[top[x]]<dep[top[y]]) swap(x,y);x=fa[top[x]];}
if(dep[x]<dep[y]) return x;return y;
}
inline int pot(int x,int y)
{
x=top[x];while(x!=top[y])if(fa[x]==y)
return x;else x=top[fa[x]];
return son[y];
}
struct tree{
#define lid id<<1
#define rid id<<1|1
LL sum[maxn<<2],lazy[maxn<<2],val[maxn<<2];
inline void build(int id,int l,int r,int flag)
{
if(l==r){if(tp[dfa[l]]!=flag)val[id]=le[ha[dfa[l]]];return;}
int mid=(l+r)>>1;build(lid,l,mid,flag);build(rid,mid+1,r,flag);
val[id]=val[lid]+val[rid];
}
inline void pushdown(int id)
{
if(!lazy[id]) return;
sum[lid]+=val[lid]*lazy[id]; lazy[lid]+=lazy[id];
sum[rid]+=val[rid]*lazy[id]; lazy[rid]+=lazy[id];
lazy[id]=0;
}
inline void update(int id,int l,int r,int ll,int rr,int v)
{
if(l>=ll&&r<=rr){sum[id]+=v*val[id];lazy[id]+=v;return ;}
int mid=(l+r)>>1;pushdown(id);
if(ll<=mid) update(lid,l,mid,ll,rr,v);
if(rr>mid) update(rid,mid+1,r,ll,rr,v);
sum[id]=sum[lid]+sum[rid];
}
inline LL query(int id,int l,int r,int ll,int rr)
{
if(l>=ll&&r<=rr) return sum[id];
int mid=(l+r)>>1;pushdown(id);LL ans=0;
if(ll<=mid) ans+=query(lid,l,mid,ll,rr);
if(rr>mid) ans+=query(rid,mid+1,r,ll,rr);
return ans;
}
inline void treeup(int x,int y,int d)
{
while(top[x]!=top[y]){update(1,1,2*n-1,dfn[top[x]],dfn[x],d);x=fa[top[x]];}
if(x!=y) update(1,1,2*n-1,dfn[y]+1,dfn[x],d);
}
inline LL treeque(int x,int y)
{
LL res=0; while(top[x]!=top[y])
{res+=query(1,1,2*n-1,dfn[top[x]],dfn[x]);x=fa[top[x]];}
if(x!=y) res+=query(1,1,2*n-1,dfn[y]+1,dfn[x]);
return res;
}
}s0,s1;
inline void add(int x,int d)
{
if(tp[x]) x=ha[x],s0.update(1,1,2*n-1,dfn[x],dfn[x],d);
else x=ha[x],s1.update(1,1,2*n-1,dfn[x],dfn[x],d);
}
inline LL getv(int x)
{
if(tp[x]) return x=ha[x],s0.query(1,1,2*n-1,dfn[x],dfn[x]);
return x=ha[x],s1.query(1,1,2*n-1,dfn[x],dfn[x]);
}
signed main()
{
freopen("pigeons.in","r",stdin);
freopen("pigeons.out","w",stdout);
memset(tp,-1,sizeof(tp));
n=read();m=read();
for(int i=n+1;i<2*n;i++)
{
int x=read(),y=read();
ch[i][0]=x;ch[i][1]=y;
tp[x]=0;tp[y]=1;
ha[x]=y;ha[y]=x;
}
for(int i=1;i<2*n;i++) if(tp[i]==-1)rt=i;dfs1(rt,0);dfs2(rt,rt);
ha[rt]=rt;s0.build(1,1,2*n-1,1);s1.build(1,1,2*n-1,0);
while(m--)
{
int o,x,y,k;
o=read();x=read();y=read();
k=mp[make_pair(x,y)];
if(o==1)
{
int v=read();
if(k) add(k,v);
else
{
int xx=u0[x],yy=u1[y],lca=LCA(x,y);
if(dep[xx]<=dep[lca]) add(pot(x,lca),v);
else add(xx,v),s0.treeup(xx,pot(x,lca),v);
if(dep[yy]<=dep[lca]) add(pot(y,lca),v);
else add(yy,v),s1.treeup(yy,pot(y,lca),v);
}
}
else
{
int lca=LCA(x,y);
if(k) printf("%lld\n",getv(k));
else
{
int xx=u0[x],yy=u1[y],lca=LCA(x,y);LL res=0;
if(dep[xx]<=dep[lca]) res+=getv(pot(x,lca));
else res+=getv(xx)+s0.treeque(xx,pot(x,lca));
if(dep[yy]<=dep[lca]) res+=getv(pot(y,lca));
else res+=getv(yy)+s1.treeque(yy,pot(y,lca));
printf("%lld\n",res);
}
}
}
}