NOIP模拟63
T1 电压机制
解题思路
先找出这个图的一个生成树,然后没有称为树边的边就都是返祖边了。
对于一个边是合法的当且仅当它属于所有的奇数环并且不属于任何一个偶数环。
可以利用树上差分进行修改,更改一个返祖边的两个点的奇偶数环的值。
对于只有一个奇数环的情况,显然那一条返祖边也是一条合法的边。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){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 N=1e5+10,M=2e5+10;
int n,m,ans,all,odd[N],even[N],fa[N],dep[N];
int tot=1,head[N],nxt[M<<1],ver[M<<1],edge[M<<1];
bool vis[N];
void add_edge(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x)
{
dep[x]=dep[fa[x]]+1; vis[x]=true;
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(!vis[to]) fa[to]=x,edge[i]=edge[i^1]=true,dfs(to);
}
}
void dfs2(int x)
{
vis[x]=true;
for(int i=head[x];i;i=nxt[i])
if(fa[ver[i]]==x&&!vis[ver[i]])
dfs2(ver[i]),odd[x]+=odd[ver[i]],even[x]+=even[ver[i]];
if(x!=1&&odd[x]==all&&!even[x]) ans++;
}
signed main()
{
freopen("a.in","r",stdin); freopen("a.out","w",stdout);
n=read(); m=read();
for(int i=1,x,y;i<=m;i++)
x=read(),y=read(),
add_edge(x,y),add_edge(y,x);
dfs(1);
for(int i=1;i<=m;i++)
{
int x=ver[i<<1],y=ver[i<<1|1];
if(edge[i<<1]) continue;
if(dep[x]<dep[y]) swap(x,y);
if((dep[x]-dep[y]+1)&1) odd[x]++,odd[y]--,all++;
else even[x]++,even[y]--;
}
memset(vis,false,sizeof(vis)); dfs2(1);
printf("%lld",ans+(all==1));
return 0;
}
T2 括号密码
大坑未补
T3 排列
解题思路
这个题可就真有意思了。。
测试点分治模板题?? 对于每一个排列进行计算。
以排列 1 2 3 4
为例,我们枚举相应比例为 4 的数下标记为 r 所表示的数字是 \(s_r\) 。
然后枚举相应比例为 2 的数下标记为 l 所表示的数字是 \(s_l\) 。
对于 \([1,l-1]\) 以及 \([l+1,r-1]\) 这两个区间某个值域的数字可以用前缀和或者线段树求出来。
于是我们假设下标在 \([1,l-1]\) 权值在 \([1,s_l-1]\) 的数字的个数为 \(sum_1\) 。
假设下标在 \([l+1,r-1]\) 权值在 \([s_l+1,s_r-1]\) 的数字的个数为 \(sum_2\) 。
那么当前的 l 和 r 的贡献就是 \(sum_1\times sum_2\)
但是锁定这两个位置的并不是普遍适用的,因此我们也可以锁定相对位置为 2 , 3 的数查询两边合法的数字。
还有一种特例 2 4 1 3
我们选择枚举相对大小是 3 的数字,从左向右枚举相对大小是 4 的数字(记下标为 \(l\) )
考虑 一个数字 \(x\) 从 \(l\) 的右侧变为 \(l\) 左侧的点的贡献 其实就是在 \([l,r]\) 区间中 值域在 \([1,x-1]\) 相对于 x 产生了贡献。
位置在 \([1,l-1]\) 区间中大于 \(x+1\) 相对于 x 产生的贡献消失了。
于是我们直接 12 分治解决掉这个题。
也许时间稍大一些但是空间绝对最优。。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
#define ls x<<1
#define rs x<<1|1
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){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 N=2e3+10;
struct Segment_Tree
{
int tre[N<<2];
void push_up(int x){tre[x]=tre[ls]+tre[rs];}
void build(int x,int l,int r)
{
if(l==r) return tre[x]=0,void();
int mid=(l+r)>>1; tre[x]=0;
build(ls,l,mid); build(rs,mid+1,r);
}
void insert(int x,int l,int r,int pos,int val)
{
if(l==r) return tre[x]+=val,void();
int mid=(l+r)>>1;
if(pos<=mid) insert(ls,l,mid,pos,val);
else insert(rs,mid+1,r,pos,val);
push_up(x);
}
int query(int x,int l,int r,int L,int R)
{
if(L>R) return 0;
if(L<=l&&r<=R) return tre[x];
int mid=(l+r)>>1,sum=0;
if(L<=mid) sum+=query(ls,l,mid,L,R);
if(R>mid) sum+=query(rs,mid+1,r,L,R);
push_up(x); return sum;
}
}T1,T2;
int n,ans,a[10],s[N];
void SPJ()
{
for(int r=4;r<=n;r++)
{
T1.build(1,1,n); T2.build(1,1,n); T1.insert(1,1,n,s[1],1);
for(int l=2;l<=r-1;l++) T2.insert(1,1,n,s[l],1);
for(int l=2;l<=r-2;l++)
{
T2.insert(1,1,n,s[l],-1);
ans+=T1.query(1,1,n,1,s[l]-1)*T2.query(1,1,n,s[l]+1,s[r]-1);
T1.insert(1,1,n,s[l],1);
}
}
}
void SPJ2()
{
for(int r=4;r<=n;r++)
{
T1.build(1,1,n); T2.build(1,1,n); T1.insert(1,1,n,s[1],1);
for(int l=2;l<=r-1;l++) T2.insert(1,1,n,s[l],1);
for(int l=2;l<=r-2;l++)
{
T2.insert(1,1,n,s[l],-1);
ans+=T1.query(1,1,n,s[r]+1,s[l]-1)*T2.query(1,1,n,1,s[r]-1);
T1.insert(1,1,n,s[l],1);
}
}
}
void SPJ3()
{
for(int r=4;r<=n;r++)
{
T1.build(1,1,n); T2.build(1,1,n); T1.insert(1,1,n,s[1],1);
for(int l=2;l<=r-1;l++) T2.insert(1,1,n,s[l],1);
for(int l=2;l<=r-2;l++)
{
T2.insert(1,1,n,s[l],-1);
if(s[l]<=s[r])ans+=T1.query(1,1,n,1,s[l]-1)*T2.query(1,1,n,s[r]+1,n);
T1.insert(1,1,n,s[l],1);
}
}
}
void SPJ4()
{
for(int r=4;r<=n;r++)
{
T1.build(1,1,n); T2.build(1,1,n); T1.insert(1,1,n,s[1],1);
for(int l=2;l<=r-1;l++) T2.insert(1,1,n,s[l],1);
for(int l=2;l<=r-2;l++)
{
T2.insert(1,1,n,s[l],-1);
if(s[r]<= s[l])ans+=T1.query(1,1,n,1,s[r]-1)*T2.query(1,1,n,s[l]+1,n);
T1.insert(1,1,n,s[l],1);
}
}
}
void SPJ5()
{
for(int r=4;r<=n;r++)
{
T1.build(1,1,n); T2.build(1,1,n); T1.insert(1,1,n,s[1],1);
for(int l=2;l<=r-1;l++) T2.insert(1,1,n,s[l],1);
for(int l=2;l<=r-2;l++)
{
T2.insert(1,1,n,s[l],-1);
ans+=T1.query(1,1,n,1,s[r]-1)*T2.query(1,1,n,s[r]+1,s[l]-1);
T1.insert(1,1,n,s[l],1);
}
}
}
void SPJ6()
{
for(int r=4;r<=n;r++)
{
T1.build(1,1,n); T2.build(1,1,n); T1.insert(1,1,n,s[1],1);
for(int l=2;l<=r-1;l++) T2.insert(1,1,n,s[l],1);
for(int l=2;l<=r-2;l++)
{
T2.insert(1,1,n,s[l],-1);
ans+=T1.query(1,1,n,s[l]+1,s[r]-1)*T2.query(1,1,n,1,s[l]-1);
T1.insert(1,1,n,s[l],1);
}
}
}
void SPJ7()
{
for(int r=3;r<n;r++)
{
T1.build(1,1,n); T2.build(1,1,n); T1.insert(1,1,n,s[1],1);
for(int i=r+1;i<=n;i++) T2.insert(1,1,n,s[i],1);
for(int l=2;l<=r-1;l++)
{
if(s[l]>=s[r])ans+=T1.query(1,1,n,1,s[r]-1)*T2.query(1,1,n,s[l]+1,n);
T1.insert(1,1,n,s[l],1);
}
}
}
void SPJ8()
{
for(int r=3;r<n;r++)
{
T1.build(1,1,n); T2.build(1,1,n); T1.insert(1,1,n,s[1],1);
for(int i=r+1;i<=n;i++) T2.insert(1,1,n,s[i],1);
for(int l=2;l<=r-1;l++)
{
if(s[l]>=s[r])ans+=T1.query(1,1,n,1,s[r]-1)*T2.query(1,1,n,s[r]+1,s[l]-1);
T1.insert(1,1,n,s[l],1);
}
}
}
void SPJ9()
{
for(int r=3;r<n;r++)
{
T1.build(1,1,n); T2.build(1,1,n); T1.insert(1,1,n,s[1],1);
for(int i=r+1;i<=n;i++) T2.insert(1,1,n,s[i],1);
for(int l=2;l<=r-1;l++)
{
if(s[l]<=s[r])ans+=T1.query(1,1,n,s[l]+1,s[r]-1)*T2.query(1,1,n,s[r]+1,n);
T1.insert(1,1,n,s[l],1);
}
}
}
void SPJ10()
{
for(int r=3;r<n;r++)
{
T1.build(1,1,n); T2.build(1,1,n); T1.insert(1,1,n,s[1],1);
for(int i=r+1;i<=n;i++) T2.insert(1,1,n,s[i],1);
for(int l=2;l<=r-1;l++)
{
if(s[l]>=s[r])ans+=T1.query(1,1,n,s[r]+1,s[l]-1)*T2.query(1,1,n,s[l]+1,n);
T1.insert(1,1,n,s[l],1);
}
}
}
void SPJ11()
{
for(int r=3;r<n;r++)
{
T1.build(1,1,n); T2.build(1,1,n);
for(int i=r+1;i<=n;i++) T2.insert(1,1,n,s[i],1);
for(int i=1;i<=r-1;i++) T1.insert(1,1,n,s[i],1);
for(int l=1;l<=r-2;l++)
{
T1.insert(1,1,n,s[l],-1);
if(s[l]>s[r]) ans+=T1.query(1,1,n,1,s[r]-1)*T2.query(1,1,n,s[l]+1,n);
}
}
}
void SPJ12()
{
for(int r=4;r<=n;r++)
{
int sum=0; T1.build(1,1,n); T2.build(1,1,n);
for(int i=1;i<=r-1;i++) T2.insert(1,1,n,s[i],1);
for(int l=1;l<=r-2;l++)
if(s[l]>s[r]) ans+=sum;
else
{
sum+=T2.query(1,1,n,1,s[l]-1);
sum-=T1.query(1,1,n,s[l]+1,n);
T1.insert(1,1,n,s[l],1);
T2.insert(1,1,n,s[l],-1);
}
}
}
signed main()
{
freopen("c.in","r",stdin); freopen("c.out","w",stdout);
n=read();
for(int i=1;i<=4;i++) a[i]=read();
for(int i=1;i<=n;i++) s[i]=read();
if(a[1]==1&&a[2]==2&&a[3]==3&&a[4]==4) SPJ();//1 2 3 4
if(a[1]==4&&a[2]==3&&a[3]==2&&a[4]==1) reverse(s+1,s+n+1),SPJ();
if(a[1]==3&&a[2]==4&&a[3]==1&&a[4]==2) SPJ2();//3 4 1 2
if(a[1]==2&&a[2]==1&&a[3]==4&&a[4]==3) reverse(s+1,s+n+1),SPJ2();
if(a[1]==1&&a[2]==2&&a[3]==4&&a[4]==3) SPJ3();//1 2 4 3
if(a[1]==3&&a[2]==4&&a[3]==2&&a[4]==1) reverse(s+1,s+n+1),SPJ3();
if(a[1]==1&&a[2]==3&&a[3]==4&&a[4]==2) SPJ4();//1 3 4 2
if(a[1]==2&&a[2]==4&&a[3]==3&&a[4]==1) reverse(s+1,s+n+1),SPJ4();
if(a[1]==1&&a[2]==4&&a[3]==3&&a[4]==2) SPJ5();//1 4 3 2
if(a[1]==2&&a[2]==3&&a[3]==4&&a[4]==1) reverse(s+1,s+n+1),SPJ5();
if(a[1]==3&&a[2]==2&&a[3]==1&&a[4]==4) SPJ6();//3 2 1 4
if(a[1]==4&&a[2]==1&&a[3]==2&&a[4]==3) reverse(s+1,s+n+1),SPJ6();
if(a[1]==1&&a[2]==3&&a[3]==2&&a[4]==4) SPJ7();//1 3 2 4
if(a[1]==4&&a[2]==2&&a[3]==3&&a[4]==1) reverse(s+1,s+n+1),SPJ7();
if(a[1]==1&&a[2]==4&&a[3]==2&&a[4]==3) SPJ8();//1 4 2 3
if(a[1]==3&&a[2]==2&&a[3]==4&&a[4]==1) reverse(s+1,s+n+1),SPJ8();
if(a[1]==2&&a[2]==1&&a[3]==3&&a[4]==4) SPJ9();//2 1 3 4
if(a[1]==4&&a[2]==3&&a[3]==1&&a[4]==2) reverse(s+1,s+n+1),SPJ9();
if(a[1]==2&&a[2]==3&&a[3]==1&&a[4]==4) SPJ10();//2 3 1 4
if(a[1]==4&&a[2]==1&&a[3]==3&&a[4]==2) reverse(s+1,s+n+1),SPJ10();
if(a[1]==3&&a[2]==1&&a[3]==2&&a[4]==4) SPJ11();//3 1 2 4
if(a[1]==4&&a[2]==2&&a[3]==1&&a[4]==3) reverse(s+1,s+n+1),SPJ11();
if(a[1]==2&&a[2]==4&&a[3]==1&&a[4]==3) SPJ12();//2 4 1 3
if(a[1]==3&&a[2]==1&&a[3]==4&&a[4]==2) reverse(s+1,s+n+1),SPJ12();
printf("%lld",ans); return 0;
}