8.16暑假集训4
题面
下发文件和题解
A.打地鼠
很水,二维前缀和累加即可.时间复杂度
B.竞赛图
的暴力应该都会,枚举每一个子图,每次跑一遍
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 51
using namespace std;
static inline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f?-x:x;
}
static inline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|48);
}
ll t,n,ans;
ll dfn[maxn],low[maxn],tot;
ll mp[maxn][maxn],mp1[maxn][maxn];
bool vis[maxn];
bool fl[maxn];
bool flag[maxn];
ll num[maxn];
stack<ll> s;
ll cnt;
ll h;
static inline void clear()
{
cnt=tot=0;while(!s.empty()) s.pop();
memset(fl,0,sizeof(fl));
memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
}
static inline void tarjan(rll x)
{
dfn[x]=low[x]=++tot;s.push(x);fl[x]=1;
for(rll i=1;i<=n;i++)
{
if(!mp1[x][i]) continue;
if(!dfn[i]) tarjan(i),low[x]=min(low[x],low[i]);
else if(fl[i]) low[x]=min(low[x],dfn[i]);
}
if(dfn[x]==low[x])
{
rll t;cnt++;
do
{
t=s.top();s.pop();fl[t]=0;
} while(t!=x);
}
}
static inline void dfs(rll x,rll d,rll sz)
{
flag[x]=1;
if(d==sz)
{
clear();
for(rll i=1;i<=n;i++)
for(rll j=1;j<=n;j++)
if(flag[i]&&flag[j]) mp1[i][j]=mp[i][j];
else mp1[i][j]=0;
for(rll i=1;i<=n;i++) if((flag[i])&&!dfn[i]) tarjan(i);
if(cnt==1) ans++;
flag[x]=0;
return;
}
for(rll i=x+1;i<=n;i++) if(!flag[i]) dfs(i,d+1,sz);
flag[x]=0;
}
int main()
{
t=read();
while(t--)
{
ans=0;n=read();
for(rll i=1;i<=n;i++) for(rll j=1;j<=n;j++) mp[i][j]=read();
for(rll i=1;i<=n;i++)
for(rll j=1;j<=n;j++)
dfs(j,1,i);
write(ans+1);puts("");
}
return 0;
}
二进制是一个好东西,既然数据范围很小,我们可以考虑二进制存状态,把非强连通图筛出去.
先更新一下每一个点的出边的集合的交,找交集是因为我们现在要找的是非强连通图,如果找并,那么最终会把强连通图也筛出去.
这样操作
mp[0]=(1<<n)-1;
for(rll i=1;i<=n;i++) for(rll j=1;j<=n;j++) mp[1<<i-1]|=(read()<<j-1);//读入
for(rll i=1;i<(1<<n);i++) mp[i]=mp[lowbit(i)]&mp[i^lowbit(i)];//更新出边集合交情况,如:11010110[100]=11010110[000]+00000000[100]
//lowbit取的是最后一个1和它后面的所有0
然后枚举每一个子集,虑对于每一个强连通的子集 ,设其中所有的点的出边集合的交为 .那么对于每一个 的子集 , 将被更新成不是强连通的子集.
因为前面的非强连通图已经筛出去了,而后面没筛出去的状态还会再枚举到,这样就可以保证不重不漏、不多不少.最后统计没有被筛出去的情况即可.
这样操作
for(rll i=1;i<(1<<n);i++)//S
if(!fl[i])
for(rll j=mp[i];j;j=(j-1)&mp[i])//R
fl[i|j]=1;
ans=1;
for(rll i=1;i<(1<<n);i++) ans+=(!fl[i]);
C.糖果
(由于懒,就不打LaTeX了)
设dp[i][j][k]为当前小A选到i,小B选到j,小C还剩k个位置可选.
对于小A的选择,如果当前的数字在排列a内不如在排列b内更优,那么该数字一定会被小C拿走,加入到c排列中;否则一定是被小A拿走,那么小C的选择就少一个.对于小B也就同理啦.
所以,我们可以再给dp数组加一维,表示当前进行到哪一步.
最后,统计答案时,直接乘上3*i-1和3*i-2即可.
(证明搬的网上的)
对于第i轮,在小C选之前小A和小B一定各选了一个数,并且一定是在小C当前要选的数的优先级前选的.
举个例子就是i=3的时候此时小C应该选择第9个数,那么小A和小B选择的就是小C整个喜好序列中的前8个数,方案就有 个.
因此对于第 i 轮而言要乘上一个 .
(因为是搬的所以有LaTeX)
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 401
#define mod 1000000007
using namespace std;
static inline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f?-x:x;
}
static inline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|48);
}
ll n,a[maxn],b[maxn],ta[maxn],tb[maxn];
ll dp[maxn][maxn][201][2],ans;
int main()
{
n=read();
for(rll i=1;i<=n;i++) a[i]=read(),ta[a[i]]=i;
for(rll i=1;i<=n;i++) b[i]=read(),tb[b[i]]=i;
dp[1][1][0][0]=1;
for(rll i=1;i<=n+1;i++)
for(rll j=1;j<=n+1;j++)
for(rll k=0;k<=n/3;k++)
{
if(dp[i][j][k][0])
{
if(i==n+1)
{
if(!k) ans=(ans+dp[i][j][k][0])%mod;continue;
}
if(tb[a[i]]<j) dp[i+1][j][k][0]=(dp[i+1][j][k][0]+dp[i][j][k][0])%mod;
else
dp[i][j][k][1]=(dp[i][j][k][1]+dp[i][j][k][0])%mod,
dp[i+1][j][k-1][0]=(dp[i+1][j][k-1][0]+dp[i][j][k][0]*k%mod)%mod;
}
if(dp[i][j][k][1])
{
if(ta[b[j]]<i) dp[i][j+1][k][1]=(dp[i][j+1][k][1]+dp[i][j][k][1])%mod;
else if(a[i]!=b[j])
dp[i+1][j+1][k+1][0]=(dp[i+1][j+1][k+1][0]+dp[i][j][k][1])%mod,
dp[i][j+1][k-1][1]=(dp[i][j+1][k-1][1]+dp[i][j][k][1]*k%mod)%mod;
}
}
for(rll i=1;i<=n;i++) if(i%3) ans=ans*i%mod;
write(ans);
return 0;
}
D.树
先将这个树进行轻重链剖分.
对于重边,可以直接使用线段树维护颜色序列.
对于轻边,可以维护两个时间戳,一个打在父亲上(lv)表示这条边最后一次被涂黑的时间;另一个打在儿子上(rv)表示这条边最后一次被涂白的时间.同样使用线段树维护.
具体细节:
点击查看代码
struct tree
{
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
ll lv,rv,v,tag;
}t[maxn<<2];
static inline void pushup(rll rt)
{
t[rt].v=t[ls(rt)].v+t[rs(rt)].v;
if(t[ls(rt)].rv!=t[rs(rt)].lv)t[rt].v++;
t[rt].lv=t[ls(rt)].lv;t[rt].rv=t[rs(rt)].rv;
return;
}
static inline void pushdown(rll rt)
{
if(t[rt].tag)
{
t[ls(rt)].lv=t[ls(rt)].rv=t[rs(rt)].lv=t[rs(rt)].rv=t[rt].tag;
t[ls(rt)].tag=t[rs(rt)].tag=t[rt].tag;
t[ls(rt)].v=t[rs(rt)].v=0;
t[rt].tag=0;
}
}
static inline void build(rll rt,rll l,rll r)
{
if(l==r)
{
t[rt].lv=t[rt].rv=l;
t[rt].v=0;
return;
}
rll mid=(l+r)>>1;
build(ls(rt),l,mid);
build(rs(rt),mid+1,r);
pushup(rt);
}
static inline void upd(rll rt,rll l,rll r,rll x,rll y,rll v)
{
if(x<=l&&r<=y) { t[rt].v=0;t[rt].tag=t[rt].lv=t[rt].rv=v;return; }
pushdown(rt);
rll mid=(l+r)>>1;
if(x<=mid)upd(ls(rt),l,mid,x,y,v);
if(y>mid)upd(rs(rt),mid+1,r,x,y,v);
pushup(rt);
}
static inline ll query(rll rt,rll l,rll r,rll x,rll y)
{
if(x<=l&&r<=y) return t[rt].v;
pushdown(rt);
rll mid=(l+r)>>1,ans=0;
if(x<=mid) ans+=query(ls(rt),l,mid,x,y);
if(y>mid) ans+=query(rs(rt),mid+1,r,x,y);
if(x<=mid&&y>mid&&t[ls(rt)].rv!=t[rs(rt)].lv) ans++;
return ans;
}
static inline ll chk(rll rt,rll l,rll r,rll pos)
{
if(l==r) return t[rt].lv;
pushdown(rt);
rll mid=(l+r)>>1;
if(pos<=mid)return chk(ls(rt),l,mid,pos);
else return chk(rs(rt),mid+1,r,pos);
}
static inline void update(rll x,rll y)
{
cnt++;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
upd(1,1,n,dfn[top[x]],dfn[x],cnt);
x=f[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
upd(1,1,n,dfn[y],dfn[x],cnt);
}
static inline ll Query(rll x,rll y)
{
rll ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans+=query(1,1,n,dfn[top[x]],dfn[x]);
if(chk(1,1,n,dfn[top[x]])!=chk(1,1,n,dfn[f[top[x]]]))ans++;
x=f[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
ans+=query(1,1,n,dfn[y],dfn[x]);
return ans;
}
while(q--)
{
op=read();rll x=read(),y=read();
if(op==1) update(x,y);else write(Query(x,y)),puts("");
}
--END--
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/p/16593112.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!