Consecutive sequence with sum 0

本文介绍了一种算法,用于计算整数数组中连续子数组的个数,这些子数组的元素之和为零。通过计算前缀和并查找相等的前缀和来确定是否存在零和子数组。

You are given an integer array which contains positive integers, zero and negetive integers
count how many consecutive sequences in this array make a sum of 0.

exmaple
int[] a = {4, -1, 2, 1, -2, -1, 5, 0} ;
The result is 2
-1, 2, 1, -2, makes a sum of 0
2, 1, -2, -1, makes a sum of 0
0 makes a sum of 0

consider a consecutive sequence in array a, say xi, ... xj, if xi + ... + xj = 0, then x0 + .. + x(i-1) = x0 + .. + xj
so we can compute all the prefix sum of array a, and see whether there are equal elements among these sum
if there is, then there must be some consecutive sequence, makes sum of 0

 

ContractedBlock.gifExpandedBlockStart.gifCode
 1 public int Count(int[] a)
 2 {
 3     // Compute prefix sum
 4     int[] sum = new int[a.Length];
 5     sum[0= a[0];
 6     for (int i = 1; i < sum.Length; i++)
 7         sum[i] = sum[i - 1+ a[i];
 8 
 9     Array.Sort(sum); // for quick determine same prefix sum
10     int c = 0;// result
11     if (sum[0== 0)
12         c++;
13     for (int i = 1; i < sum.Length; i++)
14     {
15         if (sum[i] == 0// the consecutive sequence start from a[0]
16             c++;
17         if (sum[i] == sum[i - 1])// the consecutive sequence not start from a[0]
18             c++;
19     }
20     return c;
21 }
22 

 

修改:检测代码里有没有方法 ‘_handle_run_analysis’ ,方法 ‘_handle_get_results’ ,没有的情况,根据代码的结构进行补充。(当模块收到子类界面的token里发送的“运行‘指令后就开始运行该模块(按照原来的方法进行)。。待分析数据完成,生成5注号码后回传数据到子类界面的token的相同标签的条目后面。)代码#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import uuid import queue import logging import random import numpy as np import pandas as pd import chardet from typing import Dict, List, Tuple, Optional import math import threading from collections import Counter, defaultdict from threading import Lock import time # Global event center instance event_center = None # Utility functions def map_positions_to_coords(position_matrix: Dict[str, str]) -> Dict[str, Tuple[int, int]]: """Map position strings to coordinate tuples""" coords = {} for num, pos in position_matrix.items(): row = int(pos[1:pos.find('c')]) col = int(pos[pos.find('c') + 1:]) coords[num] = (row, col) return coords def validate_numbers(num_list: List[int], min_val: int, max_val: int) -> bool: """Validate if numbers are within specified range""" return all(min_val <= n <= max_val for n in num_list) # Event system class Event: def __init__(self, event_id: str, event_type: str, source: str, target: str = None, data: dict = None, token: str = None): self.event_id = event_id self.type = event_type self.source = source self.target = target self.data = data or {} self.token = token class EventCenter: _instance = None _lock = Lock() def __new__(cls): if cls._instance is None: with cls._lock: if cls._instance is None: cls._instance = super().__new__(cls) cls._instance._subscribers = defaultdict(list) return cls._instance def subscribe(self, event_type: str, token: str, callback): with self._lock: self._subscribers[(event_type, token)].append(callback) def publish(self, event: Event): with self._lock: callbacks = self._subscribers.get((event.type, event.token), []) for callback in callbacks: callback(event) # Global configuration class GlobalConfig: MODULE1_ID = "input_analysis" MODULE2_ID = "combination_analysis" MODULE3_ID = "follow_analysis" MODULE4_ID = "trend_analysis" MODULE5_ID = "number_generation" class EventType: COMMAND = "command" DATA_RESULT = "data_result" ERROR = "error" # Position matrix configuration FRONT_POSITION_MATRIX = { '01': 'r4c3', '02': 'r3c3', '03': 'r3c4', '04': '极4c4', '05': 'r5c4', '06': 'r5c3', '07': 'r5c2', '08': 'r4c2', '09': 'r3c2', '10': 'r2c2', '11': 'r2c3', '12': 'r2c4', '13': 'r3c5', '14': 'r3c5', '15': 'r4c5', '16': 'r5c5', '17': 'r6c5', '18': 'r6c4', '19': 'r6c3', '20': 'r6c2', '21': 'r6c1', '22': 'r5c1', '23': 'r4c1', '24': 'r3c1', '25': 'r2c1', '26': 'r1c1', '27': 'r1c2', '28': 'r1c3', '29': 'r1c4', '30': 'r1c5', '31': 'r1c6', '32': 'r2c6', '33': 'r3c6', '34': 'r4c6', '35': 'r5c6' } BACK_POSITION_RANGES = { 'rows': ['r2', 'r3', 'r4', 'r5'], 'cols': ['c2', 'c3', 'c4'] } # Configure logging logging.basicConfig( level=logging.WARNING, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) # Global event queues channel_b = queue.Queue() channel_c = queue.Queue() # Initialize global event center event_center = EventCenter() class CorrelationMatrixAnalyzer: def __init__(self, position_matrix: Dict[str, str]): self.position_matrix = position_matrix self.correlation_matrix: Dict[str, Dict[str, float]] = {} self.position_coords = map_positions_to_coords(self.position_matrix) def build_correlation_matrix(self, historical_data: pd.DataFrame): num_keys = list(self.position_coords.keys()) self.correlation_matrix = {n: {m: 0.0 for m in num_keys} for n in num_keys} # Co-occurrence frequency statistics for _, row in historical_data.iterrows(): nums = [f"{n:02d}" for n in row['前区号码']] for i in range(len(nums)): for j in range(i + 1, len(nums)): if nums[i] in self.correlation_matrix and nums[j] in self.correlation_matrix: self.correlation_matrix[nums[i]][nums[j]] += 1 self.correlation_matrix[nums[j]][nums[i]] += 1 # Position correlation enhancement for n1 in num_keys: for n2 in num_keys: if n1 != n2: coord1 = self.position_coords[n1] coord2 = self.position_coords[n2] distance = math.sqrt((coord1[0] - coord2[0]) ** 2 + (coord1[1] - coord2[1]) ** 2) self.correlation_matrix[n1][n2] *= (1 / (1 + distance)) # Normalization max_val = max(max(row.values()) for row in self.correlation_matrix.values()) if max_val > 0: for n1 in num_keys: for n2 in num_keys: self.correlation_matrix[n1][n2] /= max_val def get_correlation(self, num1: int, num2: int) -> float: """Get correlation between two numbers""" n1 = f"{num1:02d}" n2 = f"{num2:02d}" return self.correlation_matrix.get(n1, {}).get(n2, 0.0) class LotteryDataAnalyzer: def __init__(self, historical_data: pd.DataFrame): self.df = historical_data self.prime_numbers = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31} self.front_ranges = [(1, 5), (6, 10), (11, 15), (16, 20), (21, 25), (26, 30), (31, 35)] def analyze_front(self) -> Dict: """Analyze front area numbers""" data = self.df.tail(100) return { 'sum_range': self._calc_sum_range(data), 'prime_ratio': self._calc_prime_ratio(data), 'odd_ratio': self._calc_odd_ratio(data), 'exclude_range': self._find_exclude_range(data), 'consecutive': self._has_consecutive(data), 'hot_cold': self._analyze_hot_cold(data, '前区号码') } def analyze_rear(self) -> Dict: """Analyze rear area numbers""" data = self.df.tail(100) return { 'span': self._calc_span(data), 'hot_cold': self._analyze_hot_cold(data, '后区号码') } @staticmethod def _calc_sum_range(data: pd.DataFrame) -> List[int]: sums = data['前区号码'].apply(sum) avg, std = sums.mean(), sums.std() return [ max(45, int(avg - std)), int(avg - std / 2), int(avg), int(avg + std / 2), min(135, int(avg + std)) ] def _calc_prime_ratio(self, data: pd.DataFrame) -> List[int]: prime_counts = data['前区号码'].apply(lambda x: len(set(x) & self.prime_numbers)) ratio = prime_counts.mean() / 5 return [math.floor(ratio * 5), math.ceil(ratio * 5)] @staticmethod def _calc_odd_ratio(data: pd.DataFrame) -> List[int]: odd_counts = data['前区号码'].apply(lambda x: sum(1 for n in x if n % 2 != 0)) ratio = odd_counts.mean() / 5 return [math.floor(ratio * 5), math.ceil(ratio * 5)] def _find_exclude_range(self, data: pd.DataFrame) -> Tuple[int, int]: range_counts = [0] * len(self.front_ranges) for nums in data['前区号码']: for idx, rng in enumerate(self.front_ranges): if any(rng[0] <= n <= rng[1] for n in nums): range_counts[idx] += 1 return self.front_ranges[range_counts.index(min(range_counts))] @staticmethod def _has_consecutive(data: pd.DataFrame) -> bool: consecutive_counts = data['前区号码'].apply( lambda x: sum(1 for i in range(4) if x[i + 1] - x[i] == 1)) return consecutive_counts.mean() > 0.5 @staticmethod def _analyze_hot_cold(data: pd.DataFrame, area: str) -> Dict[str, List[int]]: num_list = np.concatenate(data[area].values) counts = Counter(num_list) avg = sum(counts.values()) / len(counts) hot = [n for n, c in counts.most_common(8) if c > avg * 1.2] cold = [n for n, c in counts.items() if c < avg * 0.8] if len(cold) < 3: cold = [n for n, c in counts.most_common()[-3:]] return {'hot': hot[:8], 'cold': cold[:3]} @staticmethod def _calc_span(data: pd.DataFrame) -> int: spans = data['后区号码'].apply(lambda x: max(x) - min(x)) return spans.mode()[0] class NumberGenerator: def __init__(self, module_config: Optional[dict] = None): config = module_config or {} self.module_id = config.get('module_id', GlobalConfig.MODULE5_ID) self.labels = config.get('labels', ['number_generation']) self.lock = Lock() self.position_matrix = FRONT_POSITION_MATRIX self.position_coords = map_positions_to_coords(self.position_matrix) self.correlation_matrix: Optional[Dict[str, Dict[str, float]]] = None self._register_event_handlers() def _register_event_handlers(self): event_center.subscribe( event_type=GlobalConfig.EventType.COMMAND, token=self.module_id, callback=self._handle_generation_command ) def build_correlation_matrix(self, historical_data: pd.DataFrame): num_keys = list(self.position_coords.keys()) self.correlation_matrix = {n: {m: 0.0 for m in num_keys} for n in num_keys} for _, row in historical_data.iterrows(): nums = [f"{n:02d}" for n in row['前区号码']] for i in range(len(nums)): for j in range(i + 1, len(nums)): if nums[i] in self.correlation_matrix and nums[j] in self.correlation_matrix: self.correlation_matrix[nums[i]][nums[j]] += 1 self.correlation_matrix[nums[j]][nums[i]] += 1 for n1 in num_keys: for n2 in num_keys: if n1 != n2: coord1 = self.position_coords[n1] coord2 = self.position_coords[n2] distance = math.sqrt((coord1[0] - coord2[0]) ** 2 + (coord1[1] - coord2[1]) ** 2) self.correlation_matrix[n1][n2] *= (1 / (1 + distance)) max_val = max(max(row.values()) for row in self.correlation_matrix.values()) if max_val > 0: for n1 in num_keys: for n2 in num_keys: self.correlation_matrix[n1][n2] /= max_val def get_correlation(self, num1: int, num2: int) -> float: n1 = f"{num1:02d}" n2 = f"{num2:02d}" return self.correlation_matrix.get(n1, {}).get(n2, 0.0) if self.correlation_matrix else 0.0 def _handle_generation_command(self, event: Event): if not self._validate_command(event): return try: with self.lock: generated_numbers = self.generate_numbers(5) self._send_results( target_token=event.token, numbers=generated_numbers, labels=self.labels + event.data.get('labels', []) ) except Exception as e: logging.error(f"Generation failed: {str(e)}") self._send_error(event.token, str(e)) def _validate_command(self, event: Event) -> bool: return (event.token == self.module_id and event.type == GlobalConfig.EventType.COMMAND and event.data.get('action') == 'generate') @staticmethod def generate_numbers(n: int = 5) -> List[Tuple[List[int], List[int]]]: """Generate random lottery numbers""" results = [] for _ in range(n): front_nums = sorted(random.sample(range(1, 36), 5)) rear_nums = sorted(random.sample(range(1, 13), 2)) results.append((front_nums, rear_nums)) return results def _send_results(self, target_token: str, numbers: List[Tuple[List[int], List[int]]], labels: List[str]): result_event = Event( event_id=str(uuid.uuid4()), event_type=GlobalConfig.EventType.DATA_RESULT, source=self.module_id, target=GlobalConfig.MODULE5_ID, data={'numbers': numbers, 'labels': labels}, token=target_token ) event_center.publish(result_event) def _send_error(self, target_token: str, error_msg: str): error_event = Event( event_id=str(uuid.uuid4()), event_type=GlobalConfig.EventType.ERROR, source=self.module_id, target=GlobalConfig.MODULE5_ID, data={'error': error_msg}, token=target_token ) event_center.publish(error_event) class NumberGeneratorCompat: """Compatibility layer for number generation""" _instance = None _lock = threading.Lock() def __new__(cls, *args, **kwargs): if cls._instance is None: with cls._lock: if cls._instance is None: cls._instance = super().__new__(cls) cls._instance._module_config = kwargs.get('module_config', {}) return cls._instance def __init__(self, module_config: Optional[Dict] = None): if hasattr(self, '_generator'): return config = module_config or { 'module_id': GlobalConfig.MODULE5_ID, 'labels': ['compatibility_layer'] } self._generator = NumberGenerator(config) def get_generator(self) -> NumberGenerator: return self._generator @staticmethod def generate(_data: Dict) -> List[Tuple[List[int], List[int]]]: """Generate random numbers (ignore unused parameter)""" instance = NumberGeneratorCompat() return instance._generator.generate_numbers(5) class AdvancedLotteryGenerator: def __init__(self, data_file: str): self.data_file = data_file self.df = self._load_data() self.position_model = FRONT_POSITION_MATRIX compat = NumberGeneratorCompat() self.correlation_analyzer = compat.get_generator() self.correlation_analyzer.build_correlation_matrix(self.df) self.position_validity_cache = self._build_position_cache() self.analyzer = LotteryDataAnalyzer(self.df) self.module_data = { 'historical': self.analyzer.analyze_front(), 'module1': {'hot': [], 'cold': [], 'special': {}}, 'module2': {'hot': [], 'cold': [], 'special': {}}, 'module3': {'hot': [], 'cold': [], 'special': {}} } self._start_event_system() def _load_data(self) -> pd.DataFrame: if not os.path.exists(self.data_file): raise FileNotFoundError(f"Data file not found: {self.data_file}") with open(self.data_file, 'rb') as f: encoding = chardet.detect(f.read())['encoding'] df = pd.read_csv(self.data_file, encoding=encoding) df = df.rename(columns={ '开奖期号': 'issue', '前区1': 'front1', '前区2': 'front2', '前区3': 'front3', '前区4': 'front4', '前区5': 'front5', '后区1': 'rear1', '后区2': 'rear2' }) df['前区号码'] = df[['front1', 'front2', 'front3', 'front4', 'front5']].values.tolist() df['后区号码'] = df[['rear1', 'rear2']].values.tolist() return df.drop_duplicates('issue') def _build_position_cache(self) -> Dict[str, Dict[int, bool]]: cache = {'front': {}, 'rear': {}} for num_val in range(1, 36): cache['front'][num_val] = f"{num_val:02d}" in self.position_model rear_positions = [] for r in BACK_POSITION_RANGES['rows']: for c in BACK_POSITION_RANGES['cols']: rear_positions.append((int(r[1:]), int(c[1:]))) for num_val in range(1, 13): cache['rear'][num_val] = num_val % len(rear_positions) in [c for _, c in rear_positions] return cache def _start_event_system(self): def data_producer(): while True: time.sleep(3) module = random.choice(['module1', 'module2', 'module3']) hot = random.sample(range(1, 36), random.randint(3, 6)) cold = random.sample(range(1, 36), random.randint(2, 4)) channel_b.put({ 'module': module, 'hot': hot, 'cold': cold, 'special': { 'sum_range': [random.randint(80, 120)], 'prime_ratio': [random.randint(1, 3), random.randint(2, 4)], 'odd_ratio': [random.randint(1, 3), random.randint(2, 4)] } }) def event_listener(): while True: try: data = channel_b.get() module = data['module'] if module in self.module_data: self.module_data[module]['hot'] = list(set( self.module_data[module]['hot'] + data['hot'])) self.module_data[module]['cold'] = list(set( self.module_data[module]['cold'] + data['cold'])) for k, v in data['special'].items(): if k in self.module_data[module]['special']: if isinstance(v, list): self.module_data[module]['special'][k] = v except Exception as e: logging.error(f"Event processing error: {e}") threading.Thread(target=data_producer, daemon=True).start() threading.Thread(target=event_listener, daemon=True).start() def generate_numbers(self, n: int = 5) -> List[Tuple[List[int], List[int]]]: try: combined_front = self._combine_front_data() combined_rear = self.analyzer.analyze_rear() candidates = [] for target_sum in combined_front['sum_range'][:5]: for _ in range(n * 2): front_nums = self._generate_front(target_sum, combined_front) rear_nums = self._generate_rear(combined_rear) if len(front_nums) == 5 and len(rear_nums) == 2: candidates.append((front_nums, rear_nums)) valid = [c for c in candidates if self._validate_combination(c, combined_front, combined_rear)] results = self._score_combinations(valid, combined_front)[:n] if not results: results = self._generate_backup(n) return results except Exception as e: logging.error(f"Number generation error: {e}") return self._generate_backup(n) def _combine_front_data(self) -> Dict: combined = { 'hot': [], 'cold': [], 'sum_range': [], 'prime_ratio': [1, 3], 'odd_ratio': [1, 4], 'exclude_range': (0, 0), 'consecutive': False } for module in self.module_data.values(): combined['hot'].extend(module.get('hot', [])) combined['cold'].extend(module.get('cold', [])) if 'sum_range' in module.get('special', {}): combined['sum_range'].extend(module['special']['sum_range']) if 'prime_ratio' in module.get('special', {}): combined['prime_ratio'] = [ max(combined['prime_ratio'][0], module['special']['prime_ratio'][0]), min(combined['prime_ratio'][1], module['special']['prime_ratio'][1]) ] if 'odd_ratio' in module.get('special', {}): combined['odd_ratio'] = [ max(combined['odd_ratio'][0], module['special']['odd_ratio'][0]), min(combined['odd_ratio'][1], module['special']['odd_ratio'][1]) ] if 'exclude_range' in module.get('special', {}): combined['exclude_range'] = module['special']['exclude_range'] if 'consecutive' in module.get('special', {}): combined['consecutive'] |= module['special']['consecutive'] combined['hot'] = list(set(combined['hot'])) combined['cold'] = list(set(combined['cold'])) if not combined['sum_range']: combined['sum_range'] = self.module_data['historical']['sum_range'] return combined def _generate_front(self, target_sum: int, analysis: Dict) -> List[int]: valid_nums = [n for n in range(1, 36) if self.position_validity_cache['front'].get(n, False)] hot_nums = [n for n in analysis['hot'] if n in valid_nums] cold_nums = [n for n in analysis['cold'] if n in valid_nums] for _ in range(100): selected = [] if hot_nums: selected.extend(random.sample(hot_nums, min(3, len(hot_nums)))) if cold_nums and len(selected) < 4: selected.extend(random.sample(cold_nums, min(1, len(cold_nums)))) remaining = 5 - len(selected) candidates = [n for n in valid_nums if n not in selected] if remaining > 0 and candidates: weights = [self._calc_number_weight(n, selected, analysis) for n in candidates] selected.extend(random.choices(candidates, weights=weights, k=remaining)) selected = sorted(list(set(selected))[:5]) if len(selected) == 5 and abs(sum(selected) - target_sum) <= 5: return selected return random.sample(valid_nums, 5) def _calc_number_weight(self, num: int, selected: List[int], analysis: Dict) -> float: corr_weight = sum(self.correlation_analyzer.get_correlation(num, s) for s in selected) if selected else 1 hot_weight = 2 if num in analysis['hot'] else 0.5 if num in analysis['cold'] else 1 pos_key = f"{num:02d}" pos_str = self.position_model.get(pos_key, 'r0c0') row = int(pos_str[1:pos_str.find('c')]) col = int(pos_str[pos_str.find('c') + 1:]) pos_weight = 1 + (1 / (1 + row * col)) return corr_weight * hot_weight * pos_weight def _generate_rear(self, analysis: Dict) -> List[int]: valid_nums = [n for n in range(1, 13) if self.position_validity_cache['rear'].get(n, False)] hot_nums = [n for n in analysis['hot_cold']['hot'] if n in valid_nums] cold_nums = [n for n in analysis['hot_cold']['cold'] if n in valid_nums] selected = random.sample(hot_nums, min(2, len(hot_nums))) if hot_nums else [] if len(selected) < 2 and cold_nums: select_count = min(2 - len(selected), len(cold_nums)) selected.extend(random.sample(cold_nums, select_count)) if len(selected) < 2: remaining = [n for n in valid_nums if n not in selected] selected.extend(random.sample(remaining, 2 - len(selected))) return sorted(selected) def _validate_combination(self, combination: Tuple[List[int], List[int]], front_analysis: Dict, rear_analysis: Dict) -> bool: front_nums, rear_nums = combination current_sum = sum(front_nums) if not any(abs(current_sum - s) <= 5 for s in front_analysis['sum_range']): return False prime_count = len([n for n in front_nums if n in self.analyzer.prime_numbers]) if not (front_analysis['prime_ratio'][0] <= prime_count <= front_analysis['prime_ratio'][1]): return False odd_count = sum(1 for n in front_nums if n % 2 != 0) if not (front_analysis['odd_ratio'][0] <= odd_count <= front_analysis['odd_ratio'][1]): return False has_consecutive = any(front_nums[i + 1] - front_nums[i] == 1 for i in range(4)) if front_analysis['consecutive'] != has_consecutive: return False rear_span = max(rear_nums) - min(rear_nums) if rear_span not in [rear_analysis['span'] - 1, rear_analysis['span'], rear_analysis['span'] + 1]: return False return True def _score_combinations(self, combinations: List[Tuple[List[int], List[int]]], front_analysis: Dict) -> List[Tuple[float, Tuple[List[int], List[int]]]]: scored = [] for front_nums, rear_nums in combinations: score = 0 current_sum = sum(front_nums) closest_sum = min(front_analysis['sum_range'], key=lambda x: abs(x - current_sum)) score += 10 - abs(current_sum - closest_sum) corr_score = 0 for i in range(len(front_nums)): for j in range(i + 1, len(front_nums)): corr_score += self.correlation_analyzer.get_correlation(front_nums[i], front_nums[j]) score += corr_score / 10 positions = [self.position_model.get(f"{n:02d}", 'r0c0') for n in front_nums] rows = [int(p[1:p.find('c')]) for p in positions] cols = [int(p[p.find('c') + 1:]) for p in positions] row_std = np.std(rows) col_std = np.std(cols) score += 5 / (1 + row_std + col_std) scored.append((score, (front_nums, rear_nums))) return sorted(scored, reverse=True, key=lambda x: x[0]) def _generate_backup(self, n: int) -> List[Tuple[List[int], List[int]]]: valid_front = [n for n in range(1, 36) if self.position_validity_cache['front'].get(n, False)] valid_rear = [n for n in range(1, 13) if self.position_validity_cache['rear'].get(n, False)] results = [] for _ in range(n): front_nums = sorted(random.sample(valid_front, 5)) rear_nums = sorted(random.sample(valid_rear, 2)) results.append((front_nums, rear_nums)) return results if __name__ == "__main__": generator = AdvancedLotteryGenerator('historical_data.csv') number_list = generator.generate_numbers(5) for idx, (front, rear) in enumerate(number_list, 1): print(f"Group {idx}: Front {front} Rear {rear} (Sum:{sum(front)})") # Ensure newline at end of file print()
08-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值