• 排列+函数映射——hdu6038好题


    /* 
    引理:[0,n-1]的排列,i向a[i]连边,那么每个数必定在一个环中 
    所以数组a可以分割成一些环,数组b也可以分割成一些环
    先讨论a的一个环
    a[a1]=a2 a[a2]=a3 a[a3]=a4 a[a4]=a5 a[a5]=a6 a[a6]=a1 这个环长度为6
    
    那么套到函数 f[i]=b[ f[a[i] ]中
        f[a1]=b[f[a2]]
        f[a2]=b[f[a3]]
        f[a3]=b[f[a4]]
        f[a4]=b[f[a5]]
        f[a5]=b[f[a6]]
        f[a6]=b[f[a1]]
        
    可以把b[f[a[i]]] = f[i] 当成是b数组的下标i到b[i]的映射 ,只不过这里的下标i 是f[a[i]]], b[i] 是f[i] 
    (可以发现这个f函数有点像反函数的感觉) 那么显然因为b也有和a类似的循环节,我们要找到一个b的循环节来套到上述映射里,这个循环节长度必须是上面循环节的约数
    因为a[i]=ai 的循环节是6,那么b关于f的映射必定要能整除6
    如果不是约数,那么f[ai]可能会对应到不同的值,这就不满足映射条件了 求方案数,设a其中一个长度为len的环的组成方案有k种,那么计算k时b所有长为len约数的环都要算上贡献 最后的结果就是 mul(k),即所有k相乘
    */ #include<bits/stdc++.h> using namespace std; #define maxn 100005 #define mod 1000000007 #define ll long long int a[maxn],b[maxn],n,m,cnt1[maxn],cnt2[maxn],vis[maxn]; ll tot[maxn]; ll Pow(ll a,ll b){ ll res=1; while(b){ if(b%2)res=res*a%mod; b>>=1;a=a*a%mod; } return res; } int main(){ int t=0; while(cin>>n>>m){ t++; memset(cnt1,0,sizeof cnt1); memset(cnt2,0,sizeof cnt2); for(int i=0;i<n;i++)scanf("%d",&a[i]); for(int i=0;i<m;i++)scanf("%d",&b[i]); memset(vis,0,sizeof vis); for(int i=0;i<n;i++) if(!vis[i]){ int p=i,len=1; vis[i]=1; while(a[p]!=i) p=a[p],len++,vis[p]=1; cnt1[len]++; } memset(vis,0,sizeof vis); for(int i=0;i<m;i++) if(!vis[i]){ int p=i,len=1; while(b[p]!=i) p=b[p],len++,vis[p]=1; cnt2[len]++; } memset(tot,0,sizeof tot); for(int len=1;len<=m;len++)//枚举b环的长度len for(int j=1;j*len<=n;j++) tot[j*len]=(tot[j*len]+cnt2[len]*len%mod)%mod; //每个长度为len的a环都有tot[len]种安排方案 ll ans=1; for(int len=1;len<=n;len++) if(cnt1[len]) ans=ans*Pow(tot[len],cnt1[len])%mod; printf("Case #%d: %lld ",t,ans); } return 0; }
  • 相关阅读:
    自我介绍
    目前流行的源程序版本管理软件和项目管理软件的优缺点
    四月是你的谎言
    软件分析(Mobile Apps )--百词斩
    程序扩展
    超级无敌小学四则运算题目程序
    4组 团队展示
    2020面向对象设计与构造 第四单元 & 课程 博客总结
    2020面向对象设计与构造 第三单元 博客总结
    2020面向对象设计与构造 第二单元 博客总结
  • 原文地址:https://www.cnblogs.com/zsben991126/p/11191195.html
Copyright © 2020-2023  润新知