2022CCPC广州 CM

C

这里用了map存缩点后的边,会慢很多 

一个比较显而易见的性质:对于v节点的所有ui节点(ui向v连边),都有dist[ui]相等。

所以对于这些dist应该相等的点缩点,然后最长路,之后dis之差就是该点点权了

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=2e5+10;
vector<int>E[N],invE[N];
int p[N],dist[N];
bool st[N],vis[N];
int Find(int x)
{
    if(x!=p[x])return p[x]=Find(p[x]),p[x];
    return x;
}
map<int,int>nwE[N];
int dfs(int u)
{
    if(st[u])return 1;
    if(vis[u])return 0;
    st[u]=1;
    for(auto [v,t]:nwE[u])
    {
        if(dfs(v))return 1;
    }
    st[u]=0;
    vis[u]=1;
    return 0;
}
int color[N];
using pii=pair<int,int>;
int rs[N];
void dijkstra()
{
    dist[1]=1;
    priority_queue<pii>heap;
    heap.push({1,1});
    while(heap.size())
    {
        auto [dis,u]=heap.top();heap.pop();
        for(auto [v,t]:nwE[u])
        {
            if(!t)continue;
            if(dist[v]<dist[u]+1)
            {
                dist[v]=dist[u]+1;
                heap.push({dist[v],v});
            }
        }
    }
    queue<int>q;
    q.push(1);
    rs[1]=1;
    while(q.size())
    {
        int u=q.front();q.pop();
        if(st[u])continue;st[u]=1;
        for(auto v:E[u])
        {
            {
                rs[v]=dist[Find(v)]-dist[Find(u)];
                q.push(v);
            }
        }
        
    }
}
void solve()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)E[i].clear(),invE[i].clear(),nwE[i].clear(),
    st[i]=0,vis[i]=0,color[i]=-1;
    memset(dist,0,sizeof(dist[0])*(n+1));
    for(int i=1,u,v;i<=m;++i)
    {
        scanf("%d%d",&u,&v);
        E[u].push_back(v);
        invE[v].push_back(u);
    }
    if(n==1){cout<<"YES\n1\n"<<endl;return ;}
    for(int i=1;i<=n;++i)p[i]=i;
    for(int i=1;i<=n;++i)
    if(invE[i].size())
    {
        int t=invE[i][0];
        for(auto v:invE[i])
        p[Find(v)]=p[Find(t)];
    }
    for(int i=1;i<=n;++i)
    {
            for(auto v:E[i])
            nwE[Find(i)][Find(v)]=1;
    }
    for(int i=1;i<=n;++i)
    for(auto v:E[i])
    {
        if(Find(i)==Find(v)){printf("No\n");return ;}
    }
    if(dfs(1)){printf("No\n");return ;}
    printf("Yes\n");
    memset(st,0,sizeof(st[0])*(n+1));
    dijkstra();
    for(int i=1;i<=n;++i)printf("%d%c",rs[i]," \n"[i==n]);
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)solve();
}

M

考虑数位背包

#include<bits/stdc++.h>
using namespace std;
const int P=1e9+7,N=1e3+10;
using ll=long long;
ll finv[N],fac[N];
ll POW(ll x,int k=P-2,ll rs=1){while(k){if(k&1)rs=rs*x%P;x=x*x%P;k>>=1;}return rs;}
void init()
{
    finv[1]=finv[0]=fac[0]=1;
    for(int i=1;i<N;++i)fac[i]=fac[i-1]*i%P;
    finv[N-1]=POW(fac[N-1]);
    for(int i=N-2;i;--i)finv[i]=finv[i+1]*(i+1)%P;
}
ll C(int a,int b)
{
    if(b>a||a<0||b<0)return 0;
    return fac[a]*finv[a-b]%P*finv[b]%P;
}
ll dp[55][20][257];
int a[55];
const int Mx=162;

ll dfs(int pos,ll cnt,ll r,ll &n,ll&k)
{
    if(pos==-1)return r==0;
    if(r>=Mx)return 0;
    if(r<0)return 0;
    ll &rs=dp[pos][cnt][r];
    if(~rs)return rs;
    rs=0;
    int x=(pos==0?0:((n>>pos-1)&1));
    if(!a[pos])
    {
        for(int i=0;i<=k-cnt;++i)
        rs+=C(k-cnt,i)*dfs(pos-1,cnt,(r-i*(k-i)<<1)|x,n,k)%P;
    }
    else 
    {
        for(int i=0;i<=cnt;++i)
        for(int j=0;j<=k-cnt;++j)
        rs+=C(k-cnt,j)*C(cnt,i)%P*dfs(pos-1,i,(r-(i+j)*(k-i-j))<<1|x,n,k)%P;
    }
    return rs%=P,rs;
}
ll cal(ll n,ll m,ll k)
{
    int pos=-1;
    memset(dp,-1,sizeof(dp));
    while(m)a[++pos]=m&1,m>>=1;
    ll r=0;
    for(int i=pos+1;i<=50;++i)
    if(n>>i&1)r+=1ll<<(i-pos-1);
    return dfs(pos+1,k,r,n,k);
}
int main()
{
    init();
    ll n,m,k;scanf("%lld%lld%lld",&n,&m,&k);
    printf("%lld\n",cal(n,m,k));
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值