G. FQ 的函数

华中师范大学 2016 年“计蒜客杯”第十四届程序设计竞赛

G. FQ 的函数

Description
FQ 是个喜欢数学的孩子。有一天,FQ 发明了一个函数 FQ(n,p)。FQ(n,p)的值描述了 n!最多可以被 p 的多少次幂整除,其中 p 为一个素数。
举例来说,对于 FQ(8,3),我们要考查 8! = 8×7×6×5×4×3×2×1 = 40320。很容易发现,它可以被 32 整除,但是不能被 33 整除。所以FQ(8,3) = 2, 表示 8!最多可以被 32 整除。
对 FQ(k,p)可以严格的定义: k!可被p^FQ(k,p) 整除,但是不能被p^(FQ(k,p)+1) 整除。
ZQ 对 FQ 的发现很感兴趣,但是他对 FQ 在这个函数的讨论中仅使用十进制表示不满。ZQ于是定义了ZQ(n,p)。其中n是个p进制正整数,并且 ZQ(n,p)=FQ(n10,p)。其中n10表示 n 转换成十进制之后对应的数字。
本题的任务就是求出 ZQ(n,p)的值。注意:请将答案表示为十进制数。

Input
输入一个 T (T ≤ 50)表示 T 组数据。
每组测试数据占一行,是用空格分开的两个正两个整数 n,p。
数据保证:
(1) p≤16,并且 p 是素数。
(2) n 是一个 p 进制正整数,长度不超过10^5。
(3) 在高于十进制的进制中,使用 A 表示 10,B 表示 11,C 表示 12,D表示 13,E 表示 14,F 表示 15。

Output
对于每组测试用例,输出一行,包含一个整数表示你的答案。请将答案表示为十进制数。另外,由于答案可能太大,你只需要输出答案模1000000007 的余数。

Sample Input
2
11 2
1A1 11

Sample Output
1
22

Hint
样例第一组 (11)2 = (3)10,而 3!=6,可以被 2^1 整除,但不能被 2^2 整除。
样例第二组 (1A1)11 = (232)10,232! 可以被 11^22 整除,但是不能被 11^23 整除。

分析:
求n!中有多少个q就是将n反复除q直到比q小,注意到n是q进制的,所以除q就是将n右移一位,所以想到的就是每右移一次,就将结果加上n的十进制,但是右移n位复杂度O(n),将n转化成十进制也是O(n),因此O(n^2)肯定会超时。
其实O(n)的复杂度就可以求出答案,比如当n=3456,q=7时
sum=
3+
3*q+4+
(3*q+4) *q+
(3*q+4) *q+5) *q

#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<stack>
using namespace std;
#define LL long long
#define MOD 1000000007

char s[100000+10];
int q;
int len;

LL work(){
    LL sum=0;
    LL tmp=0;

    for(int i=0;i<len-1;i++){
        int num=s[i]>='A'?s[i]-'A'+10:s[i]-'0';
        tmp=(tmp*q%MOD+num)%MOD;
        sum=(sum+tmp)%MOD;
    }
    return sum;
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%s %d",s,&q);
        len=strlen(s);
        printf("%lld\n",work());
    }
    return 0;
}
def initialize(context): """初始化全局变量与策略参""" # 基础参 g.N = 102 # 通道宽度参 g.M = 7 # 波动幅度参 g.lookback = 20 # 历史据窗口 g.security = '301177.SZ' # 交易标的 # 状态变量 g.pos = 0 # 持仓状态(0空仓/1持仓) g.last_signal = 0 # 上次信号 g.channel1 = 0 # 上通道1值 g.channel3 = 0 # 上通道3值 g.current_close = 0 # 最新收盘价 # 初始化股票池 set_universe(g.security) def before_trading_start(context, data): """盘前计算通道指标""" try: # 获取历史据并校验 hist = get_history( security_list=g.security, count=g.lookback + 10, frequency='1d', field=['open', 'high', 'low', 'close'], fq='dypre' ) if hist is None or len(hist) < g.lookback: log.info(f"警告:{g.security}据不足,跳过计算") return # 计算通道指标 close = hist['close'] high = hist['high'] low = hist['low'] # 计算AA均线:(2*CLOSE+HIGH+LOW)/4的5日均值 aa = (2 * close + high + low) / 4 aa_ma5 = aa.rolling(5).mean().iloc[-1] # 通道1: AA*N/100 g.channel1 = aa_ma5 * g.N / 100 # 计算DD指标(动态均线) cc = abs(aa - aa.rolling(20).mean()) / aa.rolling(20).mean() dd_numerator = (cc * close).rolling(g.lookback).sum() dd_denominator = cc.rolling(g.lookback).sum() dd = dd_numerator / dd_denominator g.channel3 = dd.iloc[-1] * (1 + g.M/100) # 通道3 # 保存最新价格 g.current_close = close.iloc[-1] log.info(f"通道1: {g.channel1:.2f}, 通道3: {g.channel3:.2f}, 最新价: {g.current_close:.2f}") except Exception as e: log.error(f"盘前计算异常: {str(e)}") def handle_data(context, data): """盘中交易逻辑""" try: # 据有效性检查 if g.current_close == 0 or g.channel3 == 0: log.info("指标未初始化,跳过交易") return # 停牌检查 stock_status = get_stock_status(g.security, 'HALT') if stock_status[g.security]: log.info(f"{g.security}停牌,不执行交易") return # 买入逻辑:价格突破通道3 if g.pos == 0 and g.current_close > g.channel3: order_value(g.security, context.portfolio.cash) g.pos = 1 g.last_signal = 1 log.info(f"【买入信号】价格突破通道3: {g.current_close:.2f} > {g.channel3:.2f}") # 卖出逻辑:价格跌破通道下轨或止损 elif g.pos == 1: # 这里应补充通道下轨计算逻辑,示例以5日均线为例 ma5 = data[g.security].mavg(5, 'close') if g.current_close < ma5 or (g.current_close < g.channel3 * 0.95): # 跌破通道3的95%或5日均线 order_target(g.security, 0) g.pos = 0 g.last_signal = -1 log.info(f"【卖出信号】价格跌破阈值: {g.current_close:.2f} < {ma5:.2f}") except Exception as e: log.error(f"交易执行异常: {str(e)}") # 辅助函数:获取均线 def get_ma(series, window): return series.rolling(window).mean() 以双均线的代码格式重新编写这代码
06-16
import numpy as np import pandas as pd def initialize(context): """初始化参与标的""" # 指标参 g.M = 55 # 输家指标周期 g.N = 34 # 赢家指标RSV周期 g.security = '301177.SZ' # 交易标的 set_universe([g.security]) # 设置股票池 # 持仓状态 g.pos = 0 # 0:空仓,1:持仓 g.prev_winner = 0 # 前周期赢家指标值 g.prev_loser = 0 # 前周期输家指标值 g.current_winner = 0 g.current_loser = 0 def calculate_indicators(df, M, N): """向量化计算指标(修复nan问题)""" # 1. 输家指标计算(修复除零错误) hhv_high = df['high'].rolling(window=M, min_periods=1).max() llv_low = df['low'].rolling(window=M, min_periods=1).min() denominator = hhv_high - llv_low # 双重保护避免除零错误 df['输家'] = np.where( denominator != 0, 100 * (hhv_high - df['close']) / denominator, 0 # 分母为零时直接设为0 ) # 2. RSV指标计算(修复除零错误) hhv_high_n = df['high'].rolling(window=N, min_periods=1).max() llv_low_n = df['low'].rolling(window=N, min_periods=1).min() rsv_denominator = hhv_high_n - llv_low_n df['rsv'] = np.where( rsv_denominator != 0, (df['close'] - llv_low_n) / rsv_denominator * 100, 0 # 分母为零时直接设为0 ) # 3. KDJ指标计算(修复初始值问题) rsv_series = pd.Series(df['rsv']) k = rsv_series.ewm(alpha=1/3, adjust=False).mean() d = k.ewm(alpha=1/3, adjust=False).mean() j = 3 * k - 2 * d # 4. 赢家指标计算(确保无nan) df['赢家'] = j.ewm(span=6, adjust=False).mean().fillna(0) # 确保所有指标无nan df[['输家', 'rsv', '赢家']] = df[['输家', 'rsv', '赢家']].fillna(0) return df def before_trading_start(context, data): """盘前计算指标(修复据获取和处理)""" try: # 获取历史据(增加据量,确保足够计算窗口) hist = get_price( security=g.security, count=max(g.M, g.N) * 2, # 确保有足够的据点 frequency='1d', fields=['close', 'high', 'low'], fq='pre' # 前复权处理 ) if hist is None or len(hist) < max(g.M, g.N): log.info("警告:{g.security}据不足,跳过计算") return # 转换为DataFrame并计算指标 df = hist.copy() df = calculate_indicators(df, g.M, g.N) # 存储当前与前周期指标(确保无nan) g.current_winner = df['赢家'].iloc[-1] g.current_loser = df['输家'].iloc[-1] # 前周期指标(处理边界情况) if len(df) >= 2: g.prev_winner = df['赢家'].iloc[-2] g.prev_loser = df['输家'].iloc[-2] else: g.prev_winner = 0 g.prev_loser = 0 # 日志记录(用于调试) log.info("计算结果: 赢家={g.current_winner}, 输家={g.current_loser}") except Exception as e: log.info("指标计算异常: {str(e)}") # 设置默认值避免策略崩溃 g.current_winner = 0 g.current_loser = 0 def handle_data(context, data): """盘中执行交易逻辑""" log.info("g.current_winner %s" % g.current_winner) log.info("g.current_loser %s" % g.current_loser) # 确保指标有效 if np.isnan(g.current_winner) or np.isnan(g.current_loser): log.info("警告:指标值为nan,跳过交易") return if g.pos == 0: # 买入条件:赢家上穿输家(金叉) if g.prev_winner < g.prev_loser and g.current_winner > g.current_loser: order_value(security=g.security, value=context.portfolio.cash * 0.8) # 使用80%资金 g.pos = 1 log.info("【买入信号】赢家上穿输家:{g.current_winner:.2f} > {g.current_loser:.2f}") else: # 卖出条件:赢家下穿输家(死叉) if g.prev_winner > g.prev_loser and g.current_winner < g.current_loser: order_target(security=g.security, amount=0) g.pos = 0 log.info("【卖出信号】赢家下穿输家:{g.current_winner:.2f} < {g.current_loser:.2f}") 优化这个策略
06-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值