iOS开发必备指南合集之游戏接入GameCenter 指南
原地址:http://bbs.9ria.com/thread-248408-1-1.html
iTunes Connect 设置
首先,申请一个应用程序,不必提交.目地是为了得到Bundle ID.
然后设置一下工程中Info.plist的Bundle identifier使之与iTunes Connect中的Bundle ID相同,否则当你尝试登录GameCenter的时候,会提示一个不支持GameCenter的错误.
申请完毕,打开你刚申请的application,点击Manage Game Center选项.
进入后点击Enable Game Center使你的Game Center生效.
接下来就可以设置自己的Leaderboard和Achievements.
2. Leaderboard设置
Leaderboard纵观图如下所示.
1.sort Order: Leaderboard中的内容是以升序还是降序排列.
2.Score Format Type:分数的类型.
3.*Categorieseaderboard的一个分数榜,这个可以创建多个,比如游戏可以分为Easy,Normal,Hard三个难度,每个难度一个榜.
*设置完成后保存,完成了一个 Leaderboard的设置.我们可以根据需要添加多个 leaderboard.
4.**Score Format Location: leaderboard支持的语言.
**可以支持多种语言,每支持一种语言,需要完成一个上述操作.
这个时候右下角会出现save change按钮,点击完成leaderboard的设置.
你可以根据需要随时更改你的leaderboard,操作与上述内容类似.
3. Achievements设置
Achievements界面内容比较少,点击左上角的Add New Achievement,打开如下图所示的Achievements创建界面.
Hidden:表示该成就为解锁前玩家是否可见.
Achievement ID:程序通过这个属性来识别成就.
*Achievement Localization:该成就支持的语言.
*Achievement Localization设置如下图所示.
*其中,成就的Image必须是512X512,72DPI的.
一切设置完成后,点击save change按钮即完成一个成就的设置.
4.总体功能
在使用各个功能前,你需要了解一下块函数。传送门:https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html
4.1 对Game Center支持判断
- - (BOOL) isGameCenterAvailable
- {
- Class gcClass = (NSClassFromString(@"GKLocalPlayer"));
- NSString *reqSysVer = @"4.1";
- NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
- BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending);
- return (gcClass && osVersionSupported);
- }复制代码
复制代码
4.2用户登录
- - (void) authenticateLocalPlayer
- {
- [[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error){
- if (error == nil) {
- //成功处理
- NSLog(@"成功");
- NSLog(@"1--alias--.%@",[GKLocalPlayer localPlayer].alias);
- NSLog(@"2--authenticated--.%d",[GKLocalPlayer localPlayer].authenticated);
- NSLog(@"3--isFriend--.%d",[GKLocalPlayer localPlayer].isFriend);
- NSLog(@"4--playerID--.%@",[GKLocalPlayer localPlayer].playerID);
- NSLog(@"5--underage--.%d",[GKLocalPlayer localPlayer].underage);
- }else {
- //错误处理
- NSLog(@"失败 %@",error);
- }
- }];
- }复制代码
复制代码
对于开发者来说,Game Center必须经过测试才能上线,没有上线的程序在测试环境中登录时会出现sandbox提示.如图.
4.3用户变更检测
由于4.0以后系统支持多任务,玩家的机器有可能被不同的玩家接触,导致Game Center上的用户发生变化,当发生变化的时候,程序必须在游戏中通知玩家.
- - (void) registerForAuthenticationNotification
- {
- NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
- [nc addObserver:self
- selector:@selector(authenticationChanged)
- name:GKPlayerAuthenticationDidChangeNotificationName
- object:nil];
- }
- - (void) authenticationChanged
- {
- if ([GKLocalPlayer localPlayer].isAuthenticated)
- {
- ;// Insert code here to handle a successful authentication.
- }
- else
- {
- ;// Insert code here to clean up any outstanding Game Center-related classes.
- }
- }复制代码
复制代码
5.对Leaderboard进行操作
5.1上传一个分数
- - (void) reportScore: (int64_t) score forCategory: (NSString*) category
- {
- GKScore *scoreReporter = [[[GKScore alloc] initWithCategory:category] autorelease];
- scoreReporter.value = score;
- [scoreReporter reportScoreWithCompletionHandler:^(NSError *error) {
- if (error != nil)
- {
- // handle the reporting error
- NSLog(@"上传分数出错.");
- //If your application receives a network error, you should not discard the score.
- //Instead, store the score object and attempt to report the player’s process at
- //a later time.
- }else {
- NSLog(@"上传分数成功");
- }
- }];
- }复制代码
复制代码
当上传分数出错的时候,要将上传的分数存储起来,比如将SKScore存入一个NSArray中.等可以上传的时候再次尝试.
5.2下载一个分数
- //GKScore objects provide the data your application needs to create a custom view.
- //Your application can use the score object’s playerID to load the player’s alias.
- //The value property holds the actual value you reported to Game Center. the formattedValue
- //property provides a string with the score value formatted according to the parameters
- //you provided in iTunes Connect.
- - (void) retrieveTopTenScores
- {
- GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
- if (leaderboardRequest != nil)
- {
- leaderboardRequest.playerScope = GKLeaderboardPlayerScopeGlobal;
- leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;
- leaderboardRequest.range = NSMakeRange(1,10);
- leaderboardRequest.category = @"TS_LB";
- [leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
- if (error != nil){
- // handle the error.
- NSLog(@"下载失败");
- }
- if (scores != nil){
- // process the score information.
- NSLog(@"下载成功....");
- NSArray *tempScore = [NSArray arrayWithArray:leaderboardRequest.scores];
- for (GKScore *obj in tempScore) {
- NSLog(@" playerID : %@",obj.playerID);
- NSLog(@" category : %@",obj.category);
- NSLog(@" date : %@",obj.date);
- NSLog(@" formattedValue : %@",obj.formattedValue);
- NSLog(@" value : %d",obj.value);
- NSLog(@" rank : %d",obj.rank);
- NSLog(@"**************************************");
- }
- }
- }];
- }
- }复制代码
复制代码
说明:
1) playerScope:表示检索玩家分数范围.
2) timeScope:表示某一段时间内的分数
3) range:表示分数排名的范围
4) category:表示你的Leaderboard的ID.
5.3玩家信息交互
Game Center最重要的一个功能就是玩家交互.所以,必须检索已经登录玩家的好友信息.根据自己的需要做出设置,比如,可以与好友比较分数,或者好友排行榜等.
//检索已登录用户好友列表
- - (void) retrieveFriends
- {
- GKLocalPlayer *lp = [GKLocalPlayer localPlayer];
- if (lp.authenticated)
- {
- [lp loadFriendsWithCompletionHandler:^(NSArray *friends, NSError *error) {
- if (error == nil)
- {
- [self loadPlayerData:friends];
- }
- else
- {
- ;// report an error to the user.
- }
- }];
- }
- }复制代码
复制代码
上面的friends得到的只是一个身份列表,里面存储的是NSString,想要转换成好友ID,必须调用- (void) loadPlayerData: (NSArray *) identifiers方法,该方法得到的array里面存储的才是GKPlayer对象.如下
- /*
- Whether you received player identifiers by loading the identifiers for the local player’s
- friends, or from another Game Center class, you must retrieve the details about that player
- from Game Center.
- */
- - (void) loadPlayerData: (NSArray *) identifiers
- {
- [GKPlayer loadPlayersForIdentifiers:identifiers withCompletionHandler:^(NSArray *players, NSError *error) {
- if (error != nil)
- {
- // Handle the error.
- }
- if (players != nil)
- {
- NSLog(@"得到好友的alias成功");
- GKPlayer *friend1 = [players objectAtIndex:0];
- NSLog(@"friedns---alias---%@",friend1.alias);
- NSLog(@"friedns---isFriend---%d",friend1.isFriend);
- NSLog(@"friedns---playerID---%@",friend1.playerID);
- }
- }];
- }复制代码
复制代码
至此,leaderboard功能介绍完毕
6.对Achievement进行操作
这一部分内容比较多,而且有的地方有点重复的感觉.
6.1汇报一个成就的进度
对于一个玩家可见的成就,你需要尽可能的报告给玩家解锁的进度;对于一个一部完成的成就,则不需要,当玩家的进度达到100%的时候,会自动解锁该成就.
- - (void) reportAchievementIdentifier: (NSString*) identifier percentComplete: (float) percent
- {
- GKAchievement *achievement = [[[GKAchievement alloc] initWithIdentifier: identifier] autorelease];
- if (achievement)
- {
- achievement.percentComplete = percent;
- [achievement reportAchievementWithCompletionHandler:^(NSError *error)
- {
- if (error != nil)
- {
- //The proper way for your application to handle network errors is retain
- //the achievement object (possibly adding it to an array). Then, periodically
- //attempt to report the progress until it is successfully reported.
- //The GKAchievement class supports the NSCoding protocol to allow your
- //application to archive an achie
- NSLog(@"报告成就进度失败 ,错误信息为: \n %@",error);
- }else {
- //对用户提示,已经完成XX%进度
- NSLog(@"报告成就进度---->成功!");
- NSLog(@" completed:%d",achievement.completed);
- NSLog(@" hidden:%d",achievement.hidden);
- NSLog(@" lastReportedDate:%@",achievement.lastReportedDate);
- NSLog(@" percentComplete:%f",achievement.percentComplete);
- NSLog(@" identifier:%@",achievement.identifier);
- }
- }];
- }
- }复制代码
复制代码
其中该函数的参数中identifier是你成就的ID, percent是该成就完成的百分比
6.2读取一个成就
方法一:得到所有的成就
- - (void) loadAchievements
- {
- NSMutableDictionary *achievementDictionary = [[NSMutableDictionary alloc] init];
- [GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements,NSError *error)
- {
- if (error == nil) {
- NSArray *tempArray = [NSArray arrayWithArray:achievements];
- for (GKAchievement *tempAchievement in tempArray) {
- [achievementDictionary setObject:tempAchievement forKey:tempAchievement.identifier];
- NSLog(@" completed:%d",tempAchievement.completed);
- NSLog(@" hidden:%d",tempAchievement.hidden);
- NSLog(@" lastReportedDate:%@",tempAchievement.lastReportedDate);
- NSLog(@" percentComplete:%f",tempAchievement.percentComplete);
- NSLog(@" identifier:%@",tempAchievement.identifier);
- }
- }
- }];
- }复制代码
复制代码
函数中NSArray返回的是你的所有成就ID.
方法二:根据ID获取成就
- - (GKAchievement*) getAchievementForIdentifier: (NSString*) identifier
- {
- NSMutableDictionary *achievementDictionary = [[NSMutableDictionary alloc] init];
- GKAchievement *achievement = [achievementDictionary objectForKey:identifier];
- if (achievement == nil)
- {
- achievement = [[[GKAchievement alloc] initWithIdentifier:identifier] autorelease];
- [achievementDictionary setObject:achievement forKey:achievement.identifier];
- }
- return [[achievement retain] autorelease];
- }复制代码
复制代码
6.3获取成就描述和图片
在自定义界面中,玩家需要一个成就描述,以及该成就的图片,Game Center提供了该功能.当然,你也可以自己在程序中完成,毕竟玩家不可能时刻处于在线状态.
- - (NSArray*)retrieveAchievmentMetadata
- {
- //读取成就的描述
- [GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:
- ^(NSArray *descriptions, NSError *error) {
- if (error != nil)
- {
- // process the errors
- NSLog(@"读取成就说明出错");
- }
- if (descriptions != nil)
- {
- // use the achievement descriptions.
- for (GKAchievementDescription *achDescription in descriptions) {
- NSLog(@"1..identifier..%@",achDescription.identifier);
- NSLog(@"2..achievedDescription..%@",achDescription.achievedDescription);
- NSLog(@"3..title..%@",achDescription.title);
- NSLog(@"4..unachievedDescription..%@",achDescription.unachievedDescription);
- NSLog(@"5............%@",achDescription.image);
- //获取成就图片,如果成就未解锁,返回一个大文号
- /*
- [achDescription loadImageWithCompletionHandler:^(UIImage *image, NSError *error) {
- if (error == nil)
- {
- // use the loaded image. The image property is also populated with the same image.
- NSLog(@"成功取得成就的图片");
- UIImage *aImage = image;
- UIImageView *aView = [[UIImageView alloc] initWithImage:aImage];
- aView.frame = CGRectMake(50, 50, 200, 200);
- aView.backgroundColor = [UIColor clearColor];
- [[[CCDirector sharedDirector] openGLView] addSubview:aView];
- }else {
- NSLog(@"获得成就图片失败");
- }
- }];
- */
- }
- }
- }];
- return nil;
- }复制代码
复制代码
如果你不主动使用注释中的方法,那么你得到的description中不会有图片,这样可以减少网络的使用,尽量少下载东西.当使用注释中的代码时,如果成就已经解锁,则返回该成就的图标,如果没有解锁,则返回一个大问号,至于未解锁图标是否可以自定义,我找寻的结果好像是不可以.GameCenter 成就提示更新: GameCenter中成就提示需要开发者自定义,即使官方Demo的例子程序中也没有给与提示框(横幅样式)通知用户的官方代码,所以这里Himi介绍如何模仿官方的成就提示: 1. iOS5以及更高SDK中,apple已经提供官方的成就提示:方法很简单,代码如下:
- - (void)sendAchievement:(GKAchievement *)achievement {
- achievement.percentComplete = 100.0; //Indicates the achievement is done
- achievement.showsCompletionBanner = YES; //Indicate that a banner should be shown
- [achievement reportAchievementWithCompletionHandler:
- ^(NSError *error) {
- dispatch_async(dispatch_get_main_queue(), ^(void)
- {
- if (error == NULL) {
- NSLog(@"Successfully sent archievement!");
- } else {
- NSLog(@"Achievement failed to send... will try again \
- later. Reason: %@", error.localizedDescription);
- }
- });
- }];
- }复制代码
复制代码
将“showsCompletionBanner”属性设置成YES,提交给苹果。新iOS属性“showsCompletionBanner”,其默认设置是NO,但若将其调整成YES,屏幕就呈现包含成就标题和描述的漂亮横幅;
2.如果低于5.0的SDK设备中是没有 “showsCompletionBanner”属性的,所以需要我们自定义提示样式,当然这里Himi也分享一下如何模仿官方横幅提示样式的方法和代码: 首先,我借鉴Type One Error所展示的优秀代码,从https://github.com/typeoneerror/GKAchievementNotification中抓取一些代码植入自己的项目。我们将采用GKAchievementNotification和GKAchievementHandler类,同时进行相应更新和修改。首先,若你在游戏中运用ARC,快速扫描代码,移除那些发行、保留和自动发行代码属性。若你不想进行扫描,试着将文件放入项目及修复不符编译程序的内容,然后再创建内容。Type One Error类将展示类似于iOS 5所呈现的通知内容,但代码需获悉成就标题和描述是什么。为实现这点,你需要嵌入“showsCompletionBanner”目标。GKAchievementDescription目标的优点是它们已根据用户语言设定进行本土化,因此采用此方式不存在任何本土化问题。其弊端在于你无法只加载一个成就描述,你需要加载所有内容。我认为进行此操作的最佳时间是用户已在应用上认证Game Center,此时你需要通过异步调用获得这些消息。值得欣慰的是,苹果在此设有API调用,我将此放置在用户认证访问的CompletionHandler中。若你采用Ray Wenderlich网站的代码,那么你就既能够运用此方法,又拥有新方法。将NSMutableDictionary * self.achievementsDescDictionary添加至所有处理游戏Game Center代码的类(游戏邦注:它会在随后的体验中存储成就数据)。
- - (void)authenticateLocalUser {
- if (!gameCenterAvailable) return;
- NSLog(@”Authenticating local user…”);
- if ([GKLocalPlayer localPlayer].authenticated == NO) {
- [[GKLocalPlayer localPlayer]
- authenticateWithCompletionHandler:^(NSError *error) {
- if([GKLocalPlayer localPlayer].isAuthenticated){
- [self retrieveAchievmentMetadata]; //Here is the new code
- }
- }];
- }
- }
- //Here is the new method.
- - (void) retrieveAchievmentMetadata
- {
- self.achievementsDescDictionary = [[NSMutableDictionary alloc] initWithCapacity:2];
- [GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:
- ^(NSArray *descriptions, NSError *error) {
- if (error != nil) {
- NSLog(@"Error %@", error);
- } else {
- if (descriptions != nil){
- for (GKAchievementDescription* a in descriptions) {
- [achievementsDescDictionary setObject: a forKey: a.identifier];
- }
- }
- }
- }];
- }
- “retrieveAchievmentMetadata”方法会初始化所有信息库,然后调用游戏所有成就描述,进行循环,将它们添加至信息库。这属于异步调用,所以不应减缓游戏或项目的启动。
- 现在我们握有各成就的标题和描述,因此能够修改原始代码创造iOS 4/5的善意通知,其将通过Type One Error代码连续展示所有成就。
- - (void)reportAchievement:(NSString *)identifier
- percentComplete:(double)percentComplete {
- GKAchievement* achievement = [[GKAchievement alloc]
- initWithIdentifier:identifier];
- achievement.percentComplete = percentComplete;
- if (percentComplete == 100.0) {
- //Show banners manually
- GKAchievementDescription *desc = [achievementsDescDictionary objectForKey:identifier]; //Update pull achievement description for dictionary
- [[GKAchievementHandler defaultHandler] notifyAchievement:desc]; //Display to user
- }
- [achievementsToReport addObject:achievement]; //Queue up the achievement to be sent
- [self save];
- if (!gameCenterAvailable || !userAuthenticated) return;
- [self sendAchievement:achievement]; //Try to send achievement
- }
- - (void)sendAchievement:(GKAchievement *)achievement {
- [achievement reportAchievementWithCompletionHandler:
- ^(NSError *error) {
- dispatch_async(dispatch_get_main_queue(), ^(void)
- {
- if (error == NULL) {
- NSLog(@"Successfully sent archievement!");
- [achievementsToReport removeObject:achievement]; //Remove Achievement from queue.
- } else {
- NSLog(@”Achievement failed to send… will try again \
- later. Reason: %@”, error.localizedDescription);
- }
- });
- }];
- }复制代码
复制代码
如果你想让成就中显示为你在itunes connect中设置成就的自定义图片,首先将通知部分代码修改成如下代码:
- if (percentComplete == 100.0) {
- //Show banners manually
- GKAchievementDescription *desc = [achievementsDescDictionary objectForKey:identifier];
- [desc loadImageWithCompletionHandler:^(UIImage *image, NSError *error) {
- if (error == nil)
- {
- [[GKAchievementHandler defaultHandler] setImage:desc.image]; //If image found, updates the image to the achievement image.
- }
- [[GKAchievementHandler defaultHandler] notifyAchievement:desc];
- }];
- }复制代码
复制代码
使用以上方式默认为横屏显示成就通知,如果想换成竖屏提示,那么这里Himi给出参考代码:在“GKAchievementHandler”类中找到“notifyAchievement”,更新为:
- - (void)notifyAchievement:(GKAchievementDescription *)achievement
- {
- GKAchievementNotification *notification = [[GKAchievementNotification alloc] initWithAchievementDescription:achievement];
- notification.frame = kGKAchievementFrameStart;
- notification.handlerDelegate = self;
- //Adjusting rotation.
- if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft) {
- notification.transform = CGAffineTransformRotate(notification.transform, degreesToRadian(-90));
- } else {
- notification.transform = CGAffineTransformRotate(notification.transform, degreesToRadian(90));
- }
- [_queue addObject:notification];
- if ([_queue count] == 1)
- {
- [self displayNotification:notification];
- }
- }复制代码
复制代码
iOS开发必备指南合集之游戏接入GameCenter 指南的更多相关文章
- 【iOS开发必备指南合集】申请企业级IDP、真机调试、游戏接入GameCenter 指南(实现仿官方的成就提示)、游戏接入OpenFeint指南;
本站文章均为李华明Himi原创,转载务必在明显处注明:(作者新浪微博:@李华明Himi) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/iphone-c ...
- iOS开发必备HUD(透明指示层)
iOS开发必备HUD(透明指示层) 字数421 阅读2123 评论1 喜欢51 1.MBProgressHUD GitHub地址:https://github.com/jdg/MBProgressHU ...
- Web 前端从入门菜鸟到实践老司机所需要的资料与指南合集
http://web.jobbole.com/89188/ 2016 – 对于未来五年内Web发展的7个预测 2015 – 我的前端之路:从命令式到响应式,以及组件化与工程化的变革 怎么成为一名优秀的 ...
- 七款Debug工具推荐:iOS开发必备的调试利器
历时数周或数月开发出来了应用或游戏.可为什么体验不流畅?怎么能查出当中的纰漏?这些须要调试诊断工具从旁协助.调试是开发过程中不可缺少的重要一环.本文会列举几个比較有效的调试诊断工具,能够帮助你寻根究底 ...
- ios开发必备第三方库
引言 作为iOS开发人员,在开发App的过程中怎么会不使用第三方库呢?相信没有App是不使用第三方库的! 网络库 网络库,这是开发必备,除非你的App玩单机.现在特别火也特别好用的网络库就数AFNet ...
- RestKit:iOS开发必备,告别众多无聊代码
http://www.csdn.net/article/2014-04-15/2819312-RestKit-frameworkRestKit是一款专为iOS设计的Objective-C框架,旨在与R ...
- 第三届移动互联网测试开发大会 PPT合集下载
PPT下载地址 http://www.51test.space/archives/2887 大会介绍 Mobile Testing Summit China(中国移动互联网测试开发大会)是一个以移动测 ...
- ios开发经典语录锦集
原文链接: iPhone开发经典语录集锦 前言:iPhone是个极具艺术性的平台,相信大家在开发过程中一定有很多感触,希望能写出来一起交流,所以开了这个帖子,以后还会维护. 如果大家和我一样有感触的话 ...
- iOS苹果官方Demo合集
Mirror of Apple’s iOS samples This repository mirrors Apple’s iOS samples. Name Topic Framework Desc ...
随机推荐
- PHP超全局变量数组
以下8个变量都是数组变量,又称为“预定义变量” 1.$_GET : 把数据通过地址栏传递到服务器,这是方式必须是$_GET方式传递: 2.$_POST : 通过表单发送的数据必须是POST方式: 3. ...
- 《深入浅出Nodejs》笔记——模块机制(1)
前言 这是我读<深入浅出Nodejs>的笔记,真是希望我的机械键盘快点到啊,累死我了. CommonJS规范 主要分为模块引用.模块定义.模块标识三个部分. 模块引用 上下文提供requi ...
- 判断数独是否合法(LintCode)
判断数独是否合法 请判定一个数独是否有效. 该数独可能只填充了部分数字,其中缺少的数字用. 表示. 样例 下列就是一个合法数独的样例. 注意 一个合法的数独(仅部分填充)并不一定是可解的.我们仅需使填 ...
- 洛谷——P1862 输油管道问题
P1862 输油管道问题 题目背景 听说最近石油危机 所以想到了这题 题目描述 某石油公司计划建造一条由东向西的主要输油管道.该管道要穿过一个有n口油井的油田.从每口油井都要有一条输油管道沿最短路径( ...
- Codeforces Round #165 (Div. 1) Greenhouse Effect(DP)
Greenhouse Effect time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...
- 2017腾讯OMG实习生面试总结
2017腾讯OMG实习生面试总结 一面 一面有两个面试官,轮着来的,一共是一个半小时,中间等了10分钟左右.结合简历问了问项目,也考察了基础,手写了两道简单的算法题.问题包括: 第一个面试官 1.自我 ...
- 分布式框架Dubbo配置和实例
准备工作: 1.ZooKeeper:需要去Apache Zookeeper官网下载Zookeeper.tar.gz包,Dubbo是依赖于Zookeeper的 2.Maven:需要去Apache Mav ...
- [NOI 2011][BZOJ 2434] 阿狸的打字机
传送门 AC自动机 + 树状数组 建成AC自动机后,设end[i]为第i个串的末尾在Trie树上的节点. 可以发现,对于一个询问(x,y),ans等于Trie树上root到end[y]这条链上fail ...
- [Arc062] Painting Graphs with AtCoDeer
[Arc062] Painting Graphs with AtCoDeer Description 给定一张N点M边的无向图,每条边要染一个编号在1到K的颜色.你可以对一张染色了的图进行若干次操作, ...
- Android Studio自动化快速实现Parcelable接口序列化
1.在线安装 然后打开File -> Settings -> Pugins -> Browse Repositories 如下,输入android parcelable code g ...