HDU-6021 MG loves string

本文探讨了在给定的密码表下,任意长度字符串变换成自身次数的数学期望问题。通过深入分析,提出了一种高效算法,利用容斥原理和最小公倍数计算方案数,解决了传统方法的时间复杂度过高问题。

题目描述

给定\(26\)个小写字母\(x1,x2,...,x26\)的字符串作为“密码表”,

\(26\)个密码分别对应\(a-z,26\) 个小写字母,一个字母进行一次变换,

意味着该字母变换成对应的密码,譬如字母\(b\)下一次变换应该变成\(x2\)

(可以知道,经过有限次的变换,每个字母最终还是会变换回来的)。

求长度为\(n\)的任意字符串的变换成自身的期望次数。

Input

第一行读入一个\(T(T<=10)\)

表示数据的组数

然后一个\(n\),表示字符串长度\((n<=1000000000)\)

然后是一个密码表

Output

输出答案为期望乘上\(26^n\)并模上\(1e9+7\)的结果

Sample Input

2
2
abcdefghijklmnpqrstuvwxyzo
1
abcdefghijklmnopqrstuvwxyz

Sample Output

5956
26

容斥好题!!!

我们发现实际上题目要我们求的答案就是每个串变为自身的次数之和。

对于每个字母我们都可以求出他们变化为自身的次数\(A_i\)

对于一个字符串,它变为自身的次数实际上就是该字符串中所有\(A_i\)\(lcm\)

如果暴力搜索的话,我们会是搜索每个字母是否在该字符串中出现,最后统计方案数。

这样的话,时间复杂度为\(O(2^{26}*log_n)*T\),无法承受。

我们发现对于一些\(A_i\)相等的字母我们选择其中的任意一个就行了,而\(A_i\)不同的字母一共也就最多有\(1+2+3+4+5+6=28>26\),即\(6\)种。

我们发现复杂度为\(O(2^6*log_n*T)\)是完全可以接受的。


首先,我们先将所有不同的\(A_i\)求出来,共\(tot\)个不同的取值。

对于当前考虑的\(A_i\)的集合\(s\),我们需要知道\(n\)个数放入其中,并且每个集合中都有放数的方案数。

即我们需要知道\(n\)个数,放入\(m\)个集合并且每个集合至少要有一个数的方案数。

这个我们可以利用容斥来解决。

对于当前的集合\(s\),一共有\(cnt\)个字母,那么一共有\(cnt^n\)种情况。

我们发现,这\(cnt^n\)种情况中,有一大部分都是含有空集合的情况的。

于是我们可以枚举其子集,将答案减去其子集的答案即可。

于是我们对于一种状态,我们求出了方案数\(dp[s]\)


接下来,我们就可以直接开始爆搜的,对于当前的状态\(s\),我们维护其\(lcm\),最后答案累加上\(lcm*dp[s]\)

代码如下

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define reg register
#define Raed Read
#define clr(a,b) memset(a,b,sizeof a)
#define Mod(x) (x>=mod)&&(x-=mod)
#define debug(x) cerr<<#x<<" = "<<x<<endl;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)>(b)?(b):(a))
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
#pragma GCC target("avx,avx2,sse4.2")
#pragma GCC optimize(3)

inline int Read(void) {
    int res=0,f=1;
    char c;
    while(c=getchar(),c<48||c>57)if(c=='-')f=0;
    do res=(res<<3)+(res<<1)+(c^48);
    while(c=getchar(),c>=48&&c<=57);
    return f?res:-res;
}

template<class T>inline bool Min(T &a, T const&b) {
    return a>b?a=b,1:0;
}
template<class T>inline bool Max(T &a, T const&b) {
    return a<b?a=b,1:0;
}
const int N=1e5+5,M=7e6+5,mod=1e9+7;

bool MOP1;

int n;

inline int gcd(int a,int b) {
    while(b^=a^=b^=a%=b);
    return a;
}

char S[30];

int tot,Ans,cnt[28],vis[28],Sum[10],A[10],dp[(1<<6)+5];

void dfs(int x,int s,int Lcm) {
    if(x==tot+1) {
        (Ans+=dp[s]*Lcm)%=mod;
        return;
    }
    dfs(x+1,s,Lcm);
    dfs(x+1,s|(1<<(x-1)),Lcm/gcd(Lcm,A[x])*A[x]);
}

inline int Pow(int x,int y) {
    int res=1;
    while(y) {
        if(y&1)res=(res*x)%mod;
        x=(x*x)%mod,y>>=1;
    }
    return res;
}

bool MOP2;

inline void _main() {
    int T=Read();
    while(T--) {
        int n=Read();
        tot=Ans=0,scanf("%s",S+1);
        clr(cnt,0),clr(Sum,0),clr(vis,0);
        rep(i,1,26) if(!vis[i]) {
            int temp=0,Now=i;
            while(!vis[Now])temp++,vis[Now]=1,Now=S[Now]-'a'+1;
            cnt[temp]+=temp;
        }
        rep(i,1,26)if(cnt[i])A[++tot]=i,Sum[tot]=cnt[i];
        ret(i,1,1<<tot) {
            int res=0;
            rep(j,1,tot)if(i&(1<<(j-1)))res+=Sum[j];
            dp[i]=Pow(res,n);
        }
        ret(i,1,1<<tot) {
            int res=0;
            for(int j=i; j; j=i&(j-1))if(j!=i)res+=dp[j],Mod(res);
            dp[i]-=res,(dp[i]<0)&&(dp[i]+=mod);
        }
        dfs(1,0,1);
        printf("%d\n",Ans);
    }
}

signed main() {
    _main();
    return 0;
}

转载于:https://www.cnblogs.com/dsjkafdsaf/p/11438156.html

源码地址: https://pan.quark.cn/s/d1f41682e390 miyoubiAuto 米游社每日米游币自动化Python脚本(务必使用Python3) 8更新:更换cookie的获取地址 注意:禁止在B站、贴吧、或各大论坛大肆传播! 作者已退游,项目不维护了。 如果有能力的可以pr修复。 小引一波 推荐关注几个非常可爱有趣的女孩! 欢迎B站搜索: @嘉然今天吃什么 @向晚大魔王 @乃琳Queen @贝拉kira 第三方库 食用方法 下载源码 在Global.py中设置米游社Cookie 运行myb.py 本地第一次运行时会自动生产一个文件储存cookie,请勿删除 当前仅支持单个账号! 获取Cookie方法 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 按刷新页面,按下图复制 Cookie: How to get mys cookie 当触发时,可尝试按关闭,然后再次刷新页面,最后复制 Cookie。 也可以使用另一种方法: 复制代码 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 控制台粘贴代码并运行,获得类似的输出信息 部分即为所需复制的 Cookie,点击确定复制 部署方法--腾讯云函数版(推荐! ) 下载项目源码和压缩包 进入项目文件夹打开命令行执行以下命令 xxxxxxx为通过上面方式或取得米游社cookie 一定要用双引号包裹!! 例如: png 复制返回内容(包括括号) 例如: QQ截图20210505031552.png 登录腾讯云函数官网 选择函数服务-新建-自定义创建 函数名称随意-地区随意-运行环境Python3....
### 关于HDU - 6609 的题目解析 由于当前未提供具体关于 HDU - 6609 题目的详细描述,以下是基于一般算法竞赛题型可能涉及的内容进行推测和解答。 #### 可能的题目背景 假设该题目属于动态规划类问题(类似于多重背包问题),其核心在于优化资源分配或路径选择。此类问题通常会给出一组物品及其属性(如重量、价值等)以及约束条件(如容量限制)。目标是最优地选取某些物品使得满足特定的目标函数[^2]。 #### 动态转移方程设计 如果此题确实是一个变种的背包问题,则可以采用如下状态定义方法: 设 `dp[i][j]` 表示前 i 种物品,在某种条件下达到 j 值时的最大收益或者最小代价。对于每一种新加入考虑范围内的物体 k ,更新规则可能是这样的形式: ```python for i in range(n): for s in range(V, w[k]-1, -1): dp[s] = max(dp[s], dp[s-w[k]] + v[k]) ``` 这里需要注意边界情况处理以及初始化设置合理值来保证计算准确性。 另外还有一种可能性就是它涉及到组合数学方面知识或者是图论最短路等相关知识点。如果是后者的话那么就需要构建相应的邻接表表示图形结构并通过Dijkstra/Bellman-Ford/Floyd-Warshall等经典算法求解两点间距离等问题了[^4]。 最后按照输出格式要求打印结果字符串"Case #X: Y"[^3]。 #### 示例代码片段 下面展示了一个简单的伪代码框架用于解决上述提到类型的DP问题: ```python def solve(): t=int(input()) res=[] cas=1 while(t>0): n,k=list(map(int,input().split())) # Initialize your data structures here ans=find_min_unhappiness() # Implement function find_min_unhappiness() res.append(f'Case #{cas}: {round(ans)}') cas+=1 t-=1 print("\n".join(res)) solve() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值