<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>NekoMio&apos;s Blog</title><description>想变成一只猫~</description><link>https://www.nekomio.com/</link><language>zh_CN</language><item><title>将 Hexo 部署到 Cloudflare Workers</title><link>https://www.nekomio.com/posts/156/</link><guid isPermaLink="true">https://www.nekomio.com/posts/156/</guid><pubDate>Thu, 17 Dec 2020 20:01:47 GMT</pubDate><content:encoded>&lt;h3&gt;0. 起因&lt;/h3&gt;
&lt;p&gt;最近得知 Cloudflare Workers KV 有免费额度了，看起来可以搞一些有意思的东西，因为我自己 Blog 服务器在国内，所以想要通过分流的方法使国外直接访问 Cloudflare 以获得更好的体验。&lt;/p&gt;
&lt;h3&gt;1. 准备工作&lt;/h3&gt;
&lt;p&gt;想要把 Hexo Blog 部署到 Cloudflare Workers，当然要有一个 Hexo 的 Blog 了。
同时也需要一个 Cloudflare 的账号~&lt;/p&gt;
&lt;h3&gt;2. 申请一个API key&lt;/h3&gt;
&lt;p&gt;登录 Cloudflare，在 &lt;a href=&quot;https://dash.cloudflare.com/profile/api-tokens&quot;&gt;个人资料-API令牌&lt;/a&gt; 中申请一个API令牌
使用自带的 Cloudflare Workers 模板即可
&lt;img src=&quot;https://file.nekomio.com/picgo/1649775724987-156-2.webp&quot; alt=&quot;&quot; /&gt;
&lt;strong&gt;记住&lt;/strong&gt;你的Key，一会儿会用到。&lt;/p&gt;
&lt;h3&gt;3. 本地安装 Wrangler CLI 进行首次部署&lt;/h3&gt;
&lt;h5&gt;安装 wrangler&lt;/h5&gt;
&lt;p&gt;既然有 Hexo，那必然会有 Nodejs 环境，那么，通过 npm 或者 yarn 安装 wrangler~&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm i @cloudflare/wrangler -g
# yarn global add @cloudflare/wrangler
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;初始化项目&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;进入你的 Hexo 根目录&lt;/strong&gt;进行初始化&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wrangler init --site my-static-site # 最后的名字可以改成自己喜欢的名字~
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;初始化之后，大概就可以看见目录中多出来的&lt;code&gt;wrangler.toml&lt;/code&gt;文件和&lt;code&gt;workers-site&lt;/code&gt;目录了。&lt;/p&gt;
&lt;h5&gt;修改配置&lt;/h5&gt;
&lt;p&gt;我们需要修改 wrangler.toml 来配置一下我们的项目&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[site]
bucket = &quot;./public&quot;
entry-point = &quot;workers-site&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最重要的是这两行，我们需要修改 &lt;code&gt;bucket&lt;/code&gt; 的值为我们需要部署的目录，对于 Hexo 就是 &lt;code&gt;./public&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;同时还需要修改上面的个人信息&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;account_id = &quot;&quot;
workers_dev = true
route = &quot;www.nekomio.com/*&quot;
zone_id = &quot;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;account_id&lt;/code&gt; 大概登录就能看见，如果你没有绑定自己的域名可以暂时不管 &lt;code&gt;route&lt;/code&gt; 和 &lt;code&gt;zone_id&lt;/code&gt;&lt;/p&gt;
&lt;h5&gt;部署&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;这时候需要运行&lt;/strong&gt; &lt;code&gt;wrangler config&lt;/code&gt;, 并输入&lt;a href=&quot;#2dot-%E7%94%B3%E8%AF%B7%E4%B8%80%E4%B8%AAapi-key&quot;&gt;之前&lt;/a&gt;我们得到的 &lt;code&gt;API Token&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;可以通过 &lt;code&gt;preview&lt;/code&gt; 进行预览。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wrangler preview --watch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过 &lt;code&gt;publish&lt;/code&gt; 进行部署&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wrangler publish
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时，我们以及可以打开Cloudflare上我们的网站了。&lt;/p&gt;
&lt;h3&gt;4. 自定义 Router&lt;/h3&gt;
&lt;p&gt;我这里使用了 Sukka 给出的一个配置文件，主要是将以 index.html 结尾的请求 301 跳转到不包含 index.html 的 URL，加长了 css 的 cache 时间。
这里也放出来进行参考&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { getAssetFromKV, mapRequestToAsset } from &apos;@cloudflare/kv-asset-handler&apos;

addEventListener(&apos;fetch&apos;, event =&amp;gt; {
  try {
    event.respondWith(handleEvent(event))
  } catch (e) {
    if (DEBUG) {
      return event.respondWith(
        new Response(e.message || e.toString(), {
          status: 500,
        }),
      )
    }
    event.respondWith(new Response(&apos;Internal Error&apos;, { status: 500 }))
  }
})

async function handleEvent(event) {
  const { origin, pathname: path, search } = new URL(event.request.url);
  if (path.endsWith(&apos;/index.html&apos;)) {
    return new Response(null, {
      status: 301,
        headers: {
          &apos;Location&apos;: `${origin}${path.substring(0, path.length - 10)}${search}`,
          &apos;Cache-Control&apos;: &apos;max-age=3600&apos;
        }
    });
  }
  if (path === &apos;/atom.xml&apos;) {
    return getAssetFromKV(event, {
      cacheControl: {
        edgeTtl: 60 * 60,
        browserTtl: 2 * 60 * 60
      }
    });
  }
  
  if (path.startsWith(&apos;/css/&apos;))  {
    const response = await getAssetFromKV(event, {
      cacheControl: {
        edgeTtl: 365 * 24 * 60 * 60,
        browserTtl: 365 * 24 * 60 * 60
      }
    });
    // getAssetFromKV 不会添加 immutable，所以需要手动覆盖掉 Cache-Control
    response.headers.set(&apos;cache-control&apos;, `public, max-age=${365 * 24 * 60 * 60}, immutable`);
    return response;
  }
  
  const response = await getAssetFromKV(event, {
    cacheControl: {
      edgeTtl: 60 * 60,
      browserTtl: 5 * 60
    }
  });
  
  response.headers.set(&apos;X-XSS-Protection&apos;, &apos;1; mode=block&apos;);
  return response;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后，就结束了~~&lt;/p&gt;
&lt;p&gt;这个是官方给出的免费的限制，流量不大的话还是够用的。如果文章数量比较多的话，大概每天部署的次数比较有限。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Workers 功能&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;包括 100,000 个请求/天 (UTC+0)&lt;/li&gt;
&lt;li&gt;每个请求最多占用 10 毫秒 CPU 时间&lt;/li&gt;
&lt;li&gt;第一个请求后的延迟最低&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;键值存储功能&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每天 100,000 次读取操作&lt;/li&gt;
&lt;li&gt;每天 1,000 次写入、删除、列出操作&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>计算导论与程序设计基础复习指北</title><link>https://www.nekomio.com/posts/155/</link><guid isPermaLink="true">https://www.nekomio.com/posts/155/</guid><pubDate>Wed, 18 Dec 2019 09:52:47 GMT</pubDate><content:encoded>&lt;h2&gt;观前提示&lt;/h2&gt;
&lt;p&gt;本文中所有的代码都不保证可靠性，仅为一个便于理解的例子，如出现问题，本人概不负责，也请大家指正。&lt;/p&gt;
&lt;h2&gt;简介&lt;/h2&gt;
&lt;p&gt;本文简单的梳理了计导中的知识。&lt;/p&gt;
&lt;h3&gt;计算机程序设计语言&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;定义: 用于书写计算机程序的语言，用于表达和描述要加工的数据以及求解问题的步骤和过程。是根据预先定义的规则（语法）、由一个有限字母表上的字符构成的字符串的总体。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;计算模型&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;图灵机
&lt;ol&gt;
&lt;li&gt;组成
&lt;ol&gt;
&lt;li&gt;一个无限长的纸带&lt;/li&gt;
&lt;li&gt;一个读写头&lt;/li&gt;
&lt;li&gt;内部状态&lt;/li&gt;
&lt;li&gt;一个程序，用于对这个盒子进行控制&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;原理
&lt;ol&gt;
&lt;li&gt;根据程序的命令以及它的内部状态进行磁带的读写、移动 ，直至得到最后的结果。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;自动机(有限状态自动机)
&lt;ol&gt;
&lt;li&gt;组成
&lt;ol&gt;
&lt;li&gt;一个有限状态控制器&lt;/li&gt;
&lt;li&gt;一个读头&lt;/li&gt;
&lt;li&gt;一条写有字符的输入带&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;工作原理
&lt;ol&gt;
&lt;li&gt;读头在输入带上从左向右移动，每当读头从带上读到一个字符时，便引起控制器状态的改变，同时读头右移一个符号的位置&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;状态转移图
&lt;ol&gt;
&lt;li&gt;点: 表示一种状态&lt;/li&gt;
&lt;li&gt;边: 表示一种转移关系&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;C语言 （划重点）&lt;/h2&gt;
&lt;h3&gt;语法&lt;/h3&gt;
&lt;h4&gt;1. 定义&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;变量定义
C 中常见的变量有以下几种&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;int a;
long long b;
char c;
float b;
double e;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;函数定义&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;return_type function_name( parameter list )
{
   body of the function
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;数组定义&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;一维数组&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;type arrayName[arraysize];
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;多维数组&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;type arrayName[arraysize1][..]..[..][arraysizen];
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;指针定义&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;type *var-name;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;type 是var-name所指向的类型&lt;/p&gt;
&lt;h4&gt;2. 输入输出&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;输入&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;int scanf(const char *format, ...);
char *gets(char *s);
char getchar(void);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;scanf()&lt;/code&gt;是格式化输入,&lt;br /&gt;
&lt;code&gt;gets()&lt;/code&gt;能读入一整行的字符,&lt;br /&gt;
&lt;code&gt;getcchar()&lt;/code&gt;能读入单独的一个字符&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;输出&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;int printf(const char *format, ...);
int puts(const char *s);
int putchar(int c);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;与上面类似&lt;br /&gt;
&lt;code&gt;printf()&lt;/code&gt; 是格式化输出,&lt;br /&gt;
&lt;code&gt;puts()&lt;/code&gt; 可以输出一个字符串,&lt;br /&gt;
&lt;code&gt;putchar()&lt;/code&gt; 可以输出一个单独的字符&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;格式化符号&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字符&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;有符号十进制数值int&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;u&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;十进制unsigned int&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;double型输出10进制定点表示&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;char数组字符串&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;unsigned char&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;修饰符&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字符&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;l&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;对于整数类型，表示一个long尺寸的整型参数。 对于浮点类型，表示一个double尺寸的整型参数。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ll&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;对于整数类型，表示一个long long尺寸的整型参数。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;更多内容参考&lt;a href=&quot;https://en.wikipedia.org/wiki/Printf_format_string&quot;&gt;printf format string&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;流程控制&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;判断语句&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;if&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;if (...) {

} else {

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以没有else 有多个嵌套
2. switch&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;switch(...) {
    case ..:
        do some thing
        break;
    case ..:
        do some thing
        break;
    /* case的数量是任意的*/
    default: /* 可选的 */
        do some thing
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;循环&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;while&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;while(condition)
{

}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;for&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;for ( init; condition; increment ) {

}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;do...while&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;do
{

}while( condition );
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;运算符&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;算术运算符 &lt;code&gt;+-*/%&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;关系运算符 &lt;code&gt;==&lt;/code&gt;,&lt;code&gt;!=&lt;/code&gt;,&lt;code&gt;&amp;gt;&lt;/code&gt;,&lt;code&gt;&amp;lt;&lt;/code&gt;,&lt;code&gt;&amp;gt;=&lt;/code&gt;,&lt;code&gt;&amp;lt;=&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;逻辑运算符 &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;,&lt;code&gt;||&lt;/code&gt;,&lt;code&gt;!&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;结构体&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;struct struct_name {
    type val_name_1;
    ...
    type val_name_n;
} s1;

struct struct_name s2;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;typedef struct {
    type val_name_1;
    ...
    type val_name_n;
}struct_name; 

truct_name s1, s2;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个结构体可以简单的理解为将多个变量组合成了一个变量。&lt;br /&gt;
在定义结构体之后，我们相当于构造了一种新的变量类型。&lt;br /&gt;
我们可以用这种变量类型来定义变量。&lt;br /&gt;
访问结构体中的变量需要使用 &lt;code&gt;.&lt;/code&gt; 运算符。&lt;/p&gt;
&lt;h4&gt;指针&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;指向变量的指针&lt;br /&gt;
指针变量存储了另一个变量的地址。
比如&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;int a;
int *p = &amp;amp;a;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样 &lt;code&gt;p&lt;/code&gt; 变量中就储存了 &lt;code&gt;a&lt;/code&gt; 的地址。&lt;br /&gt;
我们访问一个变量&lt;br /&gt;
可以直接通过变量名访问&lt;br /&gt;
也可以通过它的地址来间接访问它的值。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;指向指针的指针&lt;br /&gt;
我们知道指针也是一种变量&lt;br /&gt;
所以我们也可以定义一个指向指针的指针，形如 &lt;code&gt;int **p&lt;/code&gt;。&lt;br /&gt;
我们这样理解，&lt;code&gt;p&lt;/code&gt; 指向了另一个指针，而那一个指针指向的是一个变量。&lt;br /&gt;
我们可以直接将一个指针解引用后的值当做一个完整的变量。
也就是说我们可以将 &lt;code&gt;*p&lt;/code&gt; 当做一个整体来理解， 它在一定意义上与它指向的变量的变量名等价。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;指向函数的指针&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;return_type (*function_name)( parameter list );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;请注意第一个括号不能省略，  否则将会变成返回一个指针的函数&lt;br /&gt;
函数指针可以指向一个函数，其中 &lt;code&gt;parameter list&lt;/code&gt; 中的参数名称可以省略，但不能省略参数名称。类似于函数声明。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;指向结构体的指针&lt;br /&gt;
指向结构体的指针与指向变量的指针类似。&lt;br /&gt;
问题在于 &lt;code&gt;.&lt;/code&gt; 运算符的优先级高于 &lt;code&gt;*&lt;/code&gt;运算符的优先级，所以我们要去元素的话 &lt;code&gt;(*a).b&lt;/code&gt; 一定要加括号。&lt;br /&gt;
这样很麻烦，所以我们有一种新的运算符 &lt;code&gt;-&amp;gt;&lt;/code&gt;， 则  &lt;code&gt;(*a).b&lt;/code&gt; 等价于 &lt;code&gt;a-&amp;gt;b&lt;/code&gt; 这样更加简洁易懂。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;函数传参与返回值&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;传参为按值传递，在函数内函数的参数不会影响原来的值。&lt;/li&gt;
&lt;li&gt;如果想要修改原来的值，那么我们要传入的值一定是&lt;strong&gt;要修改的值&lt;/strong&gt;的地址。&lt;/li&gt;
&lt;li&gt;将数组作为函数参数时，只可以省略第一维的大小，而且其他维的大小在传参的时候都要对应，而且传入数组时，数组内的元素可以被修改。&lt;/li&gt;
&lt;li&gt;函数无法返回一个数组。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;字符串&lt;/h4&gt;
&lt;p&gt;在C语言中字符串就是字符数组。&lt;br /&gt;
字符串的结尾是&lt;code&gt;&apos;\0&apos;&lt;/code&gt;，对应ASCII码为0&lt;br /&gt;
在string.h 库中有不少关于字符串的常用函数如strlen(), strcpy()。&lt;br /&gt;
我这里不再展开，大家可以再网上查阅相关内容。&lt;/p&gt;
&lt;h3&gt;算法&lt;/h3&gt;
&lt;h4&gt;1. 交换两个变量的值&lt;/h4&gt;
&lt;p&gt;假设我们有两个变量a和b, 我们要交换他们&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int temp = a;
a = b;
b = temp;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;2. 排序算法&lt;/h5&gt;
&lt;p&gt;我们主要学习一下冒泡排序&lt;br /&gt;
冒泡排序第k次循环将第k大（第k小）的数字移动到第k前（第k后）&lt;br /&gt;
然后在&lt;code&gt;n-1&lt;/code&gt;轮之后就能获得一个排好序的数组&lt;/p&gt;
&lt;p&gt;我们设 &lt;code&gt;a[i]&lt;/code&gt; 是需要排序的数组。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for (int i = 1; i &amp;lt; n; i++) {
    for (int j = 1; j &amp;lt;= n - i; j++) {
        if (a[j] &amp;gt; a[j + 1]) {
            int temp = a[j];
            a[j] = a[j + 1];
            a[j + 1] = temp;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3. 二分查找&lt;/h5&gt;
&lt;p&gt;我们先考虑最简单的二分法&lt;br /&gt;
假设我们有一个长度为 &lt;code&gt;n&lt;/code&gt; 已经从小到大排序好的数组 &lt;code&gt;a[i]&lt;/code&gt;。&lt;br /&gt;
我们想知道一个数 $x$ 是否在 &lt;code&gt;a[i]&lt;/code&gt; 中出现。&lt;br /&gt;
这时我们可以通过二分来找这个数&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int l = 0, r = n, ans = n + 1;
while (l &amp;lt;= r) {
    int mid = (l + r) / 2;
    if (a[mid] == x) {
        ans = mid;
        break;
    }
    if (a[mid] &amp;lt; x) l = mid + 1;
    else (a[mid] &amp;gt; x) r = mid - 1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后求出的 &lt;code&gt;ans&lt;/code&gt; 就是 $x$ 的位置， 如果没有找到的话 &lt;code&gt;ans&lt;/code&gt; 就是 &lt;code&gt;n + 1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;另一种二分为&lt;strong&gt;二分答案&lt;/strong&gt;。&lt;br /&gt;
二分答案是指，我们对一个问题答案的值进行二分。&lt;br /&gt;
通过逻辑判断得出我们真正的答案是比我们分出的值大还是小， 从而修改 &lt;code&gt;l,r&lt;/code&gt; 的值。&lt;br /&gt;
二分答案的条件是我们问题的答案具有单调性，&lt;br /&gt;
比如说，&lt;code&gt;a&lt;/code&gt; 如果可行， 那么比 &lt;code&gt;a&lt;/code&gt; 大的一定不可行， &lt;code&gt;a&lt;/code&gt; 如果不可行， 比 &lt;code&gt;a&lt;/code&gt; 小的一定不可行。&lt;br /&gt;
这样我们就可以进行二分了。&lt;/p&gt;
&lt;h2&gt;写在最后&lt;/h2&gt;
&lt;p&gt;由于篇幅有限，我很多内容不能写的很详细，也省略了一部分内容，很多内容还是要依靠大家自己复习。&lt;br /&gt;
希望大家能认真复习，祝愿大家在期末中取得好成绩。&lt;/p&gt;
&lt;p&gt;计导成绩更多的来自于平时的积累，要多打代码，多刷OJ题，当代码量达到一定水平之后，量变就会引发质变，会让大家对编程有一个全新的理解。&lt;/p&gt;
</content:encoded></item><item><title>Min25 筛法的原理与应用</title><link>https://www.nekomio.com/posts/154/</link><guid isPermaLink="true">https://www.nekomio.com/posts/154/</guid><description>Min25 筛法的原理与应用</description><pubDate>Sun, 11 Aug 2019 14:58:06 GMT</pubDate><content:encoded>&lt;h3&gt;0. 定义&lt;/h3&gt;
&lt;p&gt;$\mathbb{P}$ 表示质数集&lt;/p&gt;
&lt;h3&gt;1. 用途&lt;/h3&gt;
&lt;p&gt;Min25筛是一种求积性函数$f(x)$的前缀和$\sum_{i=1}^{N}{f(i)}$的一种方法。&lt;/p&gt;
&lt;h3&gt;2. 条件&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;$f(n)$ 为积性函数 (废话)&lt;/li&gt;
&lt;li&gt;$f(p)$ 在$p$处为关于$p$的低次多项式&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;3. 做法&lt;/h3&gt;
&lt;p&gt;首先， 我们定义一个函数$g_k(n, m) = \sum_{i=1}^{n}{i^k[i \in \mathbb{P};or;M(i) &amp;gt; P_m]}$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当 $n &amp;lt; P_m^2$ 时 $g_k(n, m) = g_k(n, m - 1)$&lt;/li&gt;
&lt;li&gt;否则我们要从$g_k(n, m)$中删除$M(i)=P_m$的合数的贡献，也就是&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\sum_{i=1}^{n}{i^k[i \in \mathbb{C};and;M(i) = P_m]} =P_m^k(g_k(\lfloor\frac{n}{P_m}\rfloor, m - 1)-\sum_{i=1}^{m-1}{P_i^k})$$&lt;/p&gt;
&lt;p&gt;之后，我们要计算我们的函数$f(x)$&lt;/p&gt;
&lt;p&gt;我们定义$h(n, m)=\sum_{i=1}^n{f(i)[M(i) \ge P_m]}$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;先考虑质数，因为$f(p)$ 满足第二个条件， 所以我们可以用$g$函数构造出$f(p)$的答案。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;那么设$f(p) = \sum{a_k*p^k}$&lt;/li&gt;
&lt;li&gt;则可以得出$\sum_{i=m}^{|P|}{f(P_i)[P_i&amp;lt;n]} = \sum{a_k*g_k(n, |P|) - \sum_{i=1}^{m-1}{f(P_i)}}$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后考虑合数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;枚举合数的最小质因子为$P_i$, 和最小质因子的次数为$t$,&lt;br /&gt;
可以将合数写为$P_i^t \times j (M(j) \ge P_{i+1}, j \le \lfloor \frac{n}{P_i^t} \rfloor)$&lt;/li&gt;
&lt;li&gt;则这些合数的贡献为 $f(P_i^t)((\sum_{j=1}^{\frac{n}{P_i^t}}{f(j)[M(j) \ge P_{i+1}]}) + [t \neq 1]) = f(P_i^t) (h(\lfloor \frac{n}{P_i^t} \rfloor, i + 1) + [t \neq 1])$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;综合一下&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$ h(n,m) =\sum{a_kg_k(n, |P|)}-\sum_{i=1}^{m-1}{f(P_i)}+\sum_{i=m}^{|P|}{\sum_{t \ge 1 , P_i^t \le n}{f(P_i^t)(h(\lfloor \frac{n}{P_i^t} \rfloor, i + 1) + [t \neq 1])}} $$&lt;/p&gt;
</content:encoded></item><item><title>模板库</title><link>https://www.nekomio.com/posts/templates/</link><guid isPermaLink="true">https://www.nekomio.com/posts/templates/</guid><pubDate>Wed, 31 Jul 2019 11:04:10 GMT</pubDate><content:encoded>&lt;ol&gt;
&lt;li&gt;算法 (AG)
&lt;ol&gt;
&lt;li&gt;网络流 (NF)
&lt;ol&gt;
&lt;li&gt;网络流线性规划
&lt;ol&gt;
&lt;li&gt;上下界网络流&lt;/li&gt;
&lt;li&gt;最小割&lt;/li&gt;
&lt;li&gt;费用流&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Edmond-Karp (EK)
&lt;ol&gt;
&lt;li&gt;Capacity Scaling&lt;/li&gt;
&lt;li&gt;Dinic&amp;amp;SAP&lt;/li&gt;
&lt;li&gt;HLPP&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;差分约束 (DC)&lt;/li&gt;
&lt;li&gt;通用线性规划 (LP)
&lt;ol&gt;
&lt;li&gt;单纯形算法&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;分数规划 (FP)&lt;/li&gt;
&lt;li&gt;贪心 (GE)&lt;/li&gt;
&lt;li&gt;分治 (DAC)
&lt;ol&gt;
&lt;li&gt;序列分治
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#CDQ&quot;&gt;CDQ&amp;amp;&lt;s&gt;整体二分&amp;amp;线段树分治&lt;/s&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[ ] 快速排序
&lt;ol&gt;
&lt;li&gt;快速选择
&lt;ol&gt;
&lt;li&gt;Median of Medians&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;树分治
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#%E7%82%B9%E5%88%86%E6%B2%BB&quot;&gt;点/&lt;s&gt;边&lt;/s&gt;分治&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;重链剖分
&lt;ol&gt;
&lt;li&gt;树上启发式合并&lt;/li&gt;
&lt;li&gt;长链剖分&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;搜索 (SR)
&lt;ol&gt;
&lt;li&gt;搜索优化与剪枝
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#Astar&quot;&gt;A* (AS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;迭代加深搜索 (ID)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;折半搜索 (MIM)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;随机化及近似 (RAN)
&lt;ol&gt;
&lt;li&gt;&lt;s&gt;爬山&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E6%A8%A1%E6%8B%9F%E9%80%80%E7%81%AB&quot;&gt;模拟退火&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;s&gt;遗传算法&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;&lt;s&gt;机器学习基础&lt;/s&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;离线逆序
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#%E8%8E%AB%E9%98%9F&quot;&gt;莫队算法&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E7%A6%BB%E6%95%A3%E5%8C%96&quot;&gt;散列 (HS)&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;数据结构 (DS)
&lt;ol&gt;
&lt;li&gt;栈 (STK) =&amp;gt; STL&lt;/li&gt;
&lt;li&gt;队列 (QUE) =&amp;gt; STL&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Hash_Table&quot;&gt;散列表 (HST)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;堆 (HP)
&lt;ol&gt;
&lt;li&gt;二叉堆&lt;/li&gt;
&lt;li&gt;可并堆&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;二叉查找树 (BST)
&lt;ol&gt;
&lt;li&gt;堆树 (THP)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Treap&quot;&gt;Treap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;红黑树 (RBT)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E6%9B%BF%E7%BD%AA%E7%BE%8A%E6%A0%91&quot;&gt;替罪羊树 (SGT)&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E6%A0%91%E7%8A%B6%E6%95%B0%E7%BB%84&quot;&gt;树状数组 (BIT)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E7%BA%BF%E6%AE%B5%E6%A0%91&quot;&gt;线段树 (SGM)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E5%B9%B6%E6%9F%A5%E9%9B%86&quot;&gt;并查集 (UFS)&lt;/a&gt;
&lt;ol&gt;
&lt;li&gt;带权并查集&lt;/li&gt;
&lt;li&gt;路径压缩&lt;/li&gt;
&lt;li&gt;按秩合并&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#ST&quot;&gt;Sparse Table (ST)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#KD-Tree&quot;&gt;K维树 (KDT)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;动态树
&lt;ol&gt;
&lt;li&gt;点/边分治树 (DCT)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#LCT&quot;&gt;Link-Cut Tree (LCT)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;欧拉回路树 (ETT)&lt;/li&gt;
&lt;li&gt;AAA Tree &amp;amp; Top Tree&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;动态图&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;图论 (GT)
&lt;ol&gt;
&lt;li&gt;最小生成树
&lt;ol&gt;
&lt;li&gt;Prim 算法 (PM)&lt;/li&gt;
&lt;li&gt;Kruskal 算法 (KS)
&lt;ol&gt;
&lt;li&gt;Boruvka 算法&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;最小树形图
&lt;ol&gt;
&lt;li&gt;朱-刘算法&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;斯坦纳树&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;最短路径
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#Dijkstra&quot;&gt;dijkstra 算法 (DJ)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#SPFA&quot;&gt;Bellman-Ford 算法 (BFD)&lt;/a&gt;
&lt;ol&gt;
&lt;li&gt;Johnson 算法&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Floyd 算法 (FL)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;欧拉路&amp;amp;哈密顿路&lt;/li&gt;
&lt;li&gt;连通性
&lt;ol&gt;
&lt;li&gt;点/边双连通分量 (BCC)&lt;/li&gt;
&lt;li&gt;强连通性 (SCC)&lt;/li&gt;
&lt;li&gt;支配树&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;匹配、划分与覆盖
&lt;ol&gt;
&lt;li&gt;KM 算法 (KM)
&lt;ol&gt;
&lt;li&gt;交错树&lt;/li&gt;
&lt;li&gt;带花树算法 (BL)&lt;/li&gt;
&lt;li&gt;Tutte 矩阵与一般图匹配&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;覆盖集与独立集&lt;/li&gt;
&lt;li&gt;稳定婚姻问题与 GS 算法 (GS)&lt;/li&gt;
&lt;li&gt;Hall 定理&lt;/li&gt;
&lt;li&gt;DAG 路径覆盖&lt;/li&gt;
&lt;li&gt;Dilworth 定理&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;2-SAT&lt;/li&gt;
&lt;li&gt;虚树&lt;/li&gt;
&lt;li&gt;仙人掌
&lt;ol&gt;
&lt;li&gt;圆方树&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;弦图与区间图&lt;/li&gt;
&lt;li&gt;图的树分解&lt;/li&gt;
&lt;li&gt;最小割
&lt;ol&gt;
&lt;li&gt;最小割树&lt;/li&gt;
&lt;li&gt;Stoer-Wagner 算法&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;平面图
&lt;ol&gt;
&lt;li&gt;平面图对偶图&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;网格图&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;计算几何 (CG)
&lt;ol&gt;
&lt;li&gt;几何向量&lt;/li&gt;
&lt;li&gt;二维凸包
&lt;ol&gt;
&lt;li&gt;凸包算法
&lt;ol&gt;
&lt;li&gt;卷包裹法&lt;/li&gt;
&lt;li&gt;动态凸包&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;三维凸包&lt;/li&gt;
&lt;li&gt;半平面交&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;旋转卡壳&lt;/li&gt;
&lt;li&gt;三角剖分
&lt;ol&gt;
&lt;li&gt;V图&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;路径规划&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;代数 (AB)
&lt;ol&gt;
&lt;li&gt;微积分基础
&lt;ol&gt;
&lt;li&gt;Simpson 积分算法&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;线性代数
&lt;ol&gt;
&lt;li&gt;矩阵基础
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#%E9%AB%98%E6%96%AF%E6%B6%88%E5%85%83&quot;&gt;高斯消元&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;拟阵&lt;/li&gt;
&lt;li&gt;Matrix-Tree 定理&lt;/li&gt;
&lt;li&gt;线性递推&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;多项式与幂级数
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#FFT&quot;&gt;DFT/FFT (FT)&lt;/a&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#NTT&quot;&gt;NTT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Bluestein 算法&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E5%A4%9A%E9%A1%B9%E5%BC%8F&quot;&gt;多项式基本运算&lt;/a&gt;
&lt;ol&gt;
&lt;li&gt;多项式除法&lt;/li&gt;
&lt;li&gt;多项式基本初等函数&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;FWT (FWT)
&lt;ol&gt;
&lt;li&gt;子集变换&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;抽象代数
&lt;ol&gt;
&lt;li&gt;置换群
&lt;ol&gt;
&lt;li&gt;Schreier-Sims 算法&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;数论 (NT)
&lt;ol&gt;
&lt;li&gt;同余和整除
&lt;ol&gt;
&lt;li&gt;欧几里得算法
&lt;ol&gt;
&lt;li&gt;扩展欧几里得算法&lt;/li&gt;
&lt;li&gt;类欧几里得算法&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;欧拉定理&lt;/li&gt;
&lt;li&gt;二次剩余&lt;/li&gt;
&lt;li&gt;原根及离散对数
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#BSGS&amp;amp;exBSGS&quot;&gt;BSGS&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;lucas 定理&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;质数与简单数论函数
&lt;ol&gt;
&lt;li&gt;埃氏筛&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E7%BA%BF%E6%80%A7%E7%AD%9B&quot;&gt;欧拉筛&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;莫比乌斯反演&lt;/li&gt;
&lt;li&gt;数论函数快速求和
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#%E6%9D%9C%E6%95%99%E7%AD%9B&quot;&gt;杜教筛&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;洲阁筛&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;素性测试
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#Miller_Robin&quot;&gt;Miller-Robin (MR)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Miller_Robin&quot;&gt;Pollard&apos;s Rho 因子分解&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;组合计数 (CE)
&lt;ol&gt;
&lt;li&gt;计数原理
&lt;ol&gt;
&lt;li&gt;容斥原理&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;计数数列
&lt;ol&gt;
&lt;li&gt;斯特林数&lt;/li&gt;
&lt;li&gt;卡特兰数&lt;/li&gt;
&lt;li&gt;伯努利数&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;生成函数 (GF)&lt;/li&gt;
&lt;li&gt;杨氏矩阵&lt;/li&gt;
&lt;li&gt;Burnside 引理
&lt;ol&gt;
&lt;li&gt;Polya 定理&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;博弈论与信息论 (GI)
&lt;ol&gt;
&lt;li&gt;博弈基础
&lt;ol&gt;
&lt;li&gt;组合游戏
&lt;ol&gt;
&lt;li&gt;博弈树与 DAG 模型&lt;/li&gt;
&lt;li&gt;Sprague-Grundy 函数 (SG)&lt;/li&gt;
&lt;li&gt;Nim (NIM)
&lt;ol&gt;
&lt;li&gt;Nim 积&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;威佐夫博弈&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;不平等博弈
&lt;ol&gt;
&lt;li&gt;超现实数&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;不完全信息博弈&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;通信与数据压缩
&lt;ol&gt;
&lt;li&gt;校验码&lt;/li&gt;
&lt;li&gt;哈夫曼编码&lt;/li&gt;
&lt;li&gt;游程编码&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;形式语言，自动机与串处理 (FAS)
&lt;ol&gt;
&lt;li&gt;串处理 (STR)
&lt;ol&gt;
&lt;li&gt;模式匹配
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#KMP&amp;amp;EXKMP&quot;&gt;KMP 算法 (KMP) &amp;amp;&amp;amp; EXKMP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AC 自动机&lt;/li&gt;
&lt;li&gt;Shift-And 算法&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;字典树 (TRI)
&lt;ol&gt;
&lt;li&gt;后缀树
&lt;ol&gt;
&lt;li&gt;后缀数组 (SA)&lt;/li&gt;
&lt;li&gt;后缀自动机 (SAM)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Border
&lt;ol&gt;
&lt;li&gt;Periodicity 引理&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;回文串
&lt;ol&gt;
&lt;li&gt;manacher 算法&lt;/li&gt;
&lt;li&gt;回文自动机 (PAM)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;形式语言
&lt;ol&gt;
&lt;li&gt;正则表达式 (RE)&lt;/li&gt;
&lt;li&gt;有限状态自动机 (DFA)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;并行计算&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;CDQ&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
const int MAXN = 800005;
struct Query
{
    int x, y, op, val, id, pos;
    bool operator &amp;lt; (const Query &amp;amp;a) const
    {
        return x == a.x ? op &amp;lt; a.op : x &amp;lt; a.x;
    }
} Ask[MAXN], tmp[MAXN];
int n, m, Ans[MAXN];
#define lowbit(_) ((_)&amp;amp;(-_))
struct BIT
{
    int Sum[2000005];
    void add(int x, int c)
    {
        for (int i = x; i &amp;lt;= n; i += lowbit(i))
            Sum[i] += c;
    }
    int Query(int x)
    {
        int ans = 0;
        for (int i = x; i &amp;gt; 0; i -= lowbit(i))
            ans += Sum[i];
        return ans;
    }
}bit;
void add()
{
    int x1, y1, x2, y2;
    scanf (&quot;%d%d%d%d&quot;, &amp;amp;x1, &amp;amp;y1, &amp;amp;x2, &amp;amp;y2);
    ++Ans[0];
    Ask[++m].pos = Ans[0], Ask[m].x = x1 - 1, Ask[m].y = y1 - 1, Ask[m].val = 1, Ask[m].op = 1;
    Ask[++m].pos = Ans[0], Ask[m].x = x2    , Ask[m].y = y2    , Ask[m].val = 1, Ask[m].op = 1;
    Ask[++m].pos = Ans[0], Ask[m].x = x1 - 1, Ask[m].y = y2    , Ask[m].val =-1, Ask[m].op = 1;
    Ask[++m].pos = Ans[0], Ask[m].x = x2    , Ask[m].y = y1 - 1, Ask[m].val =-1, Ask[m].op = 1;
}
void CDQ(int l, int r)
{
    if (l == r)
        return;
    int mid = l + r &amp;gt;&amp;gt; 1, l1 = l, l2 = mid + 1;
    for (int i = l; i &amp;lt;= r; i++)
    {
        if (Ask[i].id &amp;lt;= mid &amp;amp;&amp;amp; !Ask[i].op)
            bit.add(Ask[i].y, Ask[i].val);
        if (Ask[i].id &amp;gt; mid &amp;amp;&amp;amp; Ask[i].op)
            Ans[Ask[i].pos] += Ask[i].val * bit.Query(Ask[i].y);
    }
    for (int i = l; i &amp;lt;= r; i++)
        if (Ask[i].id &amp;lt;= mid &amp;amp;&amp;amp; !Ask[i].op)
            bit.add(Ask[i].y, -Ask[i].val);
    for (int i = l; i &amp;lt;= r; i++)
    {
        if (Ask[i].id &amp;lt;= mid)
            tmp[l1++] = Ask[i];
        else tmp[l2++] = Ask[i];
    }
    for (int i = l; i &amp;lt;= r; i++)
        Ask[i] = tmp[i];
    CDQ(l, mid);
    CDQ(mid + 1, r);
    return;
}
int main()
{
    freopen(&quot;mokia.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;mokia.out&quot;, &quot;w&quot;, stdout);
    int op;
    scanf (&quot;%d%d&quot;, &amp;amp;op, &amp;amp;n);
    while (1)
    {
        scanf (&quot;%d&quot;, &amp;amp;op);
        if (op == 1)
        {
            m++;
            scanf (&quot;%d%d%d&quot;, &amp;amp;Ask[m].x, &amp;amp;Ask[m].y, &amp;amp;Ask[m].val);
        }
        else if (op == 2)
            add();
        else break;
    }
    for (int i = 1; i &amp;lt;= m; i++)
        Ask[i].id = i;
    sort(Ask + 1, Ask + m + 1);
    CDQ(1 ,m);
    for (int i = 1; i &amp;lt;= Ans[0]; i++)
        printf (&quot;%d\n&quot;, Ans[i]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;点分治&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using namespace std;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
	while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
	return x*f;
}

const int MAXN = 20005;

struct edge
{
	int END, next;
	int v;
}v[MAXN &amp;lt;&amp;lt; 1]; 
int first[MAXN], p;
void add(int a, int b, int c)
{
	v[p].END = b;
	v[p].next = first[a];
	v[p].v = c;
	first[a] = p++;
}
int size[MAXN], Max[MAXN], ans, sum, t[3], d[MAXN];
bool vis[MAXN];
int root;
void Get_root(int rt, int fa)
{
	size[rt] = 1, Max[rt] = 0;
	for (int i = first[rt]; i != -1; i = v[i].next)
	{
		if (!vis[v[i].END] &amp;amp;&amp;amp; v[i].END != fa)
		{
			Get_root(v[i].END, rt);
			size[rt] += size[v[i].END];
			Max[rt] = max(Max[rt], size[v[i].END]);
		}
	}
	Max[rt] = max(Max[rt], sum - size[rt]);
	if (Max[rt] &amp;lt; Max[root]) root = rt;
}

void dfs(int rt, int fa)
{
	t[d[rt]]++;
	for (int i = first[rt]; i != -1; i = v[i].next)
	{
		if (!vis[v[i].END] &amp;amp;&amp;amp; v[i].END != fa)
		{
			d[v[i].END] = (d[rt] + v[i].v) % 3;
			dfs(v[i].END, rt);
		}
	}
}

int Calc(int rt, int x)
{
	t[0] = t[1] = t[2] = 0;
	d[rt] = x;
	dfs(rt, 0);
	return t[1] * t[2] * 2 + t[0] * t[0];
}

void Solve(int rt)
{
	ans += Calc(rt, 0);
	vis[rt] = 1;
	for (int i = first[rt]; i != -1; i = v[i].next)
	{
		if (!vis[v[i].END])
		{
			ans -= Calc(v[i].END, v[i].v);
			root = 0, sum = size[v[i].END];
			Get_root(v[i].END, 0);
			Solve(root);
		}
	}
}

int gcd(int a, int b)
{
	return b == 0 ? a : gcd(b, a % b);
}

int main()
{
	memset (first, -1, sizeof (first));
	int n = read();
	int a, b, c;
	for (int i = 1; i &amp;lt; n; i++)
	{
		a = read(), b = read(), c = read() % 3;
		add(a, b, c);
		add(b, a, c);
	}
	Max[0] = sum = n;
	Get_root(1, 0);
	Solve(root);
	int G = gcd(ans, n * n);
	printf (&quot;%d/%d\n&quot;, ans / G, n * n / G);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;Astar&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;queue&amp;gt;
using namespace std;
struct edge {
  int END, v, next;
} ZHENG[10005], FAN[10005];
struct A {
  int END, f, g;
  bool operator&amp;lt;(const A &amp;amp;a) const {
    if (f == a.f) return a.g &amp;lt; g;
    return a.f &amp;lt; f;
  }
};
int first_zheng[1005], first_fan[1005], p;
int dis[1005];
int n;
int s;
void add(int a, int b, int c);
void spfa(int a);
int Astar(int k);
int main() {
  freopen(&quot;cowjog.in&quot;, &quot;r&quot;, stdin);
  freopen(&quot;cowjog.out&quot;, &quot;w&quot;, stdout);
  // cin&amp;gt;&amp;gt;n&amp;gt;&amp;gt;m;
  memset(first_fan, -1, sizeof(first_fan));
  memset(first_zheng, -1, sizeof(first_zheng));
  p = 1;
  int m, a, b, c, K;
  scanf(&quot;%d%d%d&quot;, &amp;amp;n, &amp;amp;m, &amp;amp;K);
  for (int i = 1; i &amp;lt;= m; i++) {
    scanf(&quot;%d%d%d&quot;, &amp;amp;a, &amp;amp;b, &amp;amp;c);
    if (a &amp;gt; b)
      add(a, b, c);
    else
      add(b, a, c);
  }
  spfa(1);
  for (int k = 1; k &amp;lt;= K; k++) {
    s = 0;
    cout &amp;lt;&amp;lt; Astar(k) &amp;lt;&amp;lt; endl;
  }
  // while(1);
}
void add(int a, int b, int c) {
  ZHENG[p].END = b;
  ZHENG[p].v = c;
  ZHENG[p].next = first_zheng[a];
  FAN[p].END = a;
  FAN[p].v = c;
  FAN[p].next = first_fan[b];
  first_zheng[a] = p;
  first_fan[b] = p++;
}
void spfa(int a) {
  memset(dis, 0x3f, sizeof(dis));
  dis[a] = 0;
  bool flag[1005] = {0};
  queue&amp;lt;int&amp;gt; p;
  p.push(a);
  flag[a] = 1;
  while (!p.empty()) {
    int tmp = p.front();
    flag[tmp] = 0;
    p.pop();
    for (int i = first_fan[tmp]; i != -1; i = FAN[i].next) {
      if (dis[FAN[i].END] &amp;gt; dis[tmp] + FAN[i].v) {
        dis[FAN[i].END] = dis[tmp] + FAN[i].v;
        if (!flag[FAN[i].END]) {
          flag[FAN[i].END] = 1;
          p.push(FAN[i].END);
        }
      }
    }
  }
}
int Astar(int k) {
  priority_queue&amp;lt;A&amp;gt; p;
  A s1, s2;
  s1.END = n;
  s1.g = 0;
  s1.f = s1.g + dis[n];
  p.push(s1);
  while (!p.empty()) {
    s2 = p.top();
    p.pop();
    if (s2.END == 1) {
      s++;
      if (s == k) return s2.g;
    }
    for (int i = first_zheng[s2.END]; i != -1; i = ZHENG[i].next) {
      s1.END = ZHENG[i].END;
      s1.g = s2.g + ZHENG[i].v;
      s1.f = s1.g + dis[ZHENG[i].END];
      p.push(s1);
    }
  }
  return -1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;模拟退火&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cmath&amp;gt;
#include &amp;lt;climits&amp;gt;
#include &amp;lt;ctime&amp;gt;
using namespace std;
const double pi = acos(-1.);
const double eps = 1e-10;
const int seed = time(0);
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
double Rand()
{
    return 1.0 * rand() / RAND_MAX;
}
struct Point
{
    double x, y, k;
    Point(double _x = 0, double _y = 0): x(_x), y(_y) {
        k = atan2(y, x);
    }
    Point operator - (const Point &amp;amp;_x)
    {
        return Point(x - _x.x, y - _x.y);
    }
    double operator * (const Point &amp;amp;_x)
    {
        return x * _x.y - y * _x.x;
    }
    bool operator &amp;lt; (const Point &amp;amp;_x) const
    {
        return k &amp;gt; _x.k;
    }
}a[10], tmp[10];
int cnt = 0;
double area(Point *x, int n)
{
    double ans = 0;
    cnt++;
    sort(x + 1, x + n + 1);
    Point t(0, 0);
    for (int i = 1; i &amp;lt;= n - 1; i++)
        ans += (x[i] - t) * (x[i + 1] - t);
    ans += (x[n] - t) * (x[1] - t);
    return fabs(ans);
}
int r[10];
bool cmp(const int &amp;amp;a, const int &amp;amp;b)
{
    return a &amp;gt; b;
}
double dis(Point &amp;amp;x, Point &amp;amp;y)
{
    return (x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y);
}
bool cmp1(Point x, Point y)
{
    double s = (x - tmp[1]) * (y - tmp[1]);
    if (fabs(s) &amp;lt;= eps) return dis(x, tmp[1]) &amp;lt; dis(y, tmp[1]);
    return s &amp;gt; 0;
}
int st[10], top;
double Calc(Point *x, int n)
{
	memcpy(tmp, x, sizeof (tmp));
    int k = 0;
    for (int i = 1; i &amp;lt;= n; i++)
        if (tmp[i].x &amp;lt; tmp[k].x &amp;amp;&amp;amp; tmp[i].y &amp;lt; tmp[k].y || !k)
            k = i;
    swap(tmp[1], tmp[k]);
    sort(tmp + 2, tmp + n + 1, cmp1);
    top = 0;
    st[++top] = 1;
    for (int i = 2; i &amp;lt;= n; i++)
    {
        while (top &amp;gt; 1 &amp;amp;&amp;amp; (tmp[st[top]] - tmp[st[top - 1]]) * (tmp[i] - tmp[st[top]]) &amp;lt; 0) top--;
        st[++top] = i;
    }
    for (int i = 1; i &amp;lt;= top; i++)
        tmp[i] = tmp[st[i]];
    return area(tmp, top);
}
double T = 1e9, mint = 1e-9, delta = 1 - 1e-2;
int loop = 50;
double w[10];
int main()
{
    // freopen (&quot;1.out&quot;, &quot;w&quot;, stdout);
    srand(seed);
    int n = read();
    for (int i = 1; i &amp;lt;= n; i++) r[i] = read();
    for (int i = 1; i &amp;lt;= n; i++) w[i] = Rand() * 2 * pi;
    for (int i = 1; i &amp;lt;= n; i++) a[i].x = cos(w[i]) * r[i], a[i].y = sin(w[i]) * r[i];
    double ans = Calc(a, n);
    while (T &amp;gt; mint)
    {
        for (int i = 1; i &amp;lt;= loop; i++)
        {
            int t = rand() % n + 1;
            double tmp_w = w[t];
            w[t] = w[t] + Rand() * 2 * pi * T;
            // if (w[t] &amp;gt; 2 * pi) w[t] -= 2 * pi;
            a[t].x = cos(w[t]) * r[t], a[t].y = sin(w[t]) * r[t];
            double tmp = Calc(a, n);
            // printf (&quot;%.2f\n&quot;, (tmp - ans) / T);
            // printf (&quot;%.2f\n&quot;, exp((tmp - ans) / T));
            if (tmp &amp;gt; ans || exp((tmp - ans) / T) &amp;gt; Rand()) 
                ans = tmp;
            else
            {
                w[t] = tmp_w;
                a[t].x = cos(w[t]) * r[t], a[t].y = sin(w[t]) * r[t];
            }
        }
        T *= delta;
    }
    printf (&quot;%.10f\n&quot;, ans / 2);
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;莫队&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
int a[50005], in[50005];
int block = 500;
struct Query
{
	int l, r, ID;
	bool operator &amp;lt; (const Query &amp;amp;b) const 
	{
		return in[l] == in[b.l] ? r &amp;gt; b.r : l &amp;lt; b.l;
	}
}Q[200005];
int cnt[1000005];
int out[200005];
int main()
{
	int n, m, ans = 0;
	scanf(&quot;%d&quot;, &amp;amp;n);
	for (int i = 1; i &amp;lt;= n; i++)
	{
		scanf(&quot;%d&quot;, &amp;amp;a[i]);	
		in[i] = (i - 1) / block + 1;
		cnt[a[i]]++;
		if(cnt[a[i]] == 1)
			ans++;
	}
	scanf(&quot;%d&quot;, &amp;amp;m);
	for (int i = 1; i &amp;lt;= m; i++)
		scanf(&quot;%d%d&quot;, &amp;amp;Q[i].l, &amp;amp;Q[i].r), Q[i].ID = i;
	sort(Q + 1, Q + m + 1);
	int l = 1, r = n + 1;
	for (int i = 1; i &amp;lt;= m; i++)
	{
		while(l &amp;lt; Q[i].l) {cnt[a[l]]--; if(cnt[a[l]] == 0) ans--; l++;}
		while(l &amp;gt; Q[i].l) {l--; cnt[a[l]]++; if(cnt[a[l]] == 1) ans++;}
		while(r &amp;gt; Q[i].r) {cnt[a[r]]--; if(cnt[a[r]] == 0) ans--; r--;}
		while(r &amp;lt; Q[i].r) {r++; cnt[a[r]]++; if(cnt[a[r]] == 1) ans++;}
		out[Q[i].ID] = ans;
	}
	for (int i = 1; i &amp;lt;= m; i++)
		printf(&quot;%d\n&quot;, out[i]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;离散化&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;cnt = 0;
for (int i = 1; i &amp;lt;= n; i++) {
  a[i] = read();
  Hash[++cnt] = a[i];
}
sort(Hash + 1, Hash + cnt + 1);
cnt = unique(Hash + 1, Hash + cnt + 1) - Hash - 1;
for (int i = 1; i &amp;lt;= n; i++) {
  a[i] = lower_bound(Hash + 1, Hash + cnt + 1, a[i]) - Hash;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;Hash_Table&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;const int MAXN = 200000, BASE = 76543;
struct Hash_Table
{
    struct edge
    {
        int Id, next;
        long long Max;
    }v[MAXN];
    int first[BASE + 2], p;
    Hash_Table()
    {
        memset (first, -1, sizeof (first));
        p = 0;
    }
    void clear()
    {
        memset (first, -1, sizeof (first));
        p = 0;
    }
    long long &amp;amp;operator[](int x)
    {
        int H = x % BASE;
        for (int i = first[H]; i != -1; i = v[i].next)
            if (v[i].Id == x)
                return v[i].Max;
        v[p].Id = x;
        v[p].next = first[H];
        first[H] = p++;
        return v[p - 1].Max = -INF;
    }
}Hash;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;Treap&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;struct Treap
{
    struct Node
    {
        int s, key, Max_Num, Max_Size;
        data x;
        Node *ch[2];
        Node(data sa)
        {
            ch[0] = ch[1] = NULL;
            s = 1, x = sa, key = rand();
            Max_Num = Max_Size = 0;
        }
#define size(_) ((_) ? (_)-&amp;gt;s : 0)
        void Pushup()
        {
            s = size(ch[0]) + size(ch[1]) + 1;
        }
        void Pushdown()
        {
            if (ch[0])
            {
                ch[0]-&amp;gt;Max_Num = max(ch[0]-&amp;gt;Max_Num, Max_Num);
                ch[0]-&amp;gt;Max_Size = max(ch[0]-&amp;gt;Max_Size, Max_Size);
                Max_Morale[ch[0]-&amp;gt;x.ID] = max(Max_Morale[ch[0]-&amp;gt;x.ID], ch[0]-&amp;gt;Max_Num);
                Max_Solidarity[ch[0]-&amp;gt;x.ID] = max(Max_Solidarity[ch[0]-&amp;gt;x.ID], ch[0]-&amp;gt;Max_Size);
            }
            if (ch[1])
            {
                ch[1]-&amp;gt;Max_Num = max(ch[1]-&amp;gt;Max_Num, Max_Num);
                ch[1]-&amp;gt;Max_Size = max(ch[1]-&amp;gt;Max_Size, Max_Size);
                Max_Morale[ch[1]-&amp;gt;x.ID] = max(Max_Morale[ch[1]-&amp;gt;x.ID], ch[1]-&amp;gt;Max_Num);
                Max_Solidarity[ch[1]-&amp;gt;x.ID] = max(Max_Solidarity[ch[1]-&amp;gt;x.ID], ch[1]-&amp;gt;Max_Size);
            }
            Max_Num = Max_Size = 0;
        }
    } * root;
    Treap()
    {
        root = NULL;
    }
    Node *Merge(Node *A, Node *B)
    {
        if (!A)
            return B;
        if (!B)
            return A;
        if (A-&amp;gt;key &amp;lt; B-&amp;gt;key)
        {
            A-&amp;gt;Pushdown();
            A-&amp;gt;ch[1] = Merge(A-&amp;gt;ch[1], B);
            A-&amp;gt;Pushup();
            return A;
        }
        else
        {
            B-&amp;gt;Pushdown();
            B-&amp;gt;ch[0] = Merge(A, B-&amp;gt;ch[0]);
            B-&amp;gt;Pushup();
            return B;
        }
    }
    typedef pair&amp;lt;Node *, Node *&amp;gt; DNode;
    DNode Split(Node *rt, int k)
    {
        if (!rt)
            return DNode(NULL, NULL);
        DNode o;
        rt-&amp;gt;Pushdown();
        if (size(rt-&amp;gt;ch[0]) &amp;gt;= k)
        {
            o = Split(rt-&amp;gt;ch[0], k);
            rt-&amp;gt;ch[0] = o.second;
            rt-&amp;gt;Pushup();
            o.second = rt;
        }
        else
        {
            o = Split(rt-&amp;gt;ch[1], k - size(rt-&amp;gt;ch[0]) - 1);
            rt-&amp;gt;ch[1] = o.first;
            rt-&amp;gt;Pushup();
            o.first = rt;
        }
        return o;
    }
    Node *kth(int k)
    {
        DNode x = Split(root, k - 1);
        DNode y = Split(x.second, 1);
        Node *ans = y.first;
        root = Merge(Merge(x.first, ans), y.second);
        return ans;
    }
    int Rank(Node *rt, data x)
    {
        if (!rt)
            return 0;
        return x &amp;lt;= rt-&amp;gt;x ? Rank(rt-&amp;gt;ch[0], x) : Rank(rt-&amp;gt;ch[1], x) + size(rt-&amp;gt;ch[0]) + 1;
    }
    void Insert(data x)
    {
        int k = Rank(root, x);
        if (root)
        {
            root-&amp;gt;Max_Size = max(root-&amp;gt;Max_Size, size(root));
            root-&amp;gt;Max_Num = max(root-&amp;gt;Max_Num, x.x);
            Max_Morale[root-&amp;gt;x.ID] = max(root-&amp;gt;Max_Num, Max_Morale[root-&amp;gt;x.ID]);
            Max_Solidarity[root-&amp;gt;x.ID] = max(root-&amp;gt;Max_Size, Max_Solidarity[root-&amp;gt;x.ID]);
        }
        DNode y = Split(root, k);
        Node *n = new Node(x);
        root = Merge(Merge(y.first, n), y.second);
    }
    void remove(data x)
    {
        int k = Rank(root, x);
        DNode a = Split(root, k);
        DNode b = Split(a.second, 1);
        delete b.first;
        root = Merge(a.first, b.second);
    }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;替罪羊树&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;namespace Scapegoat_Tree
{
    const int MAXN = 1e6 + 10;
    const double alpha = 0.756;
    struct Node
    {
        Node *ch[2];
        int key, s, cover;
        bool exist;
        void Pushup()
        {
            s = ch[0]-&amp;gt;s + ch[1]-&amp;gt;s + exist;
            cover = ch[0]-&amp;gt;cover + ch[1]-&amp;gt;cover + 1;
        }
        bool isBad()
        {
            return ((ch[0]-&amp;gt;cover &amp;gt; cover * alpha + 5) || (ch[1]-&amp;gt;cover &amp;gt; cover * alpha + 5));
        }
    };
    struct Stree 
    {
        Node mem_poor[MAXN];
        Node *tail, *root, *null, *ls[MAXN];
        Node *bc[MAXN]; int bc_top, top;
        Node *NewNode(int key)
        {
            Node *o = bc_top ? bc[--bc_top] : tail++;
            o-&amp;gt;ch[0] = o-&amp;gt;ch[1] = null;
            o-&amp;gt;s = o-&amp;gt;cover = o-&amp;gt;exist = 1;
            o-&amp;gt;key = key;
            return o;
        }
        void Travel(Node *rt)
        {
            if (rt == null) return;
            Travel(rt-&amp;gt;ch[0]);
            if (rt-&amp;gt;exist) ls[++top] = rt;
            else bc[bc_top++] = rt;
            Travel(rt-&amp;gt;ch[1]);
        }
        Node *Divide(int l, int r)
        {
            if (l &amp;gt; r) return null;
            int mid = (l + r) &amp;gt;&amp;gt; 1;
            Node *o = ls[mid];
            o-&amp;gt;ch[0] = Divide(l, mid - 1);
            o-&amp;gt;ch[1] = Divide(mid + 1, r);
            o-&amp;gt;Pushup();
            return o;
        }
        void ReBuild(Node *&amp;amp;rt)
        {
            top = 0;
            Travel(rt);
            rt = Divide(1, top);
        }
        Node ** Insert(Node *&amp;amp;rt, int val)
        {
            if (rt == null) 
            {
                rt = NewNode(val);
                return &amp;amp;null;
            }
            else
            {
                Node **res = Insert(rt-&amp;gt;ch[val &amp;gt;= rt-&amp;gt;key], val);
                rt-&amp;gt;Pushup();
                if (rt-&amp;gt;isBad()) res = &amp;amp;rt;
                return res;
            }
        }
        void erase(Node *rt, int id)
        {
            rt-&amp;gt;s--;
            int offset = rt-&amp;gt;ch[0]-&amp;gt;s + rt-&amp;gt;exist;
            if (rt-&amp;gt;exist &amp;amp;&amp;amp; id == offset)
            {
                rt-&amp;gt;exist = false;
                return;
            }
            else
            {
                if (id &amp;lt;= offset) erase(rt-&amp;gt;ch[0], id);
                else erase(rt-&amp;gt;ch[1], id - offset);
            }
        }
        Stree()
        {
            tail = mem_poor;
            null = tail++;
            null-&amp;gt;ch[0] = null-&amp;gt;ch[1] = null;
            null-&amp;gt;cover = null-&amp;gt;s = null-&amp;gt;key = 0;
            root = null; bc_top = 0;
        }
        void Insert(int val)
        {
            Node **rt = Insert(root, val);
            if (*rt != null) ReBuild(*rt);
        }
        int Rank(int val)
        {
            Node *rt = root;
            int ans = 1;
            while (rt != null)
            {
                if (rt-&amp;gt;key &amp;gt;= val) rt = rt-&amp;gt;ch[0];
                else
                {
                    ans += rt-&amp;gt;ch[0]-&amp;gt;s + rt-&amp;gt;exist;
                    rt = rt-&amp;gt;ch[1];
                }
            }
            return ans;
        }
        int Kth(int k)
        {
            Node *rt = root;
            while (rt != null)
            {
                if (rt-&amp;gt;ch[0]-&amp;gt;s + 1 == k &amp;amp;&amp;amp; rt-&amp;gt;exist) return rt-&amp;gt;key;
                else if (rt-&amp;gt;ch[0]-&amp;gt;s &amp;gt;= k) rt = rt-&amp;gt;ch[0];
                else k -= rt-&amp;gt;ch[0]-&amp;gt;s + rt-&amp;gt;exist, rt = rt-&amp;gt;ch[1];
            }
        }
        void erase(int k)
        {
            erase(root, Rank(k));
            if (root-&amp;gt;s &amp;lt; alpha * root-&amp;gt;cover) ReBuild(root);
        }
    };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;FFT&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;const int MAXN = 60005 &amp;lt;&amp;lt; 2;
const double pi = acos(-1.0);
#define Complex complex&amp;lt;double&amp;gt;
int r[MAXN], n;
Complex a[MAXN], b[MAXN];
void DFT(Complex *a, int f)
{
	for (int i = 0; i &amp;lt; n; i++)
		if (r[i] &amp;gt; i) swap(a[i], a[r[i]]);
	for (int i = 1; i &amp;lt; n; i &amp;lt;&amp;lt;= 1)
	{
		Complex wn(cos(pi / i), f * sin(pi / i));
		for (int j = 0; j &amp;lt; n; j += i &amp;lt;&amp;lt; 1)
		{
			Complex w = 1;
			for (int k = 0; k &amp;lt; i; k++, w *= wn)
			{
				Complex x = a[j + k], y = w * a[j + k + i];
				a[j + k] = x + y, a[j + k + i] = x - y;
			}
		}
	}
}
int c[MAXN], m;
void FFT(Complex *a, Complex *b)
{
	int l = 0;
	for (n = 1, m &amp;lt;&amp;lt;= 1; n &amp;lt; m; n &amp;lt;&amp;lt;= 1) ++l;
	for (int i = 0; i &amp;lt; n; i++) r[i] = (r[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | ((i &amp;amp; 1) &amp;lt;&amp;lt; (l - 1));
	DFT(a, 1), DFT(b, 1);
	for (int i = 0; i &amp;lt; n; i++) a[i] *= b[i];
	DFT(a, -1);
	for (int i = 0; i &amp;lt; n; i++) a[i] /= n;
	for (int i = 0; i &amp;lt; m; i++) c[i] = (int)(a[i].real() + 0.5);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;NTT&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;const int MAXN = 2e6;
const long long MOD = 998244353;
long long A[MAXN], B[MAXN], N;
long long Inv;
int rev[MAXN];
long long pow_mod(long long a, long long b, long long P) {
  long long ans = 1;
  while (b) {
    if (b &amp;amp; 1) ans = ans * a % P;
    b &amp;gt;&amp;gt;= 1;
    a = a * a % P;
  }
  return ans;
}
void FFt(long long *a, int op) {
  long long w, wn, t;
  for (int i = 0; i &amp;lt; N; i++)
    if (i &amp;lt; rev[i]) swap(a[i], a[rev[i]]);
  for (int k = 2; k &amp;lt;= N; k &amp;lt;&amp;lt;= 1) {
    wn = pow_mod(3, op == 1 ? (MOD - 1) / k : MOD - 1 - (MOD - 1) / k, MOD);
    for (int j = 0; j &amp;lt; N; j += k) {
      w = 1;
      for (int i = 0; i &amp;lt; (k &amp;gt;&amp;gt; 1); i++, w = w * wn % MOD) {
        t = a[i + j + (k &amp;gt;&amp;gt; 1)] * w % MOD;
        a[i + j + (k &amp;gt;&amp;gt; 1)] = (a[i + j] - t + MOD) % MOD;
        a[i + j] = (a[i + j] + t) % MOD;
      }
    }
  }
  if (op == -1)
    for (int i = 0; i &amp;lt; N; i++) a[i] = a[i] * Inv % MOD;
}
void FFt(const int *a, const int *b, int *res, int n) {
  N = 1;
  while (N &amp;lt; n) N &amp;lt;&amp;lt;= 1;
  Inv = pow_mod(N, MOD - 2, MOD);
  for (int i = 0; i &amp;lt; N; i++)
    if (i &amp;amp; 1)
      rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
    else
      rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
  for (int i = 0; i &amp;lt; N; i++) A[i] = a[i], B[i] = b[i];
  FFt(A, 1), FFt(B, 1);
  for (int i = 0; i &amp;lt; N; i++) A[i] = A[i] * B[i] % MOD;
  FFt(A, -1);
  for (int i = 0; i &amp;lt; N; i++) res[i] = A[i];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;树状数组&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;long long Sum[MAXN];
int Num[MAXN];
#define lowbit(_) ((_) &amp;amp; (-_))
void add(int x, int c) {
  for (int i = x; i &amp;lt;= cnt; i += lowbit(i)) Sum[i] += c, Num[i]++;
}
long long Query(int x) {
  long long ans = 0;
  for (int i = x; i &amp;gt; 0; i -= lowbit(i))
    ans += Sum[i];
  return ans;
}
int query(int x) {
  int ans = 0;
  for (int i = x; i &amp;gt; 0; i -= lowbit(i))
    ans += Num[i];
  return ans;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;线段树&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;const int N = 100005;
int Sum[N &amp;lt;&amp;lt; 2];
#define lch l, m, rt &amp;lt;&amp;lt; 1
#define rch m + 1, r, rt &amp;lt;&amp;lt; 1 | 1
void Pushup(int rt)
{
    Sum[rt] = Sum[rt &amp;lt;&amp;lt; 1] + Sum[rt &amp;lt;&amp;lt; 1 | 1]; 
}
void Update(int x, int c, int l, int r, int rt)
{
    if (l == r)
    {
        Sum[rt] = c;
        return;
    }
    int m = l + r &amp;gt;&amp;gt; 1;
    if (x &amp;lt;= m) Update(x, c, lch);
    else Update(x, c, rch);
    Pushup(rt);
}
void buildtree(int l, int r, int rt)
{
    if (l == r)
    {
        Sum[rt] = 1;
        return;
    }
    int m = l + r &amp;gt;&amp;gt; 1;
    buildtree(lch);
    buildtree(rch);
    Pushup(rt);
}
int find(int w, int l, int r, int rt)
{
    if (l == r)
        return l;
    int m = l + r &amp;gt;&amp;gt; 1;
    if (Sum[rt &amp;lt;&amp;lt; 1] &amp;gt;= w)
        return find(w, lch);
    else
        return find(w - Sum[rt &amp;lt;&amp;lt; 1], rch);
}
int Query(int w, int L, int R, int l, int r, int rt)
{
    if (L == l &amp;amp;&amp;amp; R == r)
    {
        if (Sum[rt] &amp;lt; w)
            return -Sum[rt];
        return find(w, l, r, rt);
    }
    int m = l + r &amp;gt;&amp;gt; 1;
    if (R &amp;lt;= m)
        return Query(w, L, R, lch);
    else if (L &amp;gt; m)
        return Query(w, L, R, rch);
    else
    {
        int s1 = Query(w, L, m, lch);
        if (s1 &amp;gt; 0) return s1;
        int s2 = Query(w + s1, m + 1, R, rch);
        if (s2 &amp;gt; 0) return s2;
        return s1 + s2;
    }    
}
int Query_Sum(int L, int R, int l, int r, int rt)
{
    if (L == l &amp;amp;&amp;amp; R == r)
        return Sum[rt];
    int m = l + r &amp;gt;&amp;gt; 1;
    if (R &amp;lt;= m)
        return Query_Sum(L, R, lch);
    if (L &amp;gt; m)
        return Query_Sum(L, R, rch);
    return Query_Sum(L, m, lch) + Query_Sum(m + 1, R, rch);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;并查集&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;int find(int x) {
  if (fa[x] != x) fa[x] = find(fa[x]);
  return fa[x];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;ST&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;int Max[(50005 &amp;lt;&amp;lt; 1) + 200][16], Min[(50005 &amp;lt;&amp;lt; 1) + 200][16];

int QueryMax(int l, int r)
{
    if (l &amp;gt; N || r &amp;lt; 0) return -0x3f3f3f3f;
    if (l &amp;lt;= 0) l = 1;
    if (r &amp;gt; N) r = N;
    int k = 0;
    while ((1 &amp;lt;&amp;lt; k) &amp;lt;= (r - l + 1)) k++; k--;
    return max(Max[l][k], Max[r - (1 &amp;lt;&amp;lt; k) + 1][k]);
}

int QueryMin(int l, int r)
{
    if (l &amp;gt; N || r &amp;lt; 0) return 0x3f3f3f3f;
    if (l &amp;lt;= 0) l = 1;
    if (r &amp;gt; N) r = N;
    int k = 0;
    while ((1 &amp;lt;&amp;lt; k) &amp;lt;= (r - l + 1)) k++; k--;
    return min(Min[l][k], Min[r - (1 &amp;lt;&amp;lt; k) + 1][k]);
}
int main () {
    for (int i = 1; i &amp;lt;= 15; i++)
        for (int j = 1; j &amp;lt;= N; j++)
        {
            Max[j][i] = max(Max[j][i - 1], Max[j + (1 &amp;lt;&amp;lt; (i - 1))][i - 1]);
            Min[j][i] = min(Min[j][i - 1], Min[j + (1 &amp;lt;&amp;lt; (i - 1))][i - 1]);
        }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;KD-Tree&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
  
using namespace std;
  
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
  
const int INF = 0x3f3f3f3f;
const double alpha = 0.756;
const int MAXN = 5e5 + 5;
  
int now;
  
struct Point
{
    int d[2];
    int &amp;amp;operator[](const int &amp;amp;x)
    {
        return d[x];
    }
    inline bool operator &amp;lt; (const Point &amp;amp;x) const
    {
        return d[now] == x.d[now] ? d[now ^ 1] &amp;lt; x.d[now ^ 1] : d[now] &amp;lt; x.d[now];
    }
}a[MAXN], cur;
  
#define dis(_, __) (\
    int(abs(_[0] - __[0]) + abs(_[1] - __[1]))\
)
  
#define size(_) ((_) ? (_)-&amp;gt;s : 0)
  
struct Node
{
    Node *ch[2];
    Point v;
    int s, d;
    int Max[2], Min[2];
    Node(Point x)
    {
        ch[0] = ch[1] = NULL;
        v = x;
        s = 1, d = now;
        Max[0] = Min[0] = x[0];
        Max[1] = Min[1] = x[1];
    }
    Node(){;}
    inline bool operator &amp;lt; (const Node &amp;amp;x) const
    {
        return v &amp;lt; x.v;
    }
    bool IsBad()
    {
        return ((size(ch[0]) &amp;gt; s * alpha) || (size(ch[1]) &amp;gt; s * alpha));
    }
    void Pushup(Node *x)
    {
        if (!x) return;
        for (int i = 0; i &amp;lt;= 1; i++) Min[i] = min(Min[i], x-&amp;gt;Min[i]);
        for (int i = 0; i &amp;lt;= 1; i++) Max[i] = max(Max[i], x-&amp;gt;Max[i]);
        s += x-&amp;gt;s;
    }
    int min_dis()
    {
        int ans = 0;
        ans += max(Min[0] - cur[0], 0) + max(cur[0] - Max[0], 0);
        ans += max(Min[1] - cur[1], 0) + max(cur[1] - Max[1], 0);
        return ans;
    }
}*root;
  
inline void Build(Node *&amp;amp;rt, int l, int r, int d = 0)
{
    if (l &amp;gt; r) return;
    int mid = l + r &amp;gt;&amp;gt; 1;
    now = d;
    nth_element(a + l, a + mid, a + r + 1);
    rt = new Node(a[mid]);
    Build(rt-&amp;gt;ch[0], l, mid - 1, d ^ 1);
    Build(rt-&amp;gt;ch[1], mid + 1, r, d ^ 1);
    rt-&amp;gt;s = 1;
    rt-&amp;gt;Pushup(rt-&amp;gt;ch[0]);
    rt-&amp;gt;Pushup(rt-&amp;gt;ch[1]);
}
  
Node **res;
  
inline void Insert(Node *&amp;amp;rt)
{
    if (rt == NULL)
    {
        rt = new Node(cur);
        res = NULL;
        return;
    }
    now = rt-&amp;gt;d;
    if (cur &amp;lt; rt-&amp;gt;v) Insert(rt-&amp;gt;ch[0]);
    else Insert(rt-&amp;gt;ch[1]);
    rt-&amp;gt;s = 1;
    rt-&amp;gt;Pushup(rt-&amp;gt;ch[0]);
    rt-&amp;gt;Pushup(rt-&amp;gt;ch[1]);
    if (rt-&amp;gt;IsBad()) res = &amp;amp;rt;
}
  
Node *st[MAXN &amp;lt;&amp;lt; 1];
int top = 0;
  
inline void Travel(Node *&amp;amp;rt)
{
    if (!rt) return;
    Travel(rt-&amp;gt;ch[0]);
    st[++top] = rt;
    Travel(rt-&amp;gt;ch[1]);
}
  
inline int cmp(const Node *x, const Node *y)
{
    return x-&amp;gt;v &amp;lt; y-&amp;gt;v;
}
  
inline Node *Divide(int l, int r, int d)
{
    if (l &amp;gt; r) return NULL;
    int mid = l + r &amp;gt;&amp;gt; 1;
    now = d;
    nth_element(st + l, st + mid, st + r + 1, cmp);
    Node *rt = st[mid];
    rt-&amp;gt;ch[0] = Divide(l, mid - 1, d ^ 1);
    rt-&amp;gt;ch[1] = Divide(mid + 1, r, d ^ 1);
    rt-&amp;gt;s = 1;
    rt-&amp;gt;Max[0] = rt-&amp;gt;Min[0] = rt-&amp;gt;v[0];
    rt-&amp;gt;Max[1] = rt-&amp;gt;Min[1] = rt-&amp;gt;v[1];
    rt-&amp;gt;Pushup(rt-&amp;gt;ch[0]);
    rt-&amp;gt;Pushup(rt-&amp;gt;ch[1]);
}
  
inline void ReBuild(Node *&amp;amp;rt)
{
    top = 0;
    int d = rt-&amp;gt;d;
    Travel(rt);
    rt = Divide(1, top, d);
}
  
inline void Insert(Point x)
{
    cur = x;
    Insert(root);
    if (res != NULL)
        ReBuild(*res);
}
  
int Min_ans;
  
inline void Query(Node *rt)
{
    if (!rt) return;
    // if (rt-&amp;gt;min_dis() &amp;gt; Min_ans) return;
    Min_ans = min(Min_ans, dis(rt-&amp;gt;v, cur));
    int dis_l = rt-&amp;gt;ch[0] ? rt-&amp;gt;ch[0]-&amp;gt;min_dis() : INF;
    int dis_r = rt-&amp;gt;ch[1] ? rt-&amp;gt;ch[1]-&amp;gt;min_dis() : INF;
    if (dis_l &amp;lt; dis_r)
    {
        Query(rt-&amp;gt;ch[0]);
        if (dis_r &amp;lt; Min_ans) Query(rt-&amp;gt;ch[1]);
    }
    else
    {
        Query(rt-&amp;gt;ch[1]);
        if (dis_l &amp;lt; Min_ans) Query(rt-&amp;gt;ch[0]);
    }
}
  
inline int Query(Point x)
{
    cur = x;
    Min_ans = INF;
    Query(root);
    return Min_ans;
}
  
int main()
{
    // freopen(&quot;1.in&quot;, &quot;r&quot;, stdin);
    // freopen(&quot;2.out&quot;, &quot;w&quot;, stdout);
    int n, m;
    n = read(), m = read();
    for (int i = 1; i &amp;lt;= n; i++)
        a[i][0] = read(), a[i][1] = read();
    Build(root, 1, n);
    Point x;
    while (m--)
    {
        int t = read();
        if (t == 1)
        {
            x[0] = read(), x[1] = read();
            Insert(x);
        }
        else
        {
            x[0] = read(), x[1] = read();
            printf (&quot;%d\n&quot;, Query(x));
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;LCT&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using namespace std;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
	while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
	return x*f;
}

const int MAXN = 10010;

struct Node
{
	Node *f, *ch[2];
	bool IsRoot, Mark;
	Node()
	{
		f = ch[0] = ch[1] = NULL;
		IsRoot = 1, Mark = 0;
	}
}*null, *Q[MAXN];
Node *NewNode()
{
	Node *o = new Node();
	o-&amp;gt;f = o-&amp;gt;ch[0] = o-&amp;gt;ch[1] = null;
	return o;
}
bool son(Node *rt)
{
	return rt-&amp;gt;f-&amp;gt;ch[1] == rt;
}
inline void Pushflip(Node *rt)
{
	if (rt == null) return;
	rt-&amp;gt;Mark ^= 1, swap(rt-&amp;gt;ch[0], rt-&amp;gt;ch[1]);
}
inline void Pushdown(Node *rt)
{
	if (rt-&amp;gt;Mark)
	{
		Pushflip(rt-&amp;gt;ch[0]);
		Pushflip(rt-&amp;gt;ch[1]);
		rt-&amp;gt;Mark = 0;
	}
}
inline void rotate(Node *rt)
{
	if (rt-&amp;gt;IsRoot) return;
	Node *fa = rt-&amp;gt;f, *Grand = fa-&amp;gt;f;
	Pushdown(fa), Pushdown(rt);
	int k = son(rt), kk = son(fa);
	fa-&amp;gt;ch[k] = rt-&amp;gt;ch[k ^ 1];
	if (rt-&amp;gt;ch[k ^ 1] != null) rt-&amp;gt;ch[k ^ 1]-&amp;gt;f = fa;
	rt-&amp;gt;ch[k ^ 1] = fa, fa-&amp;gt;f = rt, rt-&amp;gt;f = Grand;
	if (!fa-&amp;gt;IsRoot) Grand-&amp;gt;ch[kk] = rt;
	else fa-&amp;gt;IsRoot = 0, rt-&amp;gt;IsRoot = 1; 
}
inline void Clear(Node *rt)
{
	if (!rt-&amp;gt;IsRoot) Clear(rt-&amp;gt;f);
	Pushdown(rt);
}

inline void Splay(Node *rt)
{
	for (Clear(rt); !rt-&amp;gt;IsRoot; rotate(rt))
		if (!rt-&amp;gt;f-&amp;gt;IsRoot)
			rotate(son(rt) == son(rt-&amp;gt;f) ? rt-&amp;gt;f : rt);
}

inline void Access(Node *rt)
{
	for (Node *pre = null; rt != null; pre = rt, rt = rt-&amp;gt;f)
	{
		Splay(rt);
		rt-&amp;gt;ch[1]-&amp;gt;IsRoot = 1;
		pre-&amp;gt;IsRoot = 0;
		rt-&amp;gt;ch[1] = pre;
	}
}

inline void MakeRoot(Node *rt)
{
	Access(rt);
	Splay(rt);
	Pushflip(rt);
}

inline void link(Node *a, Node *b)
{
	MakeRoot(a);
	a-&amp;gt;f = b;
}

inline void cut(Node *a, Node *b)
{
	MakeRoot(a);
	Access(b);
	Splay(b);
	Pushdown(b);
	b-&amp;gt;ch[0]-&amp;gt;IsRoot = 1;
	b-&amp;gt;ch[0]-&amp;gt;f = null;
	b-&amp;gt;ch[0] = null;
}

inline Node* find(Node *rt)
{
	if (rt-&amp;gt;ch[0] != null) return find(rt-&amp;gt;ch[0]);
	return rt;
}

inline bool Judge(Node *a, Node *b)
{
	while (a-&amp;gt;f != null) a = a-&amp;gt;f;
	while (b-&amp;gt;f != null) b = b-&amp;gt;f;
	return a == b;
}

int main()
{
	int n = read(), m = read();
	null = new Node();
	null-&amp;gt;ch[0] = null-&amp;gt;ch[1] = null-&amp;gt;f = null, null-&amp;gt;IsRoot = null-&amp;gt;Mark = 0;
	for (int i = 1; i &amp;lt;= n; i++)
		Q[i] = NewNode();
	int a, b;
	char c[10];
	while (m--)
	{
		scanf (&quot;%s&quot;, c);
		if (c[0] == &apos;C&apos;)
		{
			a = read(), b = read();
			link(Q[a], Q[b]);
		}
		else if (c[0] == &apos;Q&apos;)
		{
			a = read(), b = read();
			puts(Judge(Q[a], Q[b]) ? &quot;Yes&quot; : &quot;No&quot;);
		}
		else
		{
			a = read(), b = read();
			cut(Q[a], Q[b]);
		}
	}
}

&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;Dijkstra&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
const int N = 1e6 + 1;
using namespace std;
struct edge {
  int END, next, v;
} v[N * 2];
int first[N], p;
void add(int a, int b, int c) {
  v[p].END = b;
  v[p].v = c;
  v[p].next = first[a];
  first[a] = p++;
}
int n, m, S;
typedef pair&amp;lt;int, int&amp;gt; T;
int dis[N];
int main() {
  scanf(&quot;%d%d%d&quot;, &amp;amp;n, &amp;amp;m, &amp;amp;S);
	memset (first, -1, sizeof (first));
  for (int i = 1; i &amp;lt;= m; i++) {
    int x, y, z;
    scanf(&quot;%d%d%d&quot;, &amp;amp;x, &amp;amp;y, &amp;amp;z);
    add(x, y, z);
  }
  memset(dis, 0x3f, sizeof(dis));
  dis[S] = 0;
  T X;
  X.first = 0, X.second = S;
  priority_queue&amp;lt;T, vector&amp;lt;T&amp;gt;, greater&amp;lt;T&amp;gt; &amp;gt; Q;
  Q.push(X);
  while (!Q.empty()) {
    X = Q.top();
    Q.pop();
    int x = X.second;
    if (dis[x] &amp;lt; X.first) continue;
    for (int i = first[x]; i; i = v[i].next) {
      int y = v[i].END;
      if (dis[y] &amp;gt; dis[x] + v[i].v) {
        dis[y] = dis[x] + v[i].v;
        X.first = dis[y];
        X.second = y;
        Q.push(X);
      }
    }
  }
  for (int i = 1; i &amp;lt;= n; i++) printf(&quot;%d &quot;, dis[i]);
  return 0;
}

&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;SPFA&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;int dis[N];
bool flag[N];
queue&amp;lt;int&amp;gt; q;
bool Spfa(int x)
{
	memset(dis, 0x3f, sizeof (dis));
	memset(flag, 0, sizeof (flag));
	dis[x] = 0;
	flag[x] = 1;
	q.push(x);
	while (!q.empty())
	{
		int k = q.front();
		q.pop();
		flag[k] = 0;
		for (int i = first[k]; i != -1; i = v[i].next)
		{
			if (dis[v[i].END] &amp;gt; dis[k] + v[i].v)
			{
				dis[v[i].END] = dis[k] + v[i].v;
				if (!flag[v[i].END])
				{
					flag[v[i].END] = 1;
					q.push(v[i].END);
				}
			}
		}
	}
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;多项式&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
const int MAXN = 1e6 * 4;
const int MOD  = 998244353;
const int L = (1 &amp;lt;&amp;lt; 18) + 1;
const int LM = (1 &amp;lt;&amp;lt; 16) + 1;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
int N, Inv, rev[MAXN];
int Sum = 0, n, m;
struct data
{
    int e, f, g, id;
}s[60005];
long long pow_mod(long long a, int b)
{
    long long ans = 1;
    while (b)
    {
        if (b &amp;amp; 1)
            ans = ans * a % MOD;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % MOD;
    }
    return ans;
}
int ans[MAXN], cnt;
void insert(int a, int b, int c, int d, int id)
{
    if (b == 0)
    {
        ans[id] = ((1ll * a * Sum) + (1ll * c * n)) % MOD * pow_mod(d, MOD - 2) % MOD;
        return;
    }
    s[++cnt].f = (1ll * b * c - 1ll * a * d) % MOD;
    b = pow_mod(b, MOD - 2);
    s[cnt].e = 1ll * a * b % MOD, s[cnt].g = 1ll * d * b % MOD;
    b = 1ll * b * b % MOD; s[cnt].f = 1ll * s[cnt].f * b % MOD;
    if (s[cnt].f &amp;lt; 0) s[cnt].f += MOD;
    s[cnt].id = id;
}
void Init(int x)
{
    N = 1;
    while (N &amp;lt; (x &amp;lt;&amp;lt; 1)) N &amp;lt;&amp;lt;= 1;
    Inv = pow_mod(N, MOD - 2);
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
}
inline int Calc(int x)
{
    N = 1;
    while (N &amp;lt; (x &amp;lt;&amp;lt; 1)) N &amp;lt;&amp;lt;= 1;
    return N;
}
void FFt(int *a, int op)
{
    int w, wn, t;
    for (int i = 0; i &amp;lt; N; i++)
        if (i &amp;lt; rev[i])
            swap(a[i], a[rev[i]]);
    for (int k = 2; k &amp;lt;= N; k &amp;lt;&amp;lt;= 1)
    {
        wn = pow_mod(3, op == 1 ? (MOD - 1) / k : MOD - 1 - (MOD - 1) / k);
        for (int j = 0; j &amp;lt; N; j += k)
        {
            w = 1;
            for (int i = 0; i &amp;lt; (k &amp;gt;&amp;gt; 1); i++, w = 1ll * w * wn % MOD)
            {
                t = 1ll * a[i + j + (k &amp;gt;&amp;gt; 1)] * w % MOD;
                a[i + j + (k &amp;gt;&amp;gt; 1)] = (a[i + j] - t + MOD) % MOD;
                a[i + j] = (a[i + j] + t) % MOD;
            }
        }
    }
    if (op == -1)
        for (int i = 0; i &amp;lt; N; i++)
            a[i] = 1ll * a[i] * Inv % MOD;
}
int tmp[MAXN], x[MAXN];
void Get_Inv(int *a, int *b, int n)
{
    if (n == 1) return b[0] = pow_mod(a[0], MOD - 2), void();
    Get_Inv(a, b, n + 1 &amp;gt;&amp;gt; 1);
    Init(n);
    for (int i = 0; i &amp;lt; n; i++) tmp[i] = a[i];
    for (int i = n; i &amp;lt; N; i++) tmp[i] = 0;
    FFt(tmp, 1), FFt(b, 1);
    for (int i = 0; i &amp;lt; N; i++) 
        b[i] = 1ll * b[i] * ((2 - 1ll * b[i] * tmp[i] % MOD + MOD) % MOD) % MOD;
    FFt(b, -1);
    for (int i = n; i &amp;lt; N; i++) b[i] = 0;
}
int Get_mod(int *a, int ra, int *b, int rb, int *c)
{
    while (ra &amp;amp;&amp;amp; !a[ra - 1]) --ra;
    while (rb &amp;amp;&amp;amp; !b[rb - 1]) --rb;
    if (ra &amp;lt; rb)
    {
        memcpy (c, a, ra &amp;lt;&amp;lt; 2);
        memset (c + ra, 0, (rb - ra) &amp;lt;&amp;lt; 2);
        return rb;
    }
    static int tmp1[MAXN], tmp2[MAXN];
    int rc = ra - rb + 1;
    int l = Calc(rc);
    for (int i = 0; i &amp;lt; l; i++) tmp1[i] = 0;
    reverse_copy(b, b + rb, tmp1);
    for (int i = 0; i &amp;lt; l; i++) tmp2[i] = 0; 
    Get_Inv(tmp1, tmp2, rc);
    for (int i = rc; i &amp;lt; l; i++) tmp2[i] = 0;
    reverse_copy(a, a + ra, tmp1);
    for (int i = rc; i &amp;lt; l; i++) tmp1[i] = 0;
    Init(rc), FFt(tmp1, 1), FFt(tmp2, 1);
    for (int i = 0; i &amp;lt; N; i++) tmp1[i] = 1ll * tmp1[i] * tmp2[i] % MOD;
    FFt(tmp1, -1); 
    reverse(tmp1, tmp1 + rc); 
    Init(ra);
    for (int i = 0; i &amp;lt; rb; i++) tmp2[i] = b[i];
    for (int i = rb; i &amp;lt; N; i++) tmp2[i] = 0;
    for (int i = rc; i &amp;lt; N; i++) tmp1[i] = 0;
    FFt(tmp1, 1), FFt(tmp2, 1);
    for (int i = 0; i &amp;lt; N; i++) tmp1[i] = 1ll * tmp1[i] * tmp2[i] % MOD;
    FFt(tmp1, -1);
    for (int i = 0; i &amp;lt; rb; i++) c[i] = (a[i] - tmp1[i] + MOD) % MOD;
    for (int i = rb; i &amp;lt; N; i++) c[i] = 0;
    while (rb &amp;amp;&amp;amp; !c[rb - 1]) --rb;
    return rb;
}
int Solve0(int *a, int l, int r)
{
    int ra = r - l + 2;
    if (ra &amp;lt;= 256)
    {
        memset(a, 0, ra &amp;lt;&amp;lt; 2), a[0] = 1;
        for (int i = l; i &amp;lt;= r; i++)
            for (int v = x[i], j = i - l; j != -1; j--)
            {
                a[j + 1] = (a[j + 1] + a[j]) % MOD;
                a[j] = 1ll * a[j] * v % MOD;
            }
        return ra;
    }
    int mid = l + r &amp;gt;&amp;gt; 1;
    int *f1 = a, r1 = Solve0(f1, l, mid);
    int *f2 = a + r1, r2 = Solve0(f2, mid + 1, r);
    N = 1;
    while (N &amp;lt; ra) N &amp;lt;&amp;lt;= 1;
    Inv = pow_mod(N, MOD - 2);
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    static int tmp1[L], tmp2[L];
    memcpy(tmp1, f1, r1 &amp;lt;&amp;lt; 2), memset (tmp1 + r1, 0, (N - r1) &amp;lt;&amp;lt; 2), FFt(tmp1, 1);
    memcpy(tmp2, f2, r2 &amp;lt;&amp;lt; 2), memset (tmp2 + r2, 0, (N - r2) &amp;lt;&amp;lt; 2), FFt(tmp2, 1);
    for (int i = 0; i &amp;lt; N; i++) a[i] = 1ll * tmp1[i] * tmp2[i] % MOD;
    FFt(a, -1);
    return ra;
}
int *p[L];
int sta[MAXN];
int mem[LM &amp;lt;&amp;lt; 4], *head = mem;
inline int Solve1(int id, int l, int r)
{
    int ra = r - l + 2;
    if (ra &amp;lt;= 256)
    {
        int *f = p[id] = head; head += ra;
        memset (f, 0, ra &amp;lt;&amp;lt; 2), 0[f] = 1;
        for (int i = l; i &amp;lt;= r; i++)
            for (int v = (MOD - sta[i]) % MOD, j = i - l; j != -1; j--)
                f[j + 1] = (f[j + 1] + f[j]) % MOD, f[j] = 1ll * f[j] * v % MOD;
        return ra;
    }
    int mid = l + r &amp;gt;&amp;gt; 1;
    int r1 = Solve1(id &amp;lt;&amp;lt; 1, l, mid), *f1 = p[id &amp;lt;&amp;lt; 1];
    int r2 = Solve1(id &amp;lt;&amp;lt; 1 | 1, mid + 1, r), *f2 = p[id &amp;lt;&amp;lt; 1 | 1];
    N = 1;
    while (N &amp;lt; ra) N &amp;lt;&amp;lt;= 1;
    Inv = pow_mod(N, MOD - 2);
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    static int tmp1[LM], tmp2[LM];
    memcpy(tmp1, f1, r1 &amp;lt;&amp;lt; 2), memset (tmp1 + r1, 0, (N - r1) &amp;lt;&amp;lt; 2), FFt(tmp1, 1);
    memcpy(tmp2, f2, r2 &amp;lt;&amp;lt; 2), memset (tmp2 + r2, 0, (N - r2) &amp;lt;&amp;lt; 2), FFt(tmp2, 1);
    int *f = p[id] = head; head += ra;
    for (int i = 0; i &amp;lt; N; i++) f[i] = 1ll * tmp1[i] * tmp2[i] % MOD;
    FFt(f, -1);
    return ra; 
}
int val0[LM], val[LM];
void Solve2(int id, int *a, int *b, int l, int r, int deg)
{
    int ra = r - l + 2;
    if (deg &amp;lt;= 256)
    {
        int F, G;
        for (int i = l; i &amp;lt;= r; i++)
        {
            F = G = 0;
            int u = sta[i], v = 1;
            for (int j = 0; j &amp;lt;= deg; j++)
            {
                F = (F + 1ll * v * a[j]) % MOD;
                G = (G + 1ll * v * b[j]) % MOD;
                v = 1ll * v * u % MOD;
            }
            val0[i] = F, val[i] = G;
        }
        return;
    }
    int mid = l + r &amp;gt;&amp;gt; 1;
    int r1 = Get_mod(a, deg, p[id], ra, a + deg); a += deg;
    int r2 = Get_mod(b, deg, p[id], ra, b + deg); b += deg;
    ra = min(r1, r2);
    Solve2(id &amp;lt;&amp;lt; 1, a, b, l, mid, ra), Solve2(id &amp;lt;&amp;lt; 1 | 1, a, b, mid + 1, r, ra);
}
int g[MAXN], h[MAXN];
int main()
{
    n = read(), m = read();
    Sum = 0;
    for (int i = 1; i &amp;lt;= n; i++)
        x[i] = read() % MOD, Sum = (Sum + x[i]) % MOD;
    int A = 1, B = 0, C = 0, D = 1;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        if (read() == 1)
        {
            int v = read() % MOD;
            A = (A + 1ll * v * B % MOD) % MOD;
            C = (C + 1ll * v * D % MOD) % MOD;
            insert(A, B, C, D, i);
        }
        else
        {
            swap(A, B);
            swap(C, D);
            insert(A, B, C, D, i);
        }
    }
    if (cnt)
    {
        for (int i = 1; i &amp;lt;= cnt; i++) sta[i] = s[i].g;
        sort(sta + 1, sta + cnt + 1);
        int lenth = unique(sta + 1, sta + cnt + 1) - sta - 1;
        for (int i = 1; i &amp;lt;= cnt; i++)
            s[i].g = lower_bound(sta + 1, sta + lenth + 1, s[i].g) - sta;
        Solve0(g, 1, n);
        for (int i = 1; i &amp;lt;= n; i++) h[i - 1] = 1ll * g[i] * i % MOD;
        Solve1(1, 1, lenth);
        Solve2(1, g, h, 1, lenth, n + 1);
        for (int i = 1; i &amp;lt;= cnt; i++)
            ans[s[i].id] = (1ll * s[i].e * n % MOD + 1ll * s[i].f * val[s[i].g] % MOD * pow_mod(val0[s[i].g], MOD - 2) % MOD) % MOD;
    }
    for (int i = 1; i &amp;lt;= m; i++)
        printf (&quot;%d\n&quot;, ans[i]);
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;高斯消元&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;long long gauss(int n)
{
    long long ans = 1;
    for (int i = 1; i &amp;lt;= n; i++)
        for (int j = 1; j &amp;lt;= n; j++)
            a[i][j] = (a[i][j] + MOD) % MOD;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        for (int j = i + 1; j &amp;lt;= n; j++)
            while (a[j][i])
            {
                int t = a[i][i] / a[j][i];
                for (int k = i; k &amp;lt;= n; k++)
                {
                    a[i][k] = (a[i][k] - a[j][k] * t % MOD + MOD) % MOD;
                    swap(a[i][k], a[j][k]);
                }
                ans = (MOD - ans) % MOD;
            }
        ans = ans * a[i][i] % MOD;
    }
    return ans;
}



void gauss() {
  int im, num = 1;
  for (int k = 1; k &amp;lt;= n; k++, num++) {
    im = k;
    for (int i = k + 1; i &amp;lt;= n; i++) {
      if (fabs(a[i][k]) &amp;gt; fabs(a[im][k])) i = im;
    }
    if (im != k) {
      for (int i = k; i &amp;lt;= n + 1; i++) swap(a[num][i], a[im][i]);
    }
    if (!a[num][k]) {
      num--;
      continue;
    }
    for (int i = num + 1; i &amp;lt;= n; i++) {
      if (!a[num][k]) continue;
      long double t = a[i][k] / a[num][k];
      for (int j = k; j &amp;lt;= n + 1; j++) {
        a[i][j] -= t * a[k][j];
      }
    }
  }
  for (int i = n; i &amp;gt;= 1; i--) {
    for (int j = n; j &amp;gt;= i + 1; j--) {
      a[i][n + 1] -= a[i][j] * x[j];
    }
    x[i] = a[i][n + 1] / a[i][i];
    sum += x[i];
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;BSGS&amp;amp;exBSGS&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;int pow_mod(int a, int b, int c)
{
    int ans = 1;
    while (b)
    {
        if (b &amp;amp; 1) ans = ans * a % c;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % c;
    }
    return ans;
}
struct Hash_Table
{
    struct edge
    {
        int next, x, ans;
    }v[100005];
    int first[76545], p;
    int &amp;amp;operator[](int x)
    {
        int H = x % 76543;
        for (int i = first[H]; i != -1; i = v[i].next)
            if (v[i].x == x)
                return v[i].ans;
        v[p].x = x;
        v[p].next = first[H];
        first[H] = p++;
        return v[p - 1].ans = 0;
    }
    bool count(int x)
    {
        int H = x % 76543;
        for (int i = first[H]; i != -1; i = v[i].next)
            if (v[i].x == x)
                return 1;
        return 0;
    }
    void clear()
    {
        memset (first, -1, sizeof (first));
        p = 0;
    }
}Hash;
int gcd(int a, int b)
{
    return b == 0 ? a : gcd(b, a % b);
}
int BSGS(int a, int b, int c, int d)
{
    Hash.clear();
    int m = floor(sqrt(c)) + 1;
    for (int i = 0; i &amp;lt;= m; i++)
    {
        // if (!Hash.count(b)) 
        Hash[b] = i;
        b = b * a % c;
    }
    int s = pow_mod(a, m, c);
    for (int i = 1; i &amp;lt;= m; i++)
    {
        d = d * s % c;
        if (Hash.count(d)) return i * m - Hash[d];
    }
    return -1;
}
int exBSGS(int a, int b, int c)
{
    b %= c;
    int s = 1;
    for (int i = !a; i &amp;lt;= 40; i++)
    {
        if (s == b) return i;
        s = s * a % c;
    }
    int cnt = 0, d = 1;
    for (int i; (i = gcd(a, c)) != 1; cnt++)
    {
        if (b % i) return -1;
        b /= i, c /= i;
        d = d * a / i % c;
    }
    int ret = BSGS(a, b, c, d);
    if (ret == -1) return -1;
    return ret + cnt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;KMP&amp;amp;EXKMP&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;long long nxt[MAXN], pre[MAXN], extend[MAXN];
char w[MAXN], t[MAXN];
void KMP(char *s, int n) {
  for (int i = 2, k; i &amp;lt;= n; i++) {
    k = nxt[i - 1];
    while (k &amp;amp;&amp;amp; s[i] != s[k + 1]) k = nxt[k];
    if (s[i] == s[k + 1]) nxt[i] = k + 1;
    else nxt[i] = 0;
  }
}
void Get_Extend(char *s, int n) {
  pre[1] = n;
  pre[2] = 1;
  while (s[pre[2]] == s[pre[2] + 1] &amp;amp;&amp;amp; pre[2] + 1 &amp;lt;= n) pre[2]++;
  pre[2]--;
  int P_pos = 2;
  for (int i = 3; i &amp;lt;= n; i++) {
    if (pre[i - P_pos + 1] + i &amp;lt; pre[P_pos] + P_pos) pre[i] = pre[i - P_pos + 1];
    else {
      pre[i] = pre[P_pos] + P_pos - i;
      if (pre[i] &amp;lt; 0) pre[i] = 0;
      while (s[pre[i] + 1] == s[pre[i] + i] &amp;amp;&amp;amp; i + pre[i] &amp;lt;= n) pre[i]++;
      P_pos = i;
    }
  }
}
void Match(char *s, char *t) {
  int m = strlen(s + 1), n = strlen(t);
  Get_Extend(t, n);
  extend[1] = 1;
  while (s[extend[1]] == t[extend[1]] &amp;amp;&amp;amp; extend[1] &amp;lt;= n) extend[1]++;
  extend[1]--;
  int P_pos = 1;
  for (int i = 2; i &amp;lt;= m; i++) {
    if (pre[i - P_pos + 1] + i &amp;lt; extend[P_pos] + P_pos) extend[i] = pre[i - P_pos + 1];
    else {
      extend[i] = P_pos + extend[P_pos] - i;
      if (extend[i] &amp;lt; 0) extend[i] = 0;
      while (t[extend[i] + 1] == s[i + extend[i]] &amp;amp;&amp;amp; i + extend[i] &amp;lt;= m &amp;amp;&amp;amp; extend[i] &amp;lt;= n) extend[i]++;
      P_pos = i;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;线性筛&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;const int MAXN = 50000;
int prime[MAXN + 2], mu[MAXN + 2], Sum_mu[MAXN + 2], d[MAXN + 2], e[MAXN + 2], cnt;
long long Sum_d[MAXN + 2];
bool isnprime[MAXN + 2];
void Get_d()
{
    mu[1] = 1, d[1] = 1, isnprime[1] = 1;
    for (int i = 2; i &amp;lt;= MAXN; i++)
    {
        if (!isnprime[i])
        {
            prime[++cnt] = i;
            e[i] = 1;
            d[i] = 2;
            mu[i] = -1;
        }
        for (int j = 1; j &amp;lt;= cnt; j++)
        {
            if (i * prime[j] &amp;gt; MAXN) break;
            isnprime[i * prime[j]] = 1;
            if (i % prime[j] == 0)
            {
                mu[i * prime[j]] = 0;
                d[i * prime[j]] = d[i] / (e[i] + 1) * (e[i] + 2);
                e[i * prime[j]] = e[i] + 1; 
                break;
            }
            mu[i * prime[j]] = -mu[i];
            d[i * prime[j]] = d[i] * 2;
            e[i * prime[j]] = 1;
        }
    }
    for (int i = 1; i &amp;lt;= MAXN; i++)
    {
        Sum_mu[i] = Sum_mu[i - 1] + mu[i];
        Sum_d[i] = Sum_d[i - 1] + d[i];
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;杜教筛&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
struct Hash_Table {
  struct edge {
    long long x;
    int ans, next;
  }v[100005];
  int first[76545], p;
  Hash_Table() {
    memset (first, -1, sizeof (first));
    p = 0;
  }
  int &amp;amp;operator[] (const long long &amp;amp;x) {
    int H = x % 76543;
    for (int i = first[H]; i != -1; i = v[i].next) {
      if (v[i].x == x)
        return v[i].ans;
    }
    v[p].x= x;
    v[p].next = first[H];
    first[H] = p++;
    return v[p - 1].ans = 0;
  }
  bool count(const long long &amp;amp;x) {
    int H = x % 76543;
    for (int i = first[H]; i != -1; i = v[i].next) {
      if (v[i].x == x)
        return 1;
    }
    return 0;
  }
}mp;
const int MAXN = 1e6;
bool isnprime[MAXN + 5];
int mu[MAXN + 5], prime[MAXN + 5], cnt;
void Get_Prime() {
  mu[1] = 1, isnprime[1] = 1;
  for (int i = 2; i &amp;lt;= MAXN; i++) {
    if (!isnprime[i]) prime[++cnt] = i, mu[i] = -1;
    for (int j = 1; j &amp;lt;= cnt; j++) {
      if (i * prime[j] &amp;gt; MAXN) break;
      isnprime[i * prime[j]] = 1;
      if (i % prime[j] == 0) {
        mu[i * prime[j]] = 0;
        break;
      } else {
        mu[i * prime[j]] = -mu[i];
      }
    }
  }
  for (int i = 1; i &amp;lt;= MAXN; i++)
    mu[i] += mu[i - 1];
}
int Mu(long long x) {
  if (x &amp;lt;= MAXN) return mu[x];
  if (mp.count(x)) return mp[x];
  int &amp;amp;ans = mp[x] = 1;
  long long nxt = 1;
  for (long long i = 2; i &amp;lt;= x; i = nxt + 1) {
    nxt = x / (x / i);
    ans -= (nxt - i + 1) * Mu(x / i);
  }
  return ans;
}
int main() {
  Get_Prime();
  long long a, b;
  cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;
  cout &amp;lt;&amp;lt; Mu(b) - Mu(a - 1) &amp;lt;&amp;lt; endl;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;Miller_Robin&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;long long tmp[100];
int tot;
int prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
long long mul(long long a, long long b, long long z) {
  return (a * b - (long long)(((long double)a * b + 0.5) / (long double)z) * z + z) % z;
}
long long pow_mod(long long a, long long b, long long p) {
  a %= p;
  long long ans = 1;
  while (b) {
    if (b &amp;amp; 1) ans = mul(ans, a, p);
    b &amp;gt;&amp;gt;= 1;
    a = mul(a, a, p);
  }
  return ans;
}
bool Miller_Rabin(long long x) {
  if (x == 1) return 0;
  for (int i = 0; i &amp;lt;= 9; ++i) {
    if (x == prime[i]) return 1;
    if (x % prime[i] == 0) return 0;
  }
  long long y = x - 1;
  int k = 0;
  for (; !(y &amp;amp; 1); y &amp;gt;&amp;gt;= 1) k++;
  for (int i = 0; i &amp;lt; 10; ++i) {
    long long z = rand() % (x - 1) + 1;
    long long c = pow_mod(z, y, x), d;
    for (int j = 0; j &amp;lt; k; ++j, c = d)
      if ((d = mul(c, c, x)) == 1 &amp;amp;&amp;amp; c != 1 &amp;amp;&amp;amp; c != x - 1)
        return 0;
    if (d != 1) return 0;
  }
  return 1;
}
long long Pollard_Rho(long long x, int y) {
  long long i = 1, k = 2, c = rand() % (x - 1) + 1;
  long long d = c;
  while (1) {
    i++;
    c = (mul(c, c, x) + y) % x;
    long long g = __gcd((d - c + x) % x, x);
    if (g != 1 &amp;amp;&amp;amp; g != x) return g;
    if (c == d) return x;
    if (i == k) d = c, k &amp;lt;&amp;lt;= 1;
  }
}
void Divide(long long x, int c) {
  if (x == 1) return;
  if (Miller_Rabin(x)) return tmp[++tot] = x, void();
  long long z = x, tp = c;
  while (z &amp;gt;= x) z = Pollard_Rho(z, c--);
  Divide(z, tp), Divide(x / z, tp);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>小米手环3 NFC 体验</title><link>https://www.nekomio.com/posts/153/</link><guid isPermaLink="true">https://www.nekomio.com/posts/153/</guid><pubDate>Mon, 17 Jun 2019 14:04:09 GMT</pubDate><content:encoded>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;昨天在网上看到手环3打折了，而且我也不想要手环4.&lt;br /&gt;
&lt;img src=&quot;https://file.nekomio.com/picgo/1649775532912-153-2.webp&quot; alt=&quot;&quot; /&gt;
所以就立刻下单买了个 小米手环3NFC 版，今天早上就送到了。&lt;/p&gt;
&lt;p&gt;然后就是立即打开包装
&lt;img src=&quot;https://file.nekomio.com/picgo/1649775538961-153-4.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;好像没电。。。&lt;/p&gt;
&lt;p&gt;先充电，充电的时候顺便用手机更新了一下。&lt;br /&gt;
一切OK
&lt;img src=&quot;https://file.nekomio.com/picgo/1649775536019-153-3.webp&quot; alt=&quot;&quot; /&gt;
感觉还不错（蓝色是照片的缘故）。&lt;/p&gt;
&lt;p&gt;然后就是用了， 心率挺准。&lt;br /&gt;
其他的还没测。&lt;br /&gt;
以后再也不用担心走路没带手机记不上步了 :) 。&lt;/p&gt;
</content:encoded></item><item><title>【NOI2017】游戏 2-SAT</title><link>https://www.nekomio.com/posts/152/</link><guid isPermaLink="true">https://www.nekomio.com/posts/152/</guid><pubDate>Fri, 29 Jun 2018 08:02:09 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;小 L 计划进行 $n$ 场游戏，每场游戏使用一张地图，小 L 会选择一辆车在该地图上完成游戏。&lt;/p&gt;
&lt;p&gt;小 L 的赛车有三辆，分别用大写字母 $A$、$B$、$C$ 表示。地图一共有四种，分别用小写字母 $x$、$a$、$b$、$c$ 表示。&lt;/p&gt;
&lt;p&gt;其中，赛车 $A$ 不适合在地图 $a$ 上使用，赛车 $B$ 不适合在地图 $b$ 上使用，赛车 $C$ 不适合在地图 $c$ 上使用，而地图 $x$ 则适合所有赛车参加。&lt;/p&gt;
&lt;p&gt;适合所有赛车参加的地图并不多见，最多只会有 $d$ 张。&lt;/p&gt;
&lt;p&gt;$n$ 场游戏的地图可以用一个小写字母组成的字符串描述。例如：$S=\texttt{xaabxcbc}$ 表示小L计划进行 $8$ 场游戏，其中第 $1$ 场和第 $5$ 场的地图类型是 $x$，适合所有赛车，第 $2$场和第 $3$ 场的地图是 $a$，不适合赛车 $A$，第 $4$ 场和第 $7$ 场的地图是 $b$，不适合赛车 $B$，第 $6$ 场和第 $8$ 场的地图是 $c$，不适合赛车 $C$。&lt;/p&gt;
&lt;p&gt;小 L 对游戏有一些特殊的要求，这些要求可以用四元组 $ (i, h_i, j, h_j) $ 来描述，表示若在第 $i$ 场使用型号为 $h_i$ 的车子，则第 $j$ 场游戏要使用型号为 $h_j$ 的车子。&lt;/p&gt;
&lt;p&gt;你能帮小 L 选择每场游戏使用的赛车吗？如果有多种方案，输出任意一种方案。&lt;/p&gt;
&lt;p&gt;如果无解，输出 &lt;code&gt;-1&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;输入格式&lt;/h3&gt;
&lt;p&gt;输入第一行包含两个非负整数 $n$, $d$。&lt;/p&gt;
&lt;p&gt;输入第二行为一个字符串 $S$。&lt;/p&gt;
&lt;p&gt;$n$, $d$, $S$ 的含义见题目描述，其中 $S$ 包含 $n$ 个字符，且其中恰好 $d$ 个为小写字母 $x$。&lt;/p&gt;
&lt;p&gt;输入第三行为一个正整数 $m$ ，表示有 $m$ 条用车规则。&lt;/p&gt;
&lt;p&gt;接下来 $m$ 行，每行包含一个四元组 $i,h_i,j,h_j$ ，其中 $i,j$ 为整数，$h_i,h_j$ 为字符 $A$ 、$B$ 或 $C$，含义见题目描述。&lt;/p&gt;
&lt;h3&gt;输出格式&lt;/h3&gt;
&lt;p&gt;输出一行。&lt;/p&gt;
&lt;p&gt;若无解输出 &lt;code&gt;-1&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;样例&lt;/h3&gt;
&lt;h4&gt;样例输入&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;3 1
xcc
1
1 A 2 B
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;样例输出&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;ABA
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;小 $L$ 计划进行 $3$ 场游戏，其中第 $1$ 场的地图类型是 $x$，适合所有赛车，第 $2$ 场和第 $3$ 场的地图是 $c$，不适合赛车 $C$。&lt;/p&gt;
&lt;p&gt;小 $L$ 希望：若第 $1$ 场游戏使用赛车 $A$，则第 $2$ 场游戏使用赛车 $B$。&lt;/p&gt;
&lt;p&gt;那么为这 $3$ 场游戏分别安排赛车 $A$、$B$、$A$ 可以满足所有条件。&lt;/p&gt;
&lt;p&gt;若依次为 $3$ 场游戏安排赛车为 $BBB$ 或 $BAA$ 时，也可以满足所有条件，也被视为正确答案。&lt;/p&gt;
&lt;p&gt;但依次安排赛车为 $AAB$ 或 $ABC$ 时，因为不能满足所有条件，所以不被视为正确答案。&lt;/p&gt;
&lt;h3&gt;数据范围与提示&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2018/03/12/5aa65404270cd.png&quot; alt=&quot;Screen Shot 2018-03-12 at 23.17.17.png&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;2-SAT&lt;/p&gt;
&lt;p&gt;上来看这到题。&lt;br /&gt;
感到 $a,b,c$ 的时候很好搞， 但是不知道 $x$ 怎么办。&lt;br /&gt;
$a, b, c$ 的时候是2-SAT， 那 $x$ 不就是 3-SAT 了么。&lt;br /&gt;
这是NPC问题啊。&lt;/p&gt;
&lt;p&gt;之后看来一下数据范围， $x \le 8$ 发现 $x$ 可以枚举。 然后就是一个裸的2-SAT了。&lt;/p&gt;
&lt;h3&gt;2-SAT 输出方案&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Tarjan&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Tarjan缩点时会给联通块编号&lt;/p&gt;
&lt;p&gt;对于一对相互对立的问题，谁的新编号小就选谁。&lt;/p&gt;
&lt;p&gt;简单清真， 不用去跑什么 &lt;em&gt;反图+拓扑排序&lt;/em&gt; 了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#pragma GCC optimize(&quot;O3&quot;)
#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
inline int read() {
  int x = 0, f = 1;
  char ch = getchar();
  while (ch &amp;lt; &apos;0&apos; || ch &amp;gt; &apos;9&apos;) {
    if (ch == &apos;-&apos;) f = -1;
    ch = getchar();
  }
  while (ch &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; ch &amp;lt;= &apos;9&apos;) {
    x = x * 10 + ch - &apos;0&apos;;
    ch = getchar();
  }
  return x * f;
}
const int MAXN = 50005;
const int MAXM = 100005;
struct data {
  int i, hi, j, hj;
} D[MAXM];
struct edge {
  int END, next;
} v[MAXM &amp;lt;&amp;lt; 2];
int first[MAXN &amp;lt;&amp;lt; 1], p;
void add(int a, int b) {
  v[p].END = b;
  v[p].next = first[a];
  first[a] = p++;
}
char tmp[2][5];
char S[MAXN];
int id[10];
int ID(int x, int y) {
  if (S[x] - &apos;a&apos; == y) return 0;
  if (S[x] == &apos;a&apos;) return x * 2 + y - 1;
  else if (S[x] == &apos;b&apos;) return x * 2 + y / 2;
  else return x * 2 + y;
}
int dfn[MAXN &amp;lt;&amp;lt; 1], low[MAXN &amp;lt;&amp;lt; 1], Index, belong[MAXN &amp;lt;&amp;lt; 1], T;
bool vis[MAXN &amp;lt;&amp;lt; 1];
int st[MAXN &amp;lt;&amp;lt; 1], top;
void Tarjan(int rt) {
  dfn[rt] = low[rt] = ++Index;
  st[++top] = rt;
  vis[rt] = 1;
  for (int i = first[rt]; i != -1; i = v[i].next) {
    if (!dfn[v[i].END]) {
      Tarjan(v[i].END);
      low[rt] = min(low[rt], low[v[i].END]);
    } else if (vis[v[i].END])
      low[rt] = min(low[rt], dfn[v[i].END]);
  }
  if (low[rt] == dfn[rt]) {
    T++;
    int x;
    do {
      x = st[top--];
      vis[x] = 0;
      belong[x] = T;
    } while (low[x] != dfn[x]);
  }
}
bool Calc(int n, int m) {
  memset(first, -1, sizeof(first)), p = 0;
  memset(dfn, 0, sizeof(dfn));
  memset(low, 0, sizeof(low));
  memset(belong, 0, sizeof(belong));
  T = Index = 0;
  for (int i = 1; i &amp;lt;= m; ++i) {
    int t1 = ID(D[i].i, D[i].hi);
    int t2 = ID(D[i].j, D[i].hj);
    if (t1) {
      if (t2) add(t1, t2), add(t2 ^ 1, t1 ^ 1);
      else add(t1, t1 ^ 1);
    }
  }
  for (int i = 2; i &amp;lt;= 2 * n + 1; ++i) {
    if (!dfn[i]) Tarjan(i);
    if (i &amp;amp; 1) {
      if (belong[i] == belong[i - 1]) return 0;
    }
  }
  for (int i = 1; i &amp;lt;= n; ++i) {
    if (belong[2 * i] &amp;lt; belong[2 * i + 1]) {
      if (S[i] == &apos;a&apos;) printf(&quot;B&quot;);
      if (S[i] == &apos;b&apos;) printf(&quot;A&quot;);
      if (S[i] == &apos;c&apos;) printf(&quot;A&quot;);
    } else {
      if (S[i] == &apos;a&apos;) printf(&quot;C&quot;);
      if (S[i] == &apos;b&apos;) printf(&quot;C&quot;);
      if (S[i] == &apos;c&apos;) printf(&quot;B&quot;);
    }
  }
  printf(&quot;\n&quot;);
  return 1;
}
int main() {
  int n = read(), d = read();
  scanf(&quot;%s&quot;, S + 1);
  int x = 0;
  int m = read();
  for (int i = 1; i &amp;lt;= m; ++i) {
    scanf(&quot;%d%s%d%s&quot;, &amp;amp;D[i].i, tmp[0], &amp;amp;D[i].j, tmp[1]);
    D[i].hi = tmp[0][0] - &apos;A&apos;;
    D[i].hj = tmp[1][0] - &apos;A&apos;;
  }
  for (int i = 1; i &amp;lt;= n; ++i)
    if (S[i] == &apos;x&apos;) id[++x] = i;
  int N = (1 &amp;lt;&amp;lt; d) + 1;
  for (int i = 0; i &amp;lt;= N; ++i) {
    for (int j = 1; j &amp;lt;= x; ++j)
      if (i &amp;amp; (1 &amp;lt;&amp;lt; (j - 1))) S[id[j]] = &apos;a&apos;;
      else S[id[j]] = &apos;b&apos;;
    if (Calc(n, m)) return 0;
  }
  return printf(&quot;-1\n&quot;), 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>清北夏令营前集训日记</title><link>https://www.nekomio.com/posts/151/</link><guid isPermaLink="true">https://www.nekomio.com/posts/151/</guid><pubDate>Wed, 16 May 2018 19:37:10 GMT</pubDate><content:encoded>&lt;h3&gt;2018-5-16&lt;/h3&gt;
&lt;p&gt;才发现今天距离我开坑 &lt;a href=&quot;/2018/04/16/147/&quot;&gt;APIO&amp;amp;&amp;amp;CTSC集训日记&lt;/a&gt; 刚好一个月。&lt;br /&gt;
上午考试&lt;br /&gt;
上来先通读了一边题目， 发现$T2$好像是原题， 然后简单的想了一下$T1$和$T3$，发现没有$T2$好做。&lt;br /&gt;
于是先打$T2$。 半个小时打完了$T2$。&lt;br /&gt;
之后发现$T3$的$40$分暴力好像还是比较好打。然后先打了一个$O(2^{n}nL)$的， 然后写了一个暴力和他拍打。
完这些之后想了一下$T3$的正解， 发现我并不会把复杂度降到指数以下， 这时已经9点半了。&lt;br /&gt;
最后去写$T1$。 可能我的打法比较傻， 暴力打起来并不是很简单，用了一个多小时的时间才把暴力调出来。&lt;br /&gt;
然后想到了一个线段树的乱搞做法，然后就开始搞， 结果到最后也没调出来。&lt;br /&gt;
没有挂分， 只是$T1$暴力用的时间有点多， 导致没有拿到$T1$的高分暴力。
下午改完题， 看了一下清华校赛的题， 把考场上想做但是没有做出来的题看了一下， 发现正解很简单，还是太弱了。&lt;/p&gt;
&lt;h3&gt;2018-5-17&lt;/h3&gt;
&lt;p&gt;今天是ACM&lt;br /&gt;
上来先通读了题目。花了不到$20$分钟就看完了题而且对每个题的难度有了一个初步的评估。&lt;br /&gt;
$D$题一定是最先做的， 可以看出来这是一道签到题。只要一个简单的$Hash$就能解决。在开场半小时就切出了这道题。&lt;br /&gt;
看有人$A$掉了$C$题， 虽然感觉是数据有问题但还是去做了， 开始打， 打到一半发现重测了，这时只有一个人过了， 想了一种新的做法， 开始重新打， 打完这种做法之后感觉过不了， 先没有交。&lt;br /&gt;
看了一下其他的题， 看了一圈之后感觉E题和G题稍微有点思路。&lt;br /&gt;
然后上了个厕所， 发现C题可以优化到$ O(n\ln(n))$ 先交了一发暴力， 发现真的过不了， 改正解， 交上去发现$WA$了， 又改了改， 还是$WA$， 突然发现要输出 &lt;code&gt;Case #x:&lt;/code&gt; 加上就过了。
之后去打$G$， 先有梦想的打了一个网络流， 交上去果然$T$了， 接下来打我心目中的正解， 打到一半发现好像不是那没么好打， 看了一下时间，和我接下来要写的代码量， 果断的弃了这道题。
到考试结束也没想出其他题。&lt;/p&gt;
&lt;p&gt;下午发现好像$E$最可改（虽然事实证明这是假的）。 改了一下午还是没过， 卡常啊。。。。。&lt;br /&gt;
晚上又优化了一波常数才过， 然后改了 $F$。 还想改 $G$, 不过还没改。&lt;/p&gt;
&lt;h3&gt;2018-5-18&lt;/h3&gt;
&lt;p&gt;考试&lt;br /&gt;
上来先看了一边题， 然后发现都不怎么会， 看出来$T2$是一道原题，但是原题的数据范围在这道题中只有$30$分。&lt;br /&gt;
先打了一个$30$分， 然后看$T1$和$T3$， 想了想， 并没有想出来， 先打了$T3$， $T1$ 两个有梦想的暴力， 然后并没有分。&lt;br /&gt;
尝试去想正解， 无果， 看到$T3$ 的数据范围是$10^{7}$, 感觉很慌， 还是没想出正解。&lt;br /&gt;
下来发现$T2$的$30$分并没有拿到， 被卡了常数， 卡了好久才过， $T3$是最可做的， 我没看出了他是一颗树。
改题&lt;br /&gt;
T3很好改。&lt;br /&gt;
T2打出了一个DFS的打法过了。&lt;br /&gt;
T1最不可改， 还没有改出来。&lt;/p&gt;
&lt;h3&gt;2018-5-20&lt;/h3&gt;
&lt;p&gt;昨天沉迷改题无法自拔。&lt;br /&gt;
今天考试&lt;br /&gt;
上来先看了一遍题， 发现都没有什么思路。&lt;br /&gt;
发现T3是一道提答， 然后先玩了一会儿提答， 把前4个点跑了出来。
然后回头看T1打了一个20分的DP， 然而并不会优化了。&lt;br /&gt;
去看T2， 转换为图论， 好像是一个子完全图类似的东西。&lt;br /&gt;
然而并不会了。&lt;br /&gt;
在回头看T3跑了一下5～8, 又得了一点分。&lt;br /&gt;
也就拿到这么多分了。&lt;br /&gt;
不过今天的题还是比较好改的。&lt;/p&gt;
&lt;h3&gt;2018-5-21&lt;/h3&gt;
&lt;p&gt;今天把PKUWC的题做了一下。&lt;br /&gt;
下午考了一个学考， 晚上回来继续做题， 然后背了一会儿政治， 一天就这样过去了。&lt;/p&gt;
&lt;h3&gt;2018-5-23&lt;/h3&gt;
&lt;p&gt;这两天没考试， 就没怎么写。&lt;br /&gt;
今天做了不少UOJ的题， 虽然都不是什么难题， 但是锻炼一下思维么。&lt;br /&gt;
今天终于把旷野大计算过了， 非常开心。&lt;/p&gt;
&lt;h3&gt;2018-5-24&lt;/h3&gt;
&lt;p&gt;今天IOI赛制。&lt;br /&gt;
上来先看T1， 第一眼以为是四维偏序， 打了个 CDQ+BIT+Seg_Tree ， 然后发现样例不对， 再一看题， 发现其实是三维偏序， 把 Seg_Tree 删掉然后测大样例死活不对， 浪费了我好长时间， 最后发现大样例是错的。&lt;br /&gt;
然后打了一个$T3$的暴力， 打了一个T2的暴力， 然后打了T3的乱搞， T3骗了不少分。&lt;/p&gt;
&lt;h3&gt;2018-5-25&lt;/h3&gt;
&lt;p&gt;上来先看T1发现好像会60分， 就打了。&lt;br /&gt;
T2只会直接输出的20分， T3打了一个爆搜。&lt;br /&gt;
结果T1是一道FST好题， 出了成绩才发现自己想的是错的。&lt;br /&gt;
T3的暴力也不知道出现了什么问题。&lt;br /&gt;
总之这道题打的不是很好。&lt;br /&gt;
主要是暴力没有打好， 没有拿到应该拿的分数。&lt;/p&gt;
&lt;h3&gt;2018-5-26&lt;/h3&gt;
&lt;p&gt;忘写了&lt;/p&gt;
&lt;h3&gt;2018-5-27&lt;/h3&gt;
&lt;p&gt;今天没有考试。&lt;br /&gt;
主要把前几天没改完的题改了一下。&lt;br /&gt;
然后做了一道UOJ的水题。&lt;/p&gt;
&lt;h3&gt;2018-5-28&lt;/h3&gt;
&lt;p&gt;今天考了一场试。&lt;br /&gt;
去了东师大附的OJ 考的不是很好， 原因是我没能静下心来。 这次考试让我找到了我在考场上的状态， 十分的紧张。&lt;br /&gt;
其实我很需要这种状态的训练。&lt;br /&gt;
这种情况下如何静下心来思考是我的一大问题。 如果能解决， 那就能提升自己的水平了。&lt;br /&gt;
然后把清华的回执给填了。&lt;/p&gt;
&lt;h3&gt;2018-5-29&lt;/h3&gt;
&lt;p&gt;和昨天一样不过我考了OI赛制， 感觉OI赛制没有IOI那么慌。&lt;br /&gt;
上来先看T1， 想了很多种做法， 但是都不是很对， 最后只能打一个40分的做法。&lt;br /&gt;
然后是T2先打了一个暴力， 但是不对， 想不出来为什么？？？ 最后也没有得到分， 后来知道是因为少考虑了一种情况。&lt;br /&gt;
T3是一道见过但是不会做的神题答。&lt;br /&gt;
只那了可以手玩儿出来的一点分， 然后回去想T2，也没想出来为什么没分。&lt;/p&gt;
&lt;h3&gt;2018-5-30&lt;/h3&gt;
&lt;p&gt;才发现时间都是错的。。。
还是IOI与OI同时考， 上来第一题想了一个40分的DP， 去看T2推了好久通项，最后推出了一点东西， 但是没有什么用， 打了一个60分的矩阵乘。&lt;br /&gt;
然后看T3， 一直想K&amp;lt;=5的怎么做， 最后没想出来， 然后打了一个Q&amp;lt;=10的和链上的部分分。&lt;/p&gt;
&lt;h3&gt;2018-5-31&lt;/h3&gt;
&lt;p&gt;考试。&lt;br /&gt;
T1考场上写了一个38分的暴力， 然后想到了52分特征多项式可以跑过去， 但是我不是很会特征多项式， 于是只能GG了。&lt;br /&gt;
T3是真的一点都不会， 只好去玩T2的提答， 发现前三个点都是比较好打的。 然后第四个点， 先手玩儿了一会儿， 发现做不出来， 打了一个模拟退火就过了， 然后第5个点还是退火， 不过没有多少分， 后面的点只能有一个保底分了。&lt;/p&gt;
&lt;p&gt;去北大的开始收拾东西了。
我们也帮着收拾了一下。&lt;/p&gt;
&lt;h3&gt;2018-6-1&lt;/h3&gt;
&lt;p&gt;考试， 改题。&lt;br /&gt;
今天只有4个人。。&lt;br /&gt;
好像没什么事了， 不过今天得回去收拾东西。&lt;/p&gt;
</content:encoded></item><item><title>APIO &amp;&amp; CTSC 完结</title><link>https://www.nekomio.com/posts/150/</link><guid isPermaLink="true">https://www.nekomio.com/posts/150/</guid><pubDate>Tue, 15 May 2018 07:32:39 GMT</pubDate><content:encoded>&lt;h3&gt;结束了&lt;/h3&gt;
&lt;p&gt;从来到北京到今天，已经过去了快 10 天了。&lt;br /&gt;
我也是需要总结一下这几天。&lt;/p&gt;
&lt;p&gt;先从考试来说吧，这几次考试教会了我很多，因为我都死在了 T1 上。&lt;br /&gt;
CTSC 中 Day1 没有去想本身很简单的第一题。而是花费了太多的时间在其他两题上，使我没有得到我有能力拿到的分数。&lt;br /&gt;
而 APIO 更是如此， 不过这次恰恰相反。 因为我花费了太多的时间在 T1 上， T2 和 T3 都没有去想，甚至都没有仔细看一下部分分， 导致 T3 这道最好拿分的一道题没有拿更多的分。&lt;/p&gt;
&lt;p&gt;这两次的问题， 主要是出在对题目难度的把控上。&lt;br /&gt;
虽然通读了题面， 但是我却并没有对哪道题好得分， 哪道题不好得分有清晰的认识， 我可以确定，这是考试经验不足和题量少的缘故。&lt;/p&gt;
&lt;p&gt;还有一个突出的问题， 是速度——打题的速度。&lt;br /&gt;
很多时候在脑海中已经想好的解法却没有充足的时间去实现。&lt;br /&gt;
而在写代码的时候也会卡壳， 不知道该打什么， 这其实是思路不清晰的缘故。&lt;/p&gt;
&lt;p&gt;这两次比赛， 让我看到了差距， 也确定了接下来一段时间努力的方向。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;知识是一方面， 心态更是一方面。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在做题的时候， 没有一种能做出题的自信， 这是一个很大的问题， 这种自信的缺乏使得我少了不少动力去继续深入的思考。&lt;/p&gt;
&lt;p&gt;接着是清华校赛， 这场比赛让我对 &lt;strong&gt;细心&lt;/strong&gt; 这两个字有了更深入的了解: 一个 &lt;code&gt;2148473648&lt;/code&gt; 的模数与 &lt;code&gt;2147483678&lt;/code&gt; 有着本质的区别， 如果想当然的话， 那会浪费你宝贵的时间。&lt;/p&gt;
&lt;p&gt;这些天我得到了什么？ 我得到了我突出的几个问题， 这是我下一步改进的方向。&lt;/p&gt;
&lt;p&gt;还有 2 个月就要 NOI 了， 加油吧。&lt;/p&gt;
</content:encoded></item><item><title>UOJ328 【UTR #3】量子破碎</title><link>https://www.nekomio.com/posts/149/</link><guid isPermaLink="true">https://www.nekomio.com/posts/149/</guid><pubDate>Sat, 21 Apr 2018 15:12:31 GMT</pubDate><content:encoded>&lt;p&gt;Scape下载了好久终于下完了关于量子巧克力的游戏——Quantum break，准备邀请Mythological来享受在一起的时光。可是谁知道积劳成疾的Scape，居然在Mythological到来之前就陷入了梦境之中。&lt;/p&gt;
&lt;p&gt;Scape在梦境中隐隐约约看见了这样的一份题面：&lt;/p&gt;
&lt;p&gt;Mythological应邀来和他一起隔膜，并且带来了一盒与游戏中同款的 ”黎明前就会破碎的量子巧克力“。&lt;/p&gt;
&lt;p&gt;在游戏里量子巧克力可以看做一个数组 $a$，长度为 $2^n$，下标从 $0$ 开始到 $2^{n}-1$ 结束。&lt;/p&gt;
&lt;p&gt;他们俩可以关于这些量子巧克力，向游戏做一些询问，但是不幸有的询问会导致量子破碎，此时游戏会刷新这个数组开始新的一轮....&lt;/p&gt;
&lt;p&gt;即使是在梦中，Scape也想让Mythological开心，请你帮一帮他。&lt;/p&gt;
&lt;h4&gt;任务&lt;/h4&gt;
&lt;p&gt;每轮游戏开始的时候数组里只有 $a[x]=a[y]= \frac{1}{\sqrt{2} }$（$x \neq y$），剩下的元素都是 $0$。&lt;/p&gt;
&lt;p&gt;你需要编写一个函数和交互库进行多轮交互，求出 $x \oplus y$ 的值（每轮中 $x \oplus y$ 不变）:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;query_xor(n, t);
&lt;ul&gt;
&lt;li&gt;n 表示 a 的长度是 $2^n$，t 表示子任务编号。&lt;/li&gt;
&lt;li&gt;你的返回值是 $x \oplus y$ 的答案。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你可以通过四种操作来确定这个值:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;query();
&lt;ul&gt;
&lt;li&gt;向交互库做一次询问。&lt;/li&gt;
&lt;li&gt;交互库会随机返回一个下标，具体来说返回 $x$ 的概率恰好是 $\frac{a[x]^2}{\sum_i a[i]^2}$。&lt;/li&gt;
&lt;li&gt;返回 $x$ 之后，会开始新的一轮，交互库重新随机一对 $x$ 和 $y$ 保证 $x \oplus y$ 不变（在所有满足条件的 $x,y$ 中等概率随机，有可能不变），然后重新给数组 $a$ 赋值，使得数组里只有 $a[x]=a[y]=\frac{1}{\sqrt{2} }$ ($x \ne y$)，剩下的元素都是 $0$。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;manipulate(A, i);
&lt;ul&gt;
&lt;li&gt;向交互库做一次操作，给出一个 $2 \times 2$ 的实数矩阵 $A$。&lt;/li&gt;
&lt;li&gt;交互库会把数组 $a$ 更新，具体来说，对于每个二进制第 $i$（$i$ 是传入的参数）位为 $0$ 的数 $x$，令$$ \begin{cases} b[x] = A[0][0] \cdot a[x] + A[1][0]\cdot a[x+2^i],\ b[x+2^i] = A[0][1]\cdot a[x] + A[1][1]\cdot a[x+2^i],\end{cases} $$ 则 $a[x]$ 将更新为 $b[x]$, $a[x+2^i]$ 将更新为 $b[x+2^i]$。&lt;/li&gt;
&lt;li&gt;为了保证 $a[x]^2$ 的和 (概率和) 始终为1, 你的矩阵必须满足$AA^T=I$, 可以证明此时 $a[x]^2$ 的和始终不变（$A^T$ 表示 $A$ 的转置，$I$ 为单位矩阵）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;arbitary_manipulate(A, i);
&lt;ul&gt;
&lt;li&gt;和 manipulate 不同的是，这里不强制 $AA^T=I$。&lt;/li&gt;
&lt;li&gt;使用了这个函数后，$\sum a[x]^2$ 可能不为 $1$，询问的时候概率按照 $a[x]^2$ 的比例平均分配。&lt;/li&gt;
&lt;li&gt;如果 $\sum a[x]^2 = 0$，交互库会返回 0。（请选手使用下发的 grader 判断自己程序的精度问题）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;arbitary_query(x);
&lt;ul&gt;
&lt;li&gt;询问 a[x] 为多少。&lt;/li&gt;
&lt;li&gt;和 query 不同，不会导致数组清空开始新的一轮。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;限制与约定&lt;/h4&gt;
&lt;p&gt;一共五个子任务，每个子任务有对应的分数。&lt;/p&gt;
&lt;p&gt;每个子任务都有对应的可以使用的函数，使用了不可使用的函数会失去这个子任务的分数。&lt;/p&gt;
&lt;p&gt;为了拿到每个子任务的分数，你必须通过所有他依赖的子任务。&lt;/p&gt;
&lt;p&gt;所有的子任务中都不能使用超过 $400$ 个操作。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;子任务&lt;/th&gt;
&lt;th&gt;分值&lt;/th&gt;
&lt;th&gt;$n$ 的规模&lt;/th&gt;
&lt;th&gt;可以使用的函数&lt;/th&gt;
&lt;th&gt;依赖的子任务&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;$n=8$&lt;/td&gt;
&lt;td&gt;1,2,3,4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;$n=16$&lt;/td&gt;
&lt;td&gt;1,2,3,4&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;$n=16$&lt;/td&gt;
&lt;td&gt;1,2,3&lt;/td&gt;
&lt;td&gt;1,2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;$n=16$&lt;/td&gt;
&lt;td&gt;1,2,4&lt;/td&gt;
&lt;td&gt;1,2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;$n=6$&lt;/td&gt;
&lt;td&gt;1,2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;$n=16$&lt;/td&gt;
&lt;td&gt;1,2&lt;/td&gt;
&lt;td&gt;1,2,3,4,5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;时间限制：$2s$
空间限制：256MB&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://uoj.ac/problem/328&quot;&gt;UOJ328&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;题解&lt;/h3&gt;
&lt;h4&gt;Subtask 1&lt;/h4&gt;
&lt;p&gt;我们看到 $n$ 较小， 我们可以直接查询每一个位置， 然后就获得了 $5$ 分的好成绩。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://uoj.ac/submission/243944&quot;&gt;5pts&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Subtask 2&lt;/h4&gt;
&lt;p&gt;因为每个函数只能用小于 $400$ 次， 我们考虑如何减少查询次数。&lt;/p&gt;
&lt;p&gt;按位考虑&lt;br /&gt;
如果我们只想知道 $x \oplus y$ 的第 $i$ 位是否为$1$， 那么我们不用考虑其他位， 也就是说， 我们要把 $x,y$ 中除第 $i$ 位以外的位都变为 $0$。 这是一个不可逆的操作。 所以矩阵是不可逆的， 所以我们要用的操作为 $3$, 矩阵为 $\begin{pmatrix} 1 &amp;amp; 1 \ 0 &amp;amp; 0 \end{pmatrix}$&lt;br /&gt;
这本质上是把第 $i$ 位为 1 的数 $x$ 累加到 $x - 2^i$ 上， 然后将 $x$ 的值设为 $0$。&lt;br /&gt;
最后要查询一下 $a[0]$ 与 $a[2^i]$ 是否都为 $1$。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://uoj.ac/submission/243948&quot;&gt;20pts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(UPD 2018-4-25 21:37)&lt;br /&gt;
还有一种方法(by wq)&lt;br /&gt;
同样是按位考虑作用矩阵 $\begin{pmatrix} 1 &amp;amp; 1 \ 0 &amp;amp; 1 \end{pmatrix}$&lt;br /&gt;
这样作用完了之后如果 $x \oplus y$ 中有 $2^i$， 那么最后查询 $2^i$就为$\frac{1}{\sqrt{2} }$。&lt;br /&gt;
查询一下就好了。&lt;br /&gt;
&lt;a href=&quot;http://uoj.ac/submission/245096&quot;&gt;20pts&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Subtask 3&lt;/h4&gt;
&lt;h5&gt;Part1&lt;/h5&gt;
&lt;p&gt;我们考虑如何丢掉最后一步用操作4查 $a[0]$ 和$a[2^i]$&lt;br /&gt;
如果直接随机，那么无论 xor 是 0 还是 1 ，都会随机返回 0 或 1 （每次 x 会重新随机）。&lt;br /&gt;
为了区分出来我们做变换 $a[0]=a[0]+a[2^i]$, $a[2^i]=a[0]-a[2^i]$, 用上矩阵$\begin{pmatrix} 1 &amp;amp; 1 \ 1 &amp;amp; -1 \end{pmatrix}$&lt;br /&gt;
如果异或值为 1 则答案一定为 $0$, 否则答案为$0$或$1$。
那么我们可以多次询问搞一下。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;可是并不能过掉第三个Subtask， 因为复杂度是 $n^2$ 的然后如果乘个常数， 好像就超次数了。&lt;br /&gt;
如果我的理解有不对的， 请联系我。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;Part2&lt;/h5&gt;
&lt;p&gt;我们考虑另一种概率做法。
注意题面里有提到交互库的实现，会在概率平方和为0的时候返回0。&lt;br /&gt;
如果平方和不为0，返回0的概率很小。&lt;br /&gt;
对于每一位我们作用上 $\begin{pmatrix} 1 &amp;amp; 0 \ 0 &amp;amp; 0 \end{pmatrix}$&lt;br /&gt;
这样如果 $x, y$ 的第 $i$ 位都为 1， 则一定会返回 $0$, 其他情况下返回$0$ 的概率很小， 基本不用考虑。&lt;br /&gt;
那么如果返回 $0$， 我们可以就认为$x, y$的第$i$ 位都为 1。 这种方法得出的结果是有很小的概率不对的， 但正确的概率很大。
事实上, 所有 Subtask 3 的数据都不会卡掉这个做法。
但如果 $x, y$ 的值都为 $0$, 他依然不会返回 $0$, 所以我们要多次查询， 在这些次中，有很大的概率使得有至少一次 $x, y$ 都为 1。&lt;/p&gt;
&lt;p&gt;到此我们得到了 $40$ 分的好成绩。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://uoj.ac/submission/243969&quot;&gt;40pts&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Subtask 4&lt;/h3&gt;
&lt;p&gt;我们看一下&lt;a href=&quot;#Part1&quot;&gt;Subtask 3 Part1&lt;/a&gt; 中的那个变换， 其实它很有用。&lt;br /&gt;
他本质上就是一个异或的$FWT$的正变换。&lt;br /&gt;
然后回顾一下他的性质， 在变换完的数组中， 下标为 $2^i$ 的位置的值为所有二进制中第 i 位不为 1 的数的和减所有二进制中第 i 位为 1 的数的和。&lt;br /&gt;
那么如果 $x, y$ 的二进制第 $i$ 位相同那么 $a[2^i]$ 就是 0， 反之亦然。&lt;br /&gt;
这样我们就能求出答案了&lt;/p&gt;
&lt;p&gt;还有一件事， 因为要保证 $AA^T=I$， 所以我们不能用 $\begin{pmatrix} 1 &amp;amp; 1 \ 1 &amp;amp; -1 \end{pmatrix}$ 而是用 $\begin{pmatrix} \frac{1}{\sqrt{2} } &amp;amp; \frac{1}{\sqrt{2} } \ \frac{1}{\sqrt{2} } &amp;amp; -\frac{1}{\sqrt{2} } \end{pmatrix}$&lt;br /&gt;
这样相当于将所以数都乘了一个 $\frac{1}{\sqrt{2} }^n$
这样就有 $60$ 分了。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://uoj.ac/submission/244011&quot;&gt;60pts&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Subtask 5 &amp;amp; 6&lt;/h3&gt;
&lt;p&gt;我们已经知道了他是一个$FWT$，我们考虑随机的一位对我们有用的信息是什么&lt;/p&gt;
&lt;p&gt;考虑 $x$ 对一个数 $t$ 的贡献， 根据 $FWT$ 的定义他显然为 $(-1)^{cnt(x &amp;amp; t)}$， $cnt(x &amp;amp; t)$ 表示 $x &amp;amp; t$ 的二进制中 1 的个数。&lt;br /&gt;
如果有两个数 $x, y$ 对 $t$ 贡献， 那么贡献的值 $v$ 为 $(-1)^{cnt(x&amp;amp;t)} + (-1)^{cnt(y &amp;amp; t)}$&lt;br /&gt;
$v$ 不为 0 的条件是 $cnt(x &amp;amp; t) + cnt(y &amp;amp; t)$ 为奇数。&lt;br /&gt;
我们可以证明 $cnt(x &amp;amp; t) + cnt(y &amp;amp; t)$ 的奇偶性与 $cnt((x \oplus y) &amp;amp; t)$ 的奇偶性相同。&lt;br /&gt;
证明:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;考虑没一个二进制位。&lt;br /&gt;
枚举 $x, y, t$ 在这一位的值， 在每一种情况下他们的奇偶性相同&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;$x$&lt;/th&gt;
&lt;th&gt;$y$&lt;/th&gt;
&lt;th&gt;$t$&lt;/th&gt;
&lt;th&gt;$cnt(x &amp;amp; t) + cnt(y &amp;amp; t)$&lt;/th&gt;
&lt;th&gt;$x \oplus y$&lt;/th&gt;
&lt;th&gt;$cnt((x \oplus y) &amp;amp; t)$&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们可以求出任意 $n$ 个不为 0 的位置。  如果他们是线性无关的， 那是不是就能求出 $x \oplus y$ 的值了呢？&lt;/p&gt;
&lt;p&gt;很可惜并不是。
这些 $t$ 可能并不是满秩的！&lt;br /&gt;
因为所有 $x \oplus y = 0$ 始终都会是 xor 方程的解。&lt;/p&gt;
&lt;p&gt;那怎么办呢？&lt;/p&gt;
&lt;p&gt;有两种方法&lt;br /&gt;
枚举每一个不为 0 的数。 判断他是否为这个方程的解。&lt;br /&gt;
时间复杂度为 $O(n2^n)$， 询问次数为 $O(n^2)$。&lt;/p&gt;
&lt;p&gt;或者:&lt;br /&gt;
直接高斯消元， 然后排除掉 $x \oplus y = 0$ 这个解就可以了。&lt;br /&gt;
时间复杂度为 $O(n^2)$, 询问次数为 $O(n^2)$&lt;/p&gt;
&lt;p&gt;可以 AC 此题。&lt;/p&gt;
&lt;p&gt;&lt;s&gt;FWT从入门到放弃&lt;/s&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;quantumbreak.h&quot;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cmath&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
double q = sqrt(0.5);
double C[2][2] = {{q, q}, {q, -q}};
vector&amp;lt;int&amp;gt; vc;
int Num(unsigned int x)
{
	unsigned int tmp = x
					 - ((x &amp;gt;&amp;gt; 1) &amp;amp; 033333333333)
					 - ((x &amp;gt;&amp;gt; 2) &amp;amp; 011111111111);
	tmp = (tmp + (tmp &amp;gt;&amp;gt; 3)) &amp;amp; 030707070707;
	return tmp % 63;
}
int query_xor(int n, int t)
{
	int ans = 0;
	for (int j = 0; j &amp;lt;= 20; j++)
	{
		for (int i = 0; i &amp;lt; n; i++)
			manipulate(C, i);
		vc.push_back(query());
	}
	// for (auto x : vc)
		// printf (&quot;%d\n&quot;, x);
	for (int i = 1; i &amp;lt; (1 &amp;lt;&amp;lt; n); i++)
	{
		bool flag = 0;
		for (auto x : vc)
		{
			// if (i == 42163) printf (&quot;%d\n&quot;, Num(x &amp;amp; i));
			if (Num(x &amp;amp; i) &amp;amp; 1)
			{
				flag = 1;
				break;
			}
		}
		if (!flag) return i;
	}
	// printf (&quot;%d\n&quot;, ans);
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>扩展Lucas定理求组合数</title><link>https://www.nekomio.com/posts/148/</link><guid isPermaLink="true">https://www.nekomio.com/posts/148/</guid><pubDate>Fri, 20 Apr 2018 08:51:06 GMT</pubDate><content:encoded>&lt;p&gt;在求组合数的时候， 我们可能遇到模数是非质数的情况， 这时正常的Lucas可能无法解决问题。 所以我们要用到扩展Lucas定理&lt;/p&gt;
&lt;p&gt;我们令 $p = p_{1}^{k_{1} } + p_{2}^{k_{2} } + p_{3}^{k_{3} } + \cdots + p_{q}^{k_{q} }$&lt;br /&gt;
可得同余方程&lt;br /&gt;
$$ \left \lbrace { \begin{array}{c} ans \equiv c_1\pmod { {p_1}^{k_1} } \ ans\equiv c_2\pmod { {p_2}^{k_2} } \ ans\equiv c_2\pmod { {p_2}^{k_2} } \ \ldots \ ans\equiv c_q\pmod { {p_q}^{k_q} } \end{array} } \right.$$&lt;/p&gt;
&lt;p&gt;然后我们考虑求 $C_{n}^{m} % p_{i}^{k_{i} }$ 的值&lt;br /&gt;
因为 $C_{n}^{m} = \frac{n!}{n!(n - m)!}$&lt;br /&gt;
我们只要求出$n! % p_{i}^{k_{i} }$, $m! % p_{i}^{k_{i} }$, $(n - m)! % p_{i}^{k_{i} }$&lt;/p&gt;
&lt;p&gt;我们考虑如何求 $x! % p_{i}^{k_{i} }$&lt;br /&gt;
以 $x = 19, p_{i} = 2, k_{i}=2$ 为例&lt;br /&gt;
$x! = 1 \times 2 \times 3 \times 4 \times 5 \times 6 \times 7 \times 8 \times 9 \times 10 \times 11 \times 12 \times 13 \times 14 \times 15 \times 16 \times 17 \times 18 \times 19$&lt;br /&gt;
$= (1 \times 2 \times 4 \times 5 \times 7 \times 8 \times 10 \times 11 \times 13 \times 14 \times 16 \times 17 \times 19) \times (1 \times 2 \times 3 \times 4 \times 5 \times 6) \times 3^6$&lt;/p&gt;
&lt;p&gt;求解$n!$可以分为3部分: 第一部分是$p_i$的幂的部分可以直接求解 ${p_i}^{\lfloor{n\over p_i}\rfloor}$&lt;br /&gt;
第二部分是一个新的阶乘${\lfloor{n\over p_i}\rfloor}!$&lt;br /&gt;
发现第三部分在模$p_{i}^{k_{i} }$意义下是以$p_{i}^{k_{i} }$为周期的然后就可以较轻松的求出了&lt;/p&gt;
&lt;p&gt;最后一个问题是对于求出的$m! % p_{i}^{k_{i} }$， $(n - m)! % p_{i}^{k_{i} }$ 有可能与 $p_{i}^{k_{i} }$ 不互质。&lt;br /&gt;
我们需要将 $p_{i}^x$ 拆出来考虑就可以了&lt;/p&gt;
&lt;p&gt;计算$n!$中质因子$p$的个数$x$的公式为$x=\lfloor{n\over p}\rfloor+\lfloor{n\over p^2}\rfloor+\lfloor{n\over p^3}\rfloor+\ldots$&lt;br /&gt;
递推式也可以写为$f(n)=f(\lfloor{n\over p}\rfloor)+\lfloor{n\over p}\rfloor$&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pk&lt;/code&gt; 为 $p^k$, &lt;code&gt;exP&lt;/code&gt;为$p_{i}$ &lt;code&gt;phip&lt;/code&gt; 为 $\phi(p^k)$&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;long long Mul(int n, int id)
{
	if (n == 0) return 1;
	long long ans = 1;
	if (n / pk[id])
	{
		for (int i = 2; i &amp;lt;= pk[id]; i++)
			if (i % exP[id])
				ans = ans * i % pk[id];
		// ans = pow_mod(TT[id][pk[id]], n / pk[id], pk[id]);
	}
	// ans = ans * TT[id][n % pk[id]] % pk[id];
	for (int i = 2; i &amp;lt;= n % pk[id]; i++)
		if (i % exP[id])
			ans = ans * i % pk[id];
	return ans * Mul(n / exP[id], id) % pk[id];
}
int exlucas(int n, int m, int id)
{
	if (n &amp;lt; m || n &amp;lt; 0 || m &amp;lt; 0) return 0;
	if (m == n || m == 0) return 1;
	long long a = Mul(n, id), b = Mul(m, id), c = Mul(n - m, id);
	int t = 0;
	for (int i = n; i; i /= exP[id]) t += i / exP[id];
	for (int i = m; i; i /= exP[id]) t -= i / exP[id];
	for (int i = n - m; i; i /= exP[id]) t -= i / exP[id];
	return a * pow_mod(b, phip[id] - 1, pk[id]) % pk[id] * pow_mod(c, phip[id] - 1, pk[id]) % pk[id] * pow_mod(exP[id], t, pk[id]) % pk[id];
}
long long CRT(int *a, int *b, int n)
{
    long long N = 1, Ni, now, ans = 0;
    for (int i = 1; i &amp;lt;= n; i++) N *= a[i];
    for (int i = 1; i &amp;lt;= n; i++)
    {
        Ni = N / a[i];
        now = pow_mod(Ni, phip[i] - 1, a[i]);
        ans = (ans + (b[i] * now % N) * Ni % N) % N;    
    }
    return ans;
}
long long Calc(int n, int m)
{
	if (n &amp;lt; 0 || m &amp;lt; 0 || n &amp;lt; m) return 0;
	for (int i = 1; i &amp;lt;= t; i++)
	{
		b[i] = exlucas(n, m, i);
	}
	return CRT(pk, b, t);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>CTSC&amp;APIO前集训日记</title><link>https://www.nekomio.com/posts/147/</link><guid isPermaLink="true">https://www.nekomio.com/posts/147/</guid><pubDate>Mon, 16 Apr 2018 21:21:21 GMT</pubDate><content:encoded>&lt;h3&gt;2018-4-16&lt;/h3&gt;
&lt;p&gt;从省选回来的时间不短了&lt;br /&gt;
把题改完之后就是在做 $DP$&lt;br /&gt;
今天做 $DP$ 和网络流的互相交流了一下&lt;br /&gt;
然后呢，就没什么了。&lt;br /&gt;
今天做了半天的网络流。&lt;/p&gt;
&lt;h3&gt;2018-4-17&lt;/h3&gt;
&lt;p&gt;今天考了一场试，好久没见到这么清真的考试题了&lt;br /&gt;
其实都是 LOJ 上的原题， 也算是比较好做吧&lt;br /&gt;
改完题后继续做网络流的题目， 先打了 $UOJ77$ 的 $60$ 分部分分&lt;br /&gt;
然后去看正解， 用主席树优化建图， 看完之后感觉这种方法很是神器， 但并不复杂&lt;br /&gt;
然后就去做 UOJ217 奇怪的线段树 还没有做完。&lt;br /&gt;
听说明天换Linux?&lt;/p&gt;
&lt;h3&gt;2018-4-18&lt;/h3&gt;
&lt;p&gt;真的换Linux了不过祖传硬盘还是233&lt;br /&gt;
然后继续做网络流的题目， 用Linux打代码好不方便啊。&lt;br /&gt;
没有GIT真伤心， 不过听说明天考试， 然后网络流就完了。&lt;br /&gt;
然后就开数学了。&lt;/p&gt;
&lt;h3&gt;2018-4-19&lt;/h3&gt;
&lt;p&gt;考了场试， 今天的考试就不是很清真了，&lt;br /&gt;
$T1$ 是一道考组合数取模的题目。&lt;br /&gt;
$T2$基本上是一个裸的$FWT$加倍增，&lt;br /&gt;
$T3$ 是一道$DP$ 打的我很蒙， 主要是由三个DP数组互相转移。&lt;/p&gt;
&lt;p&gt;不过google输入法真难用。&lt;/p&gt;
&lt;h3&gt;2018-4-20&lt;/h3&gt;
&lt;p&gt;一直在做数学。&lt;br /&gt;
在UOJ上找了道不错的题目然后开始做， 50分的部分分非常的好想。
然后去想100分做法不会啊， 勉强看懂了题解， 但是丝毫不会实现， 去看代码， 然后发现根本看不懂代码。。。&lt;br /&gt;
就对着代码一行一行的看， 一点一点的理解， 然后发现这好像是就一个洲阁筛。 回头看题解， 发现推导过程与洲阁筛一样。&lt;br /&gt;
可是我也不会洲阁筛啊 然后只好先简单学习了一下洲阁筛， 勉强看懂了代码。&lt;br /&gt;
然后一天就快要过去了&lt;br /&gt;
晚上打了「WC2018」州区划分 发现其实50分非常好打啊。 为什么我当时不会啊。&lt;/p&gt;
&lt;h3&gt;2018-4-21&lt;/h3&gt;
&lt;p&gt;基本上一天都是在 $FWT$ 上午先做了两道简单的题， 然后开始做&lt;a href=&quot;http://uoj.ac/problem/328&quot;&gt;UOJ328 【UTR #3】量子破碎&lt;/a&gt;, 这是一道 $FWT$ 好题， 刚看到的时候我以为是一道人类智慧题， 就是瞎构造一些矩阵往上搞。&lt;br /&gt;
然后并没有搞出来， 最后正解居然是 $FWT$ 很震惊。&lt;br /&gt;
做了一下午加一晚上。。&lt;/p&gt;
&lt;h3&gt;2018-4-22&lt;/h3&gt;
&lt;p&gt;考试， 改题， 这题解是假的吧。。。&lt;/p&gt;
&lt;h3&gt;2018-4-23&lt;/h3&gt;
&lt;p&gt;考试改题， 暂时弃掉了 T2 去改昨天的 $T3$。&lt;br /&gt;
还是没调出来啊。&lt;br /&gt;
估计是调不出来了。。。&lt;/p&gt;
&lt;h3&gt;2018-4-24&lt;/h3&gt;
&lt;p&gt;听说今天的题很正常？？？？？？？？？？？？？&lt;/p&gt;
&lt;p&gt;怎么可能呢！！！！！！！&lt;/p&gt;
&lt;p&gt;$T2$ 还是很可改的。&lt;br /&gt;
然而$T1$卡了我一波内存。&lt;br /&gt;
不知道为什么重载&lt;code&gt;new&lt;/code&gt; 就过了。&lt;br /&gt;
$T3$ 一点都不会， 还没有看呢。。
UPD(2018-4-25): $T3$ 好像不难， 主要是先得到一些关键性的性质定义好方程然后转移就可以了。&lt;br /&gt;
在最后手解一下方程组。&lt;/p&gt;
&lt;h3&gt;2018-4-25&lt;/h3&gt;
&lt;p&gt;改完了昨天的题。&lt;br /&gt;
把明天大家要交流的题都看了一遍。&lt;br /&gt;
没了。&lt;/p&gt;
&lt;h3&gt;2018-4-26&lt;/h3&gt;
&lt;p&gt;上午互相交流了一下题目。&lt;br /&gt;
用了整整一个上午的时间。&lt;br /&gt;
下午突然老师说要考试， 极奇疲惫。&lt;br /&gt;
考到一半感觉到头疼。&lt;br /&gt;
晚上改题。 $T1$ 是一道假题。&lt;br /&gt;
不想写了。&lt;/p&gt;
&lt;h3&gt;2018-4-28&lt;/h3&gt;
&lt;p&gt;断了一天啊， 昨天忘写了。&lt;br /&gt;
今天考试一看 $T1$ 感觉还是很可做的。&lt;br /&gt;
推了一会儿也退出来了， 然而因为少了一个细节而少了 $20$ 分。&lt;br /&gt;
$T2$ 一眼就能看出 $30$ 分， 两眼就能看出 $50$ 分然后就不会了。&lt;br /&gt;
$T3$ 看出了 $60$ 分的打法， 然后时间不够没有打完。&lt;br /&gt;
以后要更加合理的分配时间， 简单题要考虑好代码的细节。&lt;br /&gt;
另外打代码要快一点， 不能想出来没打完。&lt;/p&gt;
&lt;h3&gt;2018-4-30&lt;/h3&gt;
&lt;p&gt;29号放了一天假， 回去休息了一下。&lt;br /&gt;
今天下午来学校主要是把昨天的题改了。&lt;br /&gt;
$T1$ 是一道一眼就能看出正解的题目， 可是出题人却让输出分数， 然后精度就很迷。&lt;br /&gt;
$T2$ 是一道并不是很难的 $DP$， 至少对与 $40$ 分是这样的。 然后对于再高的分数，就要有一个非常巧妙的的转换。&lt;br /&gt;
$T3$ 是一道简单清真小 $DP$， $50$ 分就是一眼， 然后满分也是一个不能的 $DP$, 就是需要分奇偶讨论一下， 有一点烦。&lt;br /&gt;
今天晚上有点困啊。&lt;/p&gt;
&lt;h3&gt;2018-5-1&lt;/h3&gt;
&lt;p&gt;劳动节， 真是劳动。&lt;br /&gt;
数据结构专题。。。&lt;br /&gt;
不想说什么了， 气死了。&lt;br /&gt;
打完一个200多行的代码还没存电脑就死机了。&lt;br /&gt;
一晚上都在重新打， 现在还没打完。&lt;br /&gt;
还能不能改题了啊！！！！！！！！！&lt;/p&gt;
&lt;h3&gt;2018-5-2&lt;/h3&gt;
&lt;p&gt;没考试， 做提答题。&lt;br /&gt;
先来了一道&lt;a href=&quot;http://uoj.ac/problem/83&quot;&gt;UOJ83【UR #7】水题出题人&lt;/a&gt;&lt;br /&gt;
教你如何卡排序， 不过竟然要让&lt;a href=&quot;https://zh.wikipedia.org/wiki/Bogo%E6%8E%92%E5%BA%8F&quot;&gt;Bogo排序&lt;/a&gt;跑的比&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F&quot;&gt;快速排序&lt;/a&gt;快， 开什么玩笑， 让最不靠谱的排序跑到比最靠谱的快。。。 最后看了题解过去了。
然后是一道&lt;a href=&quot;http://uoj.ac/problem/56&quot;&gt;【WC2014】非确定机&lt;/a&gt;给出输出让你猜输入。&lt;br /&gt;
还剩一个点， 好像有点不好做， 不知道能不能做出来。&lt;/p&gt;
&lt;h3&gt;2018-5-3&lt;/h3&gt;
&lt;p&gt;考了一场水水的考试&lt;br /&gt;
让后继续做提答&lt;a href=&quot;http://uoj.ac/problem/224&quot;&gt;【NOI2016】旷野大计算&lt;/a&gt;&lt;br /&gt;
很神的一道题，还有两个点没过。&lt;br /&gt;
有时间写一下题解&lt;/p&gt;
&lt;h3&gt;2018-5-4&lt;/h3&gt;
&lt;p&gt;考了一场不错的考试&lt;br /&gt;
$T1$ 会 $30$ 分， $T2$ 搞出了60 分， $T3$ 40 一共 130。&lt;br /&gt;
然后改题， 先把$T2$改了。&lt;br /&gt;
然后是$T1$。
$T3$ 现在还没有改完。&lt;/p&gt;
&lt;h3&gt;2018-5-5&lt;/h3&gt;
&lt;p&gt;考了一下江苏省选题。&lt;br /&gt;
题目很神。&lt;br /&gt;
$T1$ 是一个叫做&lt;a href=&quot;https://en.wikipedia.org/wiki/Minkowski_addition&quot;&gt;闵可夫斯基和&lt;/a&gt;的东西，这玩意基本没有中文资料，然后看的是英文维基&lt;br /&gt;
$T2$ 是一个会了之后很简单的DP，不会死也想不出来。&lt;br /&gt;
$T3$ 是一道水题， 考场上直接A了。&lt;br /&gt;
发现&lt;a href=&quot;#2018-5-3&quot;&gt;5-3号&lt;/a&gt;提答的答案没存， 花了不少时间重新跑出来。
明天就出发了。&lt;br /&gt;
简单收拾一下东西。&lt;/p&gt;
</content:encoded></item><item><title>「CodePlus 2018 3 月赛」白金元首与莫斯科</title><link>https://www.nekomio.com/posts/146/</link><guid isPermaLink="true">https://www.nekomio.com/posts/146/</guid><pubDate>Fri, 13 Apr 2018 16:13:05 GMT</pubDate><content:encoded>&lt;h4&gt;题目描述&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;莫斯科吹的寒风 / 仿佛昨日那场梦 / 啊 你还会记得我吗&lt;/p&gt;
&lt;p&gt;1941.12.&lt;/p&gt;
&lt;p&gt;寒冷刺骨的天气、疲惫不堪的军队……包围首都的作战计划陷入了困境。空军或许是拯救战况的最后希望了，元首 Adolf 想道。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在一个 $n \times m$ 的网格区域中存在一个陆军单位需要补给，区域中的每个格子为空地或障碍物中的一种。航空舰队需要派遣若干运输机前往此区域，每一架运输机可以向两个相邻（有一条公共边）的空地投放物资。为防止不必要的损坏，一个标记为空地的格子至多只能得到一次投放。&lt;/p&gt;
&lt;p&gt;由于天气原因，陆军单位所在的确切位置并不能确定。因此元首想知道，对于每个空地格子，当陆军单位在其中（视作障碍物）时，用若干（可以为 $0$）架运输机向其余空地投放任意数量的物资的不同方案数。两个投放方案不同，当且仅当存在一个格子在一个方案中被投放而另一方案中未被投放，或存在两个被投放的格子，在一个方案中被同一架运输机投放而在另一方案中非然。若仍有疑问，请参考「样例 1 解释」。&lt;/p&gt;
&lt;p&gt;你需要编写程序帮助元首计算这些值对 $10^9+7$ 取模的结果。&lt;/p&gt;
&lt;h4&gt;输入格式&lt;/h4&gt;
&lt;p&gt;从标准输入读入数据。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第 $1$ 行：两个空格分隔的正整数 $n,m$ —— 网格区域的行数和列数。&lt;/li&gt;
&lt;li&gt;接下来 $n$ 行：其中第 $i$ 行包含 $m$ 个空格分隔的整数 $A_{i1},A_{i2},\ldots,A_{im}$ —— 其中 $A_{ij} = 0$ 表示第 $i$ 行第 $j$ 列的格子为&lt;strong&gt;空地&lt;/strong&gt;; $A_{ij} = 1$表示该格为&lt;strong&gt;障碍物&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;输出格式&lt;/h4&gt;
&lt;p&gt;输出到标准输出。&lt;/p&gt;
&lt;p&gt;对于每组数据输出 $n$ 行，第 $i$ 行包含 $m$ 个空格分隔的整数 $B_{i1}, B_{i2}, \ldots, B_{im}$ —— 若第 $i$ 行第 $j$ 列的格子为空地, $B_{ij}$ 为该格变为障碍物后投放的方案数；否则 $B_{ij} = 0$。&lt;/p&gt;
&lt;h4&gt;样例&lt;/h4&gt;
&lt;h5&gt;样例 1 输入&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;2 4
0 0 0 0
0 0 0 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;样例 1 输出&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;14 13 10 22
15 11 17 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;样例 1 解释&lt;/h5&gt;
&lt;p&gt;以第 $2$ 行第 $1$ 列的空地格为例，其变为障碍物后的网格如下图，其中白色格子代表空地，黑色格子代表障碍物。
&lt;img src=&quot;https://file.nekomio.com/picgo/1649776153426-146-1.webp&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
15 种方案如下图所示，不同颜色代表不同运输机的投放位置。
&lt;img src=&quot;https://file.nekomio.com/picgo/1649776168383-146-2.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h5&gt;样例 2 输入&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;4 5
0 0 0 1 1
1 0 0 0 1
1 0 0 0 0
0 0 0 0 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;样例 2 输出&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;1882 827 1523 0 0
0 1189 791 1529 0
0 1106 979 823 1315
1810 899 1136 1075 1189
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;数据范围与提示&lt;/h4&gt;
&lt;p&gt;对于所有数据，有 $1 \leq n, m \leq 17$，$A_{ij} \in {0, 1}$。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;子任务编号&lt;/th&gt;
&lt;th&gt;分值&lt;/th&gt;
&lt;th&gt;$n$&lt;/th&gt;
&lt;th&gt;$m$&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;$\leq 2$&lt;/td&gt;
&lt;td&gt;$\leq 17$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;$\leq 5$&lt;/td&gt;
&lt;td&gt;$\leq 5$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;$\leq 9$&lt;/td&gt;
&lt;td&gt;$\leq 9$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;$\leq 12$&lt;/td&gt;
&lt;td&gt;$\leq 12$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;$\leq 15$&lt;/td&gt;
&lt;td&gt;$\leq 15$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;$\leq 16$&lt;/td&gt;
&lt;td&gt;$\leq 16$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;$\leq 17$&lt;/td&gt;
&lt;td&gt;$\leq 17$&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;“Von allem Anfang an bin ich nur verraten und betrogen worden!”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;题面与史实不尽相符。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;来自 CodePlus 2018 3 月赛，清华大学计算机科学与技术系学生算法与竞赛协会 荣誉出品。&lt;br /&gt;
Credit：idea/吕时清　命题/吕时清　验题/吕欣，王聿中&lt;br /&gt;
Git Repo：&lt;a href=&quot;https://git.thusaac.org/publish/CodePlus3&quot;&gt;https://git.thusaac.org/publish/CodePlus3&lt;/a&gt;&lt;br /&gt;
感谢腾讯公司对此次比赛的支持。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;题解&lt;/h3&gt;
&lt;p&gt;首先我们可以想到这道题一定是用插头$DP$&lt;/p&gt;
&lt;p&gt;那么我们定义插头的状态 $1$ 为这个方向的格子与它为一架运输机投放&lt;br /&gt;
然后转移时注意一下合法性就可以了， 很是简单的一道 $DP$&lt;br /&gt;
这样的话枚举每一个格子为障碍。&lt;br /&gt;
时间复杂度为 $O(n^2m^22^{m+1})$&lt;/p&gt;
&lt;p&gt;但是这样并不能 $A$ 掉这道题， 事实上， 在 &lt;a href=&quot;https://loj.ac/problem/6301&quot;&gt;LibreOJ&lt;/a&gt; 它只能拿到 $33$ 分的好成绩。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://loj.ac/submission/89649&quot;&gt;33pts&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;正解&lt;br /&gt;
我们发现每次只有一个点不同&lt;br /&gt;
然后我们可以考虑合并。&lt;/p&gt;
&lt;p&gt;我们正反分别进行一次插头$DP$ 将所有的状态储存下来&lt;br /&gt;
在考虑一个块的时候&lt;/p&gt;
&lt;p&gt;将正反的 $DP$ 值乘起来就好了&lt;br /&gt;
需要判断一下合法性&lt;/p&gt;
&lt;p&gt;时间复杂度$O(nm2^{m+1}+nm2^{m+1})$&lt;/p&gt;
&lt;p&gt;没了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;stdint.h&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 200000, BASE = 76543;
const int32_t MOD = 1e9 + 7;
int f[20][20][(1 &amp;lt;&amp;lt; 18) + 1], g[20][20][(1 &amp;lt;&amp;lt; 18) + 1];
int a[20][20], ans[20][20];
// int tmp[(1 &amp;lt;&amp;lt; 18) + 1];
int DP1(int n, int m)
{
    // f[0].clear();
    int M = (1 &amp;lt;&amp;lt; (m + 1)) - 1;
    f[1][0][0] = 1;
    // int now = 0;
    // int Ans = 0;
    register int32_t k = 0, i, j;
    for (i = 1; i &amp;lt;= n; i++)
    {
        for (j = 1; j &amp;lt;= m; j++)
        {
            // now ^= 1;
            // f[now].clear();
            for (k = 0; k &amp;lt;= M; k++)
            {
                int S = k;
                int Sum = f[i][j - 1][k];
                char L = (S &amp;gt;&amp;gt; (j - 1)) &amp;amp; 1, U = (S &amp;gt;&amp;gt; j) &amp;amp; 1;
                if (a[i][j])
                {
                    if (L == 0 &amp;amp;&amp;amp; U == 0)
                        f[i][j][S] = (f[i][j][S] + Sum) % MOD;
                    continue;
                }
                else if (L == 1 &amp;amp;&amp;amp; U != 1)
                {
                    int nxt = S ^ (1 &amp;lt;&amp;lt; (j - 1));
                    f[i][j][nxt] = (f[i][j][nxt] + Sum) % MOD;
                }
                else if (L != 1 &amp;amp;&amp;amp; U == 1)
                {
                    int nxt = S ^ (1 &amp;lt;&amp;lt; j);
                    f[i][j][nxt] = (f[i][j][nxt] + Sum) % MOD;
                }
                else if (L != 1 &amp;amp;&amp;amp; U != 1)
                {
                    int nxt = S ^ (1 &amp;lt;&amp;lt; (j - 1));
                    if (i != n)
                        f[i][j][nxt] = (f[i][j][nxt] + Sum) % MOD;
                    nxt = S ^ (1 &amp;lt;&amp;lt; j);
                    if (j != m) 
                        f[i][j][nxt] = (f[i][j][nxt] + Sum) % MOD;
                    f[i][j][S] = (f[i][j][S] + Sum) % MOD;
                }
                // if (S == 0)
                //     Ans += Sum;
            }
        }
        for (int k = 0; k &amp;lt;= M; k++)
            f[i + 1][0][k &amp;lt;&amp;lt; 1] = f[i][m][k];
        // for (k = 0; k &amp;lt; f[now].p; k++)
        //     f[now].v[k].Id &amp;lt;&amp;lt;= 1;
    }
    return f[n][m][0];
}

// f-&amp;gt;g
int DP2(int n, int m)
{
    // f[0].clear();
    int M = (1 &amp;lt;&amp;lt; (m + 1)) - 1;
    g[n][m + 1][0] = 1;
    // int now = 0;
    // int Ans = 0;
    register int32_t k = 0, i, j;
    for (i = n; i &amp;gt;= 1; i--)
    {
        for (j = m; j &amp;gt;= 1; j--)
        {
            // now ^= 1;
            // f[now].clear();
            for (k = 0; k &amp;lt;= M; k++)
            {
                int S = k;
                int Sum = g[i][j + 1][k];
                char L = (S &amp;gt;&amp;gt; (j - 1)) &amp;amp; 1, U = (S &amp;gt;&amp;gt; j) &amp;amp; 1;
                if (a[i][j])
                {
                    if (L == 0 &amp;amp;&amp;amp; U == 0)
                        g[i][j][S] = (g[i][j][S] + Sum) % MOD;
                    continue;
                }
                else if (L == 1 &amp;amp;&amp;amp; U != 1)
                {
                    int nxt = S ^ (1 &amp;lt;&amp;lt; (j - 1));
                    g[i][j][nxt] = (g[i][j][nxt] + Sum) % MOD;
                }
                else if (L != 1 &amp;amp;&amp;amp; U == 1)
                {
                    int nxt = S ^ (1 &amp;lt;&amp;lt; j);
                    g[i][j][nxt] = (g[i][j][nxt] + Sum) % MOD;
                }
                else if (L != 1 &amp;amp;&amp;amp; U != 1)
                {
                    int nxt = S ^ (1 &amp;lt;&amp;lt; (j - 1));
                    if (j != 1)
                        g[i][j][nxt] = (g[i][j][nxt] + Sum) % MOD;
                    nxt = S ^ (1 &amp;lt;&amp;lt; j);
                    if (i != 1) 
                        g[i][j][nxt] = (g[i][j][nxt] + Sum) % MOD;
                    g[i][j][S] = (g[i][j][S] + Sum) % MOD;
                }
                // if (S == 0)
                //     Ans += Sum;
            }
        }
        for (int k = M; k &amp;gt;= 0; k--)
        // {
            g[i - 1][m + 1][k &amp;gt;&amp;gt; 1] = g[i][1][k];
            // printf (&quot;%d %d %d %d\n&quot;, k &amp;gt;&amp;gt; 1, k, g[i - 1][m + 1][k &amp;gt;&amp;gt; 1], g[i][1][k]);
        // }
        // for (k = 0; k &amp;lt; f[now].p; k++)
        //     f[now].v[k].Id &amp;lt;&amp;lt;= 1;
    }
    return g[1][1][0];
}
int main()
{

    char n = read(), m = read();
    register int i, j, k;
    for (i = 1; i &amp;lt;= n; i++)
        for (j = 1; j &amp;lt;= m; j++)
            a[i][j] = read();
    DP1(n, m), DP2(n, m);
    int M = (1 &amp;lt;&amp;lt; (m + 1)) - 1;
    for (i = 1; i &amp;lt;= n; i++)
        for (j = 1; j &amp;lt;= m; j++)
        {
            if (a[i][j]) continue;
            int Sum = 0;
            for (k = 0; k &amp;lt;= M; k++)
            {
                char L = (k &amp;gt;&amp;gt; (j - 1)) &amp;amp; 1, U = (k &amp;gt;&amp;gt; j) &amp;amp; 1;
                if (L == 0 &amp;amp;&amp;amp; U == 0)
                    (Sum += 1ll * f[i][j - 1][k] * g[i][j + 1][k] % MOD) %= MOD;
            }
            ans[i][j] = Sum;
        }
    for (i = 1; i &amp;lt;= n; i++)
        for (j = 1; j &amp;lt;= m; j++)
            printf (&quot;%d%c&quot;, ans[i][j], &quot; \n&quot;[j == m]);
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>「Codeforces Round #418」白金夜话</title><link>https://www.nekomio.com/posts/145/</link><guid isPermaLink="true">https://www.nekomio.com/posts/145/</guid><pubDate>Thu, 12 Apr 2018 14:08:21 GMT</pubDate><content:encoded>&lt;h4&gt;题目描述&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;いつまでも止まらない　この胸のときめきで　一緒に踊ろう&lt;br /&gt;
随着永不停息的这心中的悸动，一起来跳舞吧！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;给定坐标平面上 $n$ 个圆。任意两个圆的边界至多只有一个公共点 —— 即它们必定相离或相切。&lt;/p&gt;
&lt;p&gt;对于一个圆的集合，定义其异或面积为平面上被该集合中奇数个圆覆盖的图形面积。&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://file.nekomio.com/picgo/1649775990635-145-1.webp&quot; alt=&quot;Figure 1&quot; style=&quot;display: block; margin: 0 auto;&quot;&amp;gt;
&amp;lt;div style=&quot;text-align:center; color:#999;&quot;&amp;gt;对于这个集合，浅蓝色部分图形的面积被计入异或面积内。&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;现在需要将这 $n$ 个圆划分为两个集合，每个圆恰好在两个集合中的一个内。&lt;br /&gt;
&amp;lt;img src=&quot;https://file.nekomio.com/picgo/1649776008860-145-2.webp&quot; alt=&quot;Figure 2&quot; style=&quot;display: block; margin: 0 auto;&quot;&amp;gt;
&amp;lt;div style=&quot;text-align:center; color:#999;&quot;&amp;gt;对于这个集合，浅蓝色部分图形的面积被计入异或面积内。&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;请求出合法的划分方案中，两个集合分别计算的&lt;strong&gt;异或面积&lt;/strong&gt;之和的最大值。&lt;/p&gt;
&lt;h4&gt;输入格式&lt;/h4&gt;
&lt;p&gt;输入的第一行包含一个正整数 $n$ —— 圆的数目。&lt;/p&gt;
&lt;p&gt;接下来 $n$ 行，每行包含三个整数 $x_i, y_i, r_i$  —— 描述一个圆心位于 ($x_i, y_i$)、半径为 $r_i$ 的圆。&lt;/p&gt;
&lt;h4&gt;输出格式&lt;/h4&gt;
&lt;p&gt;输出一个十进制实数 —— 合法的划分方案中，两个集合&lt;strong&gt;异或面积&lt;/strong&gt;之和的最大值。&lt;/p&gt;
&lt;p&gt;当选手答案与参考答案的相对误差或绝对误差不超过 $10^{-9}$ 时被视为正确。形式化地，若选手输出为 $a$，参考答案为 $b$，答案被视为正确当且仅当 $\frac{|a-b|}{\max(1,|b|)} \leq 10^{-9}$。&lt;/p&gt;
&lt;h4&gt;样例&lt;/h4&gt;
&lt;h5&gt;样例输入 1&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;5
2 1 6
0 4 1
2 -1 3
1 -2 1
4 -1 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;样例输出 1&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;138.23007676
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;样例解释 1&lt;/h5&gt;
&lt;p&gt;样例 1 的最优方案与「题目描述」一节中的图形对应。&lt;/p&gt;
&lt;h5&gt;样例输入 2&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;8
0 0 1
0 0 2
0 0 3
0 0 4
0 0 5
0 0 6
0 0 7
0 0 8
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;样例输出 2&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;289.02652413
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;数据范围与提示&lt;/h4&gt;
&lt;p&gt;$1 \leq n \leq 1000$&lt;br /&gt;
$-10^6 \leq x_i,y_i \leq 10^6, 1 \leq r_i \leq 10^6$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ささやかだけど　かけがえのない　歴史を重ねて&lt;br /&gt;
渺小平凡却无可替代的事物一点点重现着历史&lt;br /&gt;
偽りさえも　本当になる　君の隣りで&lt;br /&gt;
即使谎言在你身旁也会变得如此真实&lt;br /&gt;
　　　　　　　　　　　　　　　　　　——「白金ディスコ」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;题解&lt;/h3&gt;
&lt;p&gt;其实不难吧, 但思路还是不错的。&lt;/p&gt;
&lt;p&gt;首先在平面的几何关系不是很好搞， 我们发现题目中保证&lt;strong&gt;必定相离或相切&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;那么圆就只有包含或者相离的关系&lt;/p&gt;
&lt;p&gt;可以抽象成一颗树(森林)。&lt;br /&gt;
在图中包含他的圆为他的祖先&lt;br /&gt;
那么我们一个圆的贡献就与他在树上的深度有关&lt;/p&gt;
&lt;p&gt;我们现在要把这个森林分成不相交的两部分&lt;/p&gt;
&lt;p&gt;考虑 $DP$&lt;br /&gt;
定义 $F[i][j][k]$ 表示以 $i$ 为根的子树一个集合的深度的奇偶为 $j$ 另一个为集合的深度的奇偶为 $k$ 的最大面积和
转移的时候先将子树合并&lt;br /&gt;
在枚举这个点放在哪个集合里&lt;/p&gt;
&lt;p&gt;就完了。。。&lt;/p&gt;
&lt;p&gt;好像还有一个贪心的做法。&lt;br /&gt;
但我不会啊。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 1005;
#define dis(_, __) (\
(((_).x - (__).x) * ((_).x - (__).x)) + \
(((_).y - (__).y) * ((_).y - (__).y))\
)
struct Circle
{
    double x, y, r;
    bool operator &amp;lt; (const Circle &amp;amp;b) const 
    {
        return r &amp;lt; b.r;
    }
}a[MAXN];
struct edge
{
    int END, next;
}v[MAXN &amp;lt;&amp;lt; 1];
int first[MAXN], p;
void add(int a, int b)
{
    v[p].END = b;
    v[p].next = first[a];
    first[a] = p++;
}
bool vis[MAXN];
double f[MAXN][2][2], tmp[MAXN][2][2];
void DFS(int rt, int fa)
{
    // vis[rt] = 1;
    for (int i = first[rt]; i != -1; i = v[i].next)
    {
        DFS(v[i].END, rt);
        for (int j = 0; j &amp;lt;= 1; j++)
            for (int k = 0; k &amp;lt;= 1; k++)
                tmp[rt][j][k] += f[v[i].END][j][k];
    }
    for (int i = 0; i &amp;lt;= 1; i++)
        for (int j = 0; j &amp;lt;= 1; j++)
        {
            f[rt][i][j] = max(
                tmp[rt][i ^ 1][j] + a[rt].r * a[rt].r * (i == 0 ? 1 : -1),
                tmp[rt][i][j ^ 1] + a[rt].r * a[rt].r * (j == 0 ? 1 : -1)
            );
        }
}
int main()
{
    memset (first, -1, sizeof (first));
    int n = read();
    for (int i = 1; i &amp;lt;= n; i++)
        a[i].x = read(), a[i].y = read(), a[i].r = read();
    sort(a + 1, a + n + 1);
    for (int i = 1; i &amp;lt;= n; i++)
        for (int j = i + 1; j &amp;lt;= n; j++)
            if (dis(a[i], a[j]) &amp;lt; a[j].r * a[j].r)
            {
                // printf (&quot;%d %d\n&quot;, j, i);
                add(j, i);
                vis[i] = 1;
                break;
            }
    // while (1);
    double ans = 0;
    for (int i = 1; i &amp;lt;= n; i++)
        if (!vis[i])
        {
            DFS(i, 0);
            ans += f[i][0][0];
        }
    printf (&quot;%.15f\n&quot;, ans * acos(-1.));
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>「清华集训 2017」小 Y 和恐怖的奴隶主</title><link>https://www.nekomio.com/posts/144/</link><guid isPermaLink="true">https://www.nekomio.com/posts/144/</guid><pubDate>Thu, 12 Apr 2018 10:25:17 GMT</pubDate><content:encoded>&lt;h4&gt;题目描述&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;A fight? Count me in!&quot; 要打架了，算我一个。&lt;br /&gt;
&quot;Everyone, get in here!&quot; 所有人，都过来！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;小Y是一个喜欢玩游戏的 OIer。一天，她正在玩一款游戏，要打一个 Boss。&lt;/p&gt;
&lt;p&gt;虽然这个 Boss 有 $10^{100}$ 点生命值，但它只带了一个随从——一个只有 $m$ 点生命值的“恐怖的奴隶主”。&lt;/p&gt;
&lt;p&gt;这个“恐怖的奴隶主”有一个特殊的技能：每当它被扣减生命值但没有死亡（死亡即生命值 $\leq 0$），且 Boss 的随从数量小于上限 $k$，便会召唤一个新的具有 $m$ 点生命值的“恐怖的奴隶主”。&lt;/p&gt;
&lt;p&gt;现在小Y可以进行 $n$ 次攻击，每次攻击时，会从 Boss 以及 Boss 的所有随从中的等概率随机选择一个，并扣减 $1$ 点生命值，她想知道进行 $n$ 次攻击后扣减 Boss 的生命值点数的期望。为了避免精度误差，你的答案需要对 $998244353$ 取模。&lt;/p&gt;
&lt;h4&gt;输入格式&lt;/h4&gt;
&lt;p&gt;输入第一行包含三个正整数 $T,m,k$ 表示询问组数，$m,k$ 的含义见题目描述。&lt;/p&gt;
&lt;p&gt;接下来 $T$ 行，每行包含一个正整数 $n$，表示询问进行 $n$ 次攻击后扣减 Boss 的生命值点数的期望。&lt;/p&gt;
&lt;h4&gt;输出格式&lt;/h4&gt;
&lt;p&gt;输出共 $T$ 行，对于每个询问输出一行一个非负整数，表示该询问的答案对 $998244353$ 取模的结果。&lt;/p&gt;
&lt;p&gt;可以证明，所求期望一定是一个有理数，设其为$p/q (\mathrm{gcd}(p,q) = 1)$  那么你输出的数 $x$ 要满足 $p \equiv qx \mod 998244353$。&lt;/p&gt;
&lt;h4&gt;样例&lt;/h4&gt;
&lt;h5&gt;输入&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;3 2 6
1
2
3
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;输出&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;499122177
415935148
471393168
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;数据范围与提示&lt;/h4&gt;
&lt;p&gt;在所有测试点中, $1\leq T \leq 1000, 1 \leq n \leq 10^{18}, 1 \leq m \leq 3, 1 \leq k \leq 8$&lt;/p&gt;
&lt;p&gt;各个测试点的分值和数据范围如下：&lt;/p&gt;
&lt;p&gt;&amp;lt;table&amp;gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th rowspan=&quot;1&quot;&amp;gt;测试点编号&amp;lt;/th&amp;gt;&amp;lt;th rowspan=&quot;1&quot;&amp;gt;分值&amp;lt;/th&amp;gt;&amp;lt;th rowspan=&quot;1&quot;&amp;gt;$T=$&amp;lt;/th&amp;gt;&amp;lt;th rowspan=&quot;1&quot;&amp;gt;$n \leq $&amp;lt;/th&amp;gt;&amp;lt;th rowspan=&quot;1&quot;&amp;gt;$m=$&amp;lt;/th&amp;gt;&amp;lt;th rowspan=&quot;1&quot;&amp;gt;$k=$&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;1&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;3&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;4&quot;&amp;gt;10&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;2&quot;&amp;gt;10&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;1&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;1&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;2&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;8&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;3&quot;&amp;gt;2&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;8&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;3&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;7&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;8&quot;&amp;gt;$10^{18}$&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;3&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;4&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;12&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;7&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;5&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;30&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;20&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;6&quot;&amp;gt;3&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;5&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;6&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;10&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;500&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;6&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;7&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;10&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;200&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;2&quot;&amp;gt;7&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;8&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;5&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;1000&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;9&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;10&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;100&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;2&quot;&amp;gt;8&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;10&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;5&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;500&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/tbody&amp;gt;&amp;lt;/table&amp;gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;h4&gt;20pts&lt;/h4&gt;
&lt;p&gt;可以直接$DP$&lt;br /&gt;
同&lt;a href=&quot;/2017/08/03/59/&quot;&gt;[BZOJ 4832] [Lydsy2017年4月月赛]抵制克苏恩&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;100pts&lt;/h4&gt;
&lt;p&gt;发现每次转移都是一样的&lt;br /&gt;
然后就可以矩阵快速幂了。&lt;br /&gt;
然而并不能过 2333&lt;/p&gt;
&lt;p&gt;时间复杂度为$O(Tcnt^3log(n))$, $cnt$不会超过200。&lt;br /&gt;
我们还需要优化&lt;/p&gt;
&lt;p&gt;我们可以将转移矩阵的 $k$ 次方全部预处理出来， 然后用一个 $1 \times cnt$ 的矩阵不断的去乘, 这样时间复杂度会被降到 $O(cnt^3log(n) + Tcnt^2log(n))$
就可以过了。&lt;/p&gt;
&lt;p&gt;好像是道水题&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline long long read()
{
    long long x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MOD = 998244353;
struct Matrix
{
    int a[200][200];
    int n, m;
    Matrix(int _n = 0, int _m = 0)
    {
        n = _n, m = _m;
        memset (a, 0, sizeof (a));
    }
    Matrix operator * (const Matrix &amp;amp;b) const 
    {
        Matrix ans(n, b.m);
        for (int i = 1; i &amp;lt;= n; i++)
            for (int j = 1; j &amp;lt;= m; j++)
                for (int k = 1; k &amp;lt;= b.m; k++)
                    ans.a[i][k] = (ans.a[i][k] + 1ll * a[i][j] * b.a[j][k]) % MOD;
        return ans;
    }
}A[64];
long long pow_mod(long long a, int b)
{
    long long ans = 1;
    while (b)
    {
        if (b &amp;amp; 1) ans = ans * a % MOD;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % MOD;
    }
    return ans;
}
int cnt[10][10][10], Index, IDans;
int main()
{
    int T = read(), m = read(), k = read();
    for (int i = 0; i &amp;lt;= k; i++)
        for (int j = 0; j &amp;lt;= (m == 1 ? 0 : k); j++)
            for (int l = 0; l &amp;lt;= ((m == 1 || m == 2) ? 0 : k); l++) if (i + j + l &amp;lt;= k)
                cnt[i][j][l] = ++Index;
    IDans = ++Index;
    if (m == 1)
    {
        for (int i = 0; i &amp;lt;= k; i++)
        {
            if (i &amp;gt; 0) (A[0].a[cnt[i][0][0]][cnt[i - 1][0][0]] += i * pow_mod(i + 1, MOD - 2) % MOD) %= MOD;
            (A[0].a[cnt[i][0][0]][cnt[i][0][0]] += pow_mod(i + 1, MOD - 2)) %= MOD;
            (A[0].a[cnt[i][0][0]][IDans] += pow_mod(i + 1, MOD - 2)) %= MOD;
        }
        A[0].a[IDans][IDans] = 1;
    }
    else if (m == 2)
    {
        for (int j = 0; j &amp;lt;= k; j++)
            for (int l = 0; l &amp;lt;= k; l++) if (l + j &amp;lt;= k)
            {
                if (l &amp;gt;= 1 &amp;amp;&amp;amp; j + l + 1 &amp;lt;= k) 
                    (A[0].a[cnt[j][l][0]][cnt[j + 1][l][0]] += pow_mod(j + l + 1, MOD - 2) * l % MOD) %= MOD;
                if (l &amp;gt;= 1 &amp;amp;&amp;amp; j + l + 1 &amp;gt; k)
                    (A[0].a[cnt[j][l][0]][cnt[j + 1][l - 1][0]] += pow_mod(j + l + 1, MOD - 2) * l % MOD) %= MOD;
                if (j &amp;gt;= 1)
                    (A[0].a[cnt[j][l][0]][cnt[j - 1][l][0]] += pow_mod(j + l + 1, MOD - 2) * j % MOD) %= MOD;
                (A[0].a[cnt[j][l][0]][cnt[j][l][0]] += pow_mod(j + l + 1, MOD - 2)) %= MOD;
                (A[0].a[cnt[j][l][0]][IDans] += pow_mod(j + l + 1, MOD - 2)) %= MOD;
            }
        A[0].a[IDans][IDans] = 1;
    }
    else
    {
        for (int i = 0; i &amp;lt;= k; i++)
            for (int j = 0; j &amp;lt;= k; j++)
                for (int l = 0; l &amp;lt;= k; l++) if (i + j + l &amp;lt;= k)
                {
                    if (i &amp;gt; 0)
                        (A[0].a[cnt[i][j][l]][cnt[i - 1][j][l]] += i * pow_mod(i + j + l + 1, MOD - 2) % MOD) %= MOD;
                    if (j &amp;gt; 0)
                    {
                        if (i + j + l + 1 &amp;lt;= k) 
                            (A[0].a[cnt[i][j][l]][cnt[i + 1][j - 1][l + 1]] += j * pow_mod(i + j + l + 1, MOD - 2) % MOD) %= MOD;
                        else 
                            (A[0].a[cnt[i][j][l]][cnt[i + 1][j - 1][l]] += j * pow_mod(i + j + l + 1, MOD - 2) % MOD) %= MOD;
                    }
                    if (l &amp;gt; 0)
                    {
                        if (i + j + l + 1 &amp;lt;= k) 
                            (A[0].a[cnt[i][j][l]][cnt[i][j + 1][l]] += l * pow_mod(i + j + l + 1, MOD - 2) % MOD) %= MOD;
                        else 
                            (A[0].a[cnt[i][j][l]][cnt[i][j + 1][l - 1]] += l * pow_mod(i + j + l + 1, MOD - 2) % MOD) %= MOD;
                    }
                    (A[0].a[cnt[i][j][l]][cnt[i][j][l]] += pow_mod(i + j + l + 1, MOD - 2)) %= MOD;
                    (A[0].a[cnt[i][j][l]][IDans] += pow_mod(i + j + l + 1, MOD - 2)) %= MOD;
                }
        A[0].a[IDans][IDans] = 1;
    }
    A[0].n = A[0].m = Index;
    for (int i = 1; i &amp;lt;= 63; i++)
        A[i] = A[i - 1] * A[i - 1];
    while (T--)
    {
        Matrix B(1, Index);
        B.a[1][cnt[m == 1][m == 2][m == 3]] = 1;
        long long n = read();
        for (int i = 0; i &amp;lt;= 63; i++)
            if (n &amp;amp; (1ll &amp;lt;&amp;lt; i))
                B = B * A[i];
        printf (&quot;%d\n&quot;, B.a[1][IDans]);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>「LibreOJ Round #8」MINIM</title><link>https://www.nekomio.com/posts/143/</link><guid isPermaLink="true">https://www.nekomio.com/posts/143/</guid><pubDate>Wed, 11 Apr 2018 20:27:50 GMT</pubDate><content:encoded>&lt;h4&gt;题目描述&lt;/h4&gt;
&lt;p&gt;取石子游戏的规则是这样的：有若干堆石子，两个玩家轮流操作，每个玩家每次要选一堆取走任意多个石子，但不能不取，无石子可取者输。&lt;/p&gt;
&lt;p&gt;现在共有 $n$ 堆石子，其中第 $i$ 堆的数量为 $l_i$，现在 LCR 需要在每一堆中扔掉一部分（可以不扔也可以全扔），如果第 $i$ 堆的石子在 LCR 操作后&lt;strong&gt;还有剩余&lt;/strong&gt;，LCR 就需要付出 $v_i$ 的代价。LCR 操作完成后神犇会搬来新的一堆个数在 $[0,m]$ 之间的石子，两人玩取石子游戏，LCR 先手。神犇搬运新的一堆石子时会保证自己（后手）必胜，如果他无法做到这一点，就会立即结束游戏。&lt;/p&gt;
&lt;p&gt;现在 LCR 有 $q$ 次询问，每次给出一个 $c\in [0,m]$，请你回答如果要让神犇搬来的石子数为 $c$（不能让神犇结束游戏，即使这里要求 $c=0$），LCR 付出代价的总和至少是多少。如果 LCR 不可能通过调整石子使得神犇搬来的石子数为 $c$，输出 &lt;code&gt;-1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;NIM is a game of strategy in which two players take turns removing stones from distinct piles. On each turn, a player must remove at least one stone, and may remove any number of stones provided they all come from the same pile. &lt;strong&gt;The player who has no stones to remove loses.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are $n$ piles of stones, the $i$-th pile has $l_i$ stones. Alice needs to remove some of the stones from each pile (removing zero or all of the stones from a certain pile is allowed). If the $i$-th pile remains at least one stone after this operation, Alice has to pay a price of $v_i$. After Alice&apos;s operation, Bob will create a pile of stones whose number is in $[0,m]$ and add it to the game to make sure that Alice — the player who moves first in this NIM game will lose.If he can&apos;t ensure that Alice will lose,he will exit from the game immediately.&lt;/p&gt;
&lt;p&gt;Now Alice has $q$ queries. Each query gives an integer $c$, and you need to calculate the minimal total price Alice needs to pay to ensure Bob’s new pile has exactly $c$ stones(making Bob exit from the game isn&apos;t allowed,even if $c=0$). If this is impossible, print &lt;code&gt;-1&lt;/code&gt; instead.&lt;/p&gt;
&lt;h4&gt;输入格式&lt;/h4&gt;
&lt;p&gt;第一行两个正整数 $n,m$。&lt;br /&gt;
接下来 $n$ 行每行两个正整数 $v_i,l_i$ 表示该堆石子的代价和数量。&lt;br /&gt;
接下来一行一个正整数 $q$。&lt;br /&gt;
接下来 $q$ 行每行一个正整数 $c$ 表示询问。&lt;/p&gt;
&lt;p&gt;The first line contains two integers $n,m$.&lt;br /&gt;
Each of the following $n$ lines contains two integers $v_i,l_i$.&lt;br /&gt;
The next line contains an integer $q$. Each of the following $n$ lines contains an integers $c$.&lt;/p&gt;
&lt;h4&gt;输出格式&lt;/h4&gt;
&lt;p&gt;输出共 $q$ 行，依次表示每次询问的答案，无解输出 &lt;code&gt;-1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;Output contains $q$ lines,containing the answer of each query in order.&lt;/p&gt;
&lt;h4&gt;样例&lt;/h4&gt;
&lt;h5&gt;样例输入 Sample Input&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;4 6
2 3
4 4
3 5
5 2
7
0
1
2
3
4
5
6
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;样例输出 Sample Output&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;0
2
2
2
3
3
5
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;数据范围与提示&lt;/h4&gt;
&lt;p&gt;对于所有数据，$1 \leq n,q \leq 10^5, 1 \leq v_i \leq 10^9, 0 \leq l_i \leq m \leq 10^9, c \in [0, m]$。&lt;/p&gt;
&lt;p&gt;详细的数据限制及约定如下（留空表示和上述所有数据的约定相同）&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Subtask #&lt;/th&gt;
&lt;th&gt;分值（百分比）&lt;/th&gt;
&lt;th&gt;$n,q$&lt;/th&gt;
&lt;th&gt;$l_i,m$&lt;/th&gt;
&lt;th&gt;特殊性质&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;$\leq 10$&lt;/td&gt;
&lt;td&gt;$\leq 10$&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;$\leq 100$&lt;/td&gt;
&lt;td&gt;$\leq 100$&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;对于每个 $i$ 存在非负整数 $k$ 满足 $l_i=2^k-1$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;$\leq 20000$&lt;/td&gt;
&lt;td&gt;$\leq 20000$&lt;/td&gt;
&lt;td&gt;$l_i,v_i$ 在范围内均匀随机（使用 &lt;code&gt;std::mt19937&lt;/code&gt; 并对最大值取模）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;$l_i,v_i$ 在范围内均匀随机（使用 &lt;code&gt;std::mt19937&lt;/code&gt; 并对最大值取模）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;h3&gt;Subtask 1&lt;/h3&gt;
&lt;p&gt;直接爆搜&lt;/p&gt;
&lt;h3&gt;Subtask 2&lt;/h3&gt;
&lt;p&gt;考虑 $DP$&lt;br /&gt;
因为想要使得后手必胜，则初始状态的异或值为 $0$ , 那么就可以 $DP$ 了, 如果想要让神犇搬来的石子数为 $c$ 则前面的异或值需要为 $c$&lt;br /&gt;
然后定义 $f[i][j]$ 表示 $DP$ 到 $i$ 异或值为 $j$ 的最小花费， 暴力转移即可&lt;br /&gt;
时间复杂度$O(nm^2)$&lt;br /&gt;
&lt;a href=&quot;https://loj.ac/submission/88276&quot;&gt;35pts&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Subtask 3&lt;/h3&gt;
&lt;p&gt;这部分所有的 $i$ 存在非负整数 $k$ 满足 $l_i=2^k-1$&lt;br /&gt;
可以发现最优解一定是选一个&lt;br /&gt;
我们只要找大于等于 $c$ 的数中 $v_i$ 的最小值就可以了&lt;br /&gt;
&lt;a href=&quot;https://loj.ac/submission/88286&quot;&gt;55pts&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Subtask 4 &amp;amp; 5&lt;/h3&gt;
&lt;p&gt;我们发现 &lt;a href=&quot;#Subtask-2&quot;&gt;Subtask 2&lt;/a&gt; 中的每一层 $f$ 数组是分段的&lt;br /&gt;
当数据随机时可以证明: &lt;strong&gt;段数的期望是常数&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;https://loj.ac/article/322&quot;&gt;CommonAnts的证明&lt;/a&gt;是这样的&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;考虑最小的一对满足 $m$ 以内二进制最高位均为 $1$ 的 $l_i,l_j$，那么这一对可以保证 $DP$ 数组的任意位置不超过 $v_i+v_j$。又根据算法四的分析，每一个权值和不超过 $v_i+v_j$ 的子集的贡献不超过一段。&lt;br /&gt;
由于随机，$v_i$ 的分布是均匀的，故枚举 $i,j$ 计算概率可得期望段数不超过 $\sum_{i \leq j}{2^{-j}\sum_{k=1}^{i+j}{S(i+j-\binom{k-1}{2}, k)}} = O(1)$ ($S$ 表示第二类斯特林数)&lt;br /&gt;
对于 $m$ 不是 $2$ 的幂的情况，可以分最高位和次高位分别分析，每一位产生的贡献都不超过上述的常数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然后就可以记录段数转移了&lt;br /&gt;
时间复杂度 $O(n+q)$ (Subtask 4 &amp;amp; 5) 或 $O(nlog(n))$ (Subtask 3) 或 $O(nm)$ (Subtask 1 &amp;amp; 2)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
inline void gmin(int &amp;amp;a, int b) { if (a &amp;gt; b) a = b; }
const int MAXN = 100005;
int M;
struct data
{
    int v, l;
    data(int _v = 0, int _l = 0) : v(_v), l(_l) {}
    data operator + (const data &amp;amp;a) const 
    {
        data c(v + a.v, l | a.l);
        for (int i = M; i &amp;gt;= 0; i--)
            if (l &amp;amp; a.l &amp;amp; (1 &amp;lt;&amp;lt; i))
            {
                c.l |= ((1 &amp;lt;&amp;lt; (i + 1)) - 1);
                break;
            }
        return c;
    }
    bool operator &amp;lt; (const data &amp;amp;a) const 
    {
        return v &amp;lt; a.v;
    }
}a[MAXN], s[MAXN], t[MAXN], tmp[MAXN];
int cnt, len;
int Calc(int x)
{
    for (int i = 1; i &amp;lt;= cnt; i++)
        if (s[i].l &amp;gt;= x)
            return s[i].v;
    return -1;
}
int main()
{
    // freopen (&quot;1.out&quot;, &quot;w&quot;, stdout);
    int n = read(), m = read();
    for (int i = 1; i &amp;lt;= n; i++)
        a[i].v = read(), a[i].l = read();
    for (M = 31; M &amp;amp;&amp;amp; (1 &amp;lt;&amp;lt; (M - 1)) &amp;gt;= m; M--);
    s[++cnt] = data(0, 0);
    tmp[0] = data(0, -1);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        for (int j = 1; j &amp;lt;= cnt; j++) 
            t[j] = s[j] + a[i];
        len = 0;
        int j = 0, k = 0, l;
        while (j &amp;lt; cnt || k &amp;lt; cnt)
        {
            data tp = j &amp;gt;= cnt ? t[++k] : (k &amp;gt;= cnt ? s[++j] : s[j + 1] &amp;lt; t[k + 1] ? s[++j] : t[++k]);
            for (l = 1; l &amp;lt;= len; l++)
                if (tmp[l].l &amp;gt;= tp.l)
                    break;
            if (l == len + 1)
                tmp[++len] = tp;
        }
        for (int j = 1; j &amp;lt;= len; j++)
            s[j] = tmp[j];
        cnt = len;
    }
    int q = read();
    while (q--)
    {
        printf (&quot;%d\n&quot;, Calc(read()));
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>「LibreOJ Round #6」花火</title><link>https://www.nekomio.com/posts/142/</link><guid isPermaLink="true">https://www.nekomio.com/posts/142/</guid><pubDate>Wed, 11 Apr 2018 10:46:10 GMT</pubDate><content:encoded>&lt;h4&gt;题目描述&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;「Hanabi, hanabi……」&lt;br /&gt;
一听说祭典上没有烟火，Karen 一脸沮丧。&lt;br /&gt;
「有的哦…… 虽然比不上大型烟花就是了。」&lt;br /&gt;
还好 Shinobu 早有准备，Alice、Ayaya、Karen、Shinobu、Yoko 五人又能继续愉快地玩耍啦！&lt;br /&gt;
「噢……！不是有放上天的烟花嘛！」Karen 兴奋地喊道。&lt;br /&gt;
「啊等等……」Yoko 惊呼。Karen 手持点燃引信的烟花，「嗯？？」&lt;br /&gt;
Yoko 最希望见到的是排列优美的烟火，当然不会放过这个机会…… 不过时间似乎已经不多了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;$n$ 个烟火排成一排，从左到右高度分别为 $h_1, h_2, \cdots, h_n$，这些高度两两不同。&lt;br /&gt;
每次 Yoko 可以选择两个相邻的烟火交换，这样的交换可以进行任意多次。&lt;br /&gt;
每次 Yoko 还可以选择两个不相邻的烟火交换，但这样的交换至多进行一次。&lt;br /&gt;
你的任务是帮助 Yoko 用最少次数的交换，使这些烟火从左到右的高度递增。&lt;/p&gt;
&lt;h4&gt;输入格式&lt;/h4&gt;
&lt;p&gt;第一行包含一个正整数 $n$。&lt;br /&gt;
第二行包含 $n$ 个正整数 $h_1, h_2, \cdots, h_n$，相邻整数之间用一个空格隔开。&lt;/p&gt;
&lt;h4&gt;输出格式&lt;/h4&gt;
&lt;p&gt;输出一个整数，表示最少的交换次数。&lt;/p&gt;
&lt;h4&gt;样例&lt;/h4&gt;
&lt;h5&gt;样例输入&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;5
3 5 4 1 2
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;样例输出&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;5
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;样例解释&lt;/h5&gt;
&lt;p&gt;一开始，$5$ 个烟火的高度依次为 $3,5,4,1,2$。&lt;br /&gt;
第 $1$ 次，交换第 $4$ 根烟火和第 $5$ 根烟火，交换后烟火的高度依次为 $3,5,4,2,1$。&lt;br /&gt;
第 $2$ 次，交换第 $3$ 根烟火和第 $4$ 根烟火，交换后烟火的高度依次为 $3,5,2,4,1$。&lt;br /&gt;
第 $3$ 次，交换第 $1$ 根烟火和第 $2$ 根烟火，交换后烟火的高度依次为 $5,3,2,4,1$。&lt;br /&gt;
第 $4$ 次，交换第 $2$ 根烟火和第 $3$ 根烟火，交换后烟火的高度依次为 $5,2,3,4,1$。&lt;br /&gt;
第 $5$ 次，交换第 $1$ 根烟火和第 $5$ 根烟火，交换后烟火的高度依次为 $1,2,3,4,5$。&lt;br /&gt;
可以证明这是交换次数最少的方案。&lt;/p&gt;
&lt;h4&gt;数据范围与提示&lt;/h4&gt;
&lt;p&gt;对于所有数据，满足 $1 \leq n \leq 300,000, 1 \leq h_i \leq n, h_i$互不相同。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Subtask #&lt;/th&gt;
&lt;th&gt;分值&lt;/th&gt;
&lt;th&gt;$n$&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;$6$&lt;/td&gt;
&lt;td&gt;$\leq 4$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;$11$&lt;/td&gt;
&lt;td&gt;$\leq 8$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;$16$&lt;/td&gt;
&lt;td&gt;$\leq 100$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;$8$&lt;/td&gt;
&lt;td&gt;$\leq 300$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;$13$&lt;/td&gt;
&lt;td&gt;$\leq 700$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;$7$&lt;/td&gt;
&lt;td&gt;$\leq 2,000$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;$6$&lt;/td&gt;
&lt;td&gt;$\leq 6,000$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;$14$&lt;/td&gt;
&lt;td&gt;$\leq 60,000$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;$19$&lt;/td&gt;
&lt;td&gt;$\leq 300,000$&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;h3&gt;Subtask 1 &amp;amp; 2&lt;/h3&gt;
&lt;p&gt;直接去搜吧，记忆化一下&lt;br /&gt;
因为与$DP$没关系， 就不写了&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Subtask 3&lt;/h3&gt;
&lt;p&gt;需要一个多项式复杂度的做法&lt;br /&gt;
我们可以证明&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;总是可以假设交换不相邻元素在第一次进行。&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;证明:&lt;/strong&gt; 假设交换的两个值为 $x$ 和 $y$ 那么， 我们可以在第一次就交换他们然后可以构造出一个与原先交换次数相同的解&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;如果已经交换了不相邻元素，之后的最小交换次数等于此时排列的逆序对数。&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;证明:&lt;/strong&gt; 设这一次交换的数为 $h[i]$ 与 $h[i + 1]$ 则这一次交换后他们与其他数$(j \neq i, j \neq i + 1)$的逆序对数是不变的。 那么改变的只有他们之间的关系。 又因为一个含有逆序对的数列中一定存在 $h[i] &amp;gt; h[i + 1]$ 所以只有不断的找到这样的数对交换即可， 每次交换减少一个逆序对， 交换次数为逆序对数。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;可以 $n^2$ 枚举第一次交换的两个数， 然后 $n^2$ 求逆序对&lt;br /&gt;
时间复杂度$O(n^4)$&lt;br /&gt;
&lt;a href=&quot;https://loj.ac/submission/87860&quot;&gt;33pts&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Subtask 4&lt;/h3&gt;
&lt;p&gt;与上面的相同， 只是用随便的一些方法将逆序对用 $n \log(n)$ 求&lt;br /&gt;
&lt;a href=&quot;https://loj.ac/submission/87888&quot;&gt;41pts&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Subtask 5&lt;/h3&gt;
&lt;p&gt;这时我们需要一个 $O(n^3)$ 的做法&lt;br /&gt;
因为每次交换所改变的逆序对数很少， 只要先求出来再 $O(n)$ 维护即可&lt;br /&gt;
&lt;a href=&quot;https://loj.ac/submission/87943&quot;&gt;54pts&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Subtask 6 &amp;amp; 7&lt;/h3&gt;
&lt;p&gt;每次改变的逆序对并不用 $O(n)$ 求&lt;br /&gt;
将 $(x, h_x)$ 看做平面上的点&lt;br /&gt;
在第一次交换的时候， 只有当 $h[i] &amp;gt; h[j]$ 时才有意义&lt;br /&gt;
然后我们发现这时减少的逆序对数就是以 $(i, h[i])$ 为左上角 $(j, h[j])$ 为右下角的矩形内部点数的二倍&lt;br /&gt;
然后用一个二维前缀和就可以了&lt;br /&gt;
&lt;a href=&quot;https://loj.ac/submission/88043&quot;&gt;67pts&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Subtask 8 &amp;amp; 9&lt;/h3&gt;
&lt;p&gt;到这里其实就比较显然了&lt;br /&gt;
我们想要找的是一对点作为左上角与右下角使得其矩形内的点数最多。&lt;br /&gt;
这显然和我们做过的一道题一样， 然后用线段树维护就好了&lt;br /&gt;
时间复杂度 $O(n\log(n))$&lt;br /&gt;
&lt;s&gt;不知道为什么我的程序又长又慢 2333&lt;/s&gt;&lt;br /&gt;
知道了，我作死用的平衡树。。。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;set&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 300005;
#define size(_) ((_) ? (_)-&amp;gt;s : 0)
#define _Max(_) ((_) ? (_)-&amp;gt;Max : 0)
struct Node
{
    Node *ch[2];
    int s, v, key;
    int val, Max, lazy;
    Node(int x)
    {
        s = 0, v = x;
        key = rand();
        val = lazy = Max = 1;
        ch[0] = ch[1] = NULL;
    }
    void Pushup()
    {
        s = size(ch[0]) + size(ch[1]) + 1;
        Max = max(max(_Max(ch[0]), _Max(ch[1])), val);
    }
    void Pushlazy(int x)
    {
        val += x;
        lazy += x;
        Max += x;
    }
    void Pushdown()
    {
        if (lazy)
        {
            if (ch[0]) ch[0]-&amp;gt;Pushlazy(lazy);
            if (ch[1]) ch[1]-&amp;gt;Pushlazy(lazy);
            lazy = 0;
        }
    }
}*root;
Node *Merge(Node *A, Node *B)
{
    if (!A) return B;
    if (!B) return A;
    if (A-&amp;gt;key &amp;lt; B-&amp;gt;key)
    {
        A-&amp;gt;Pushdown();
        A-&amp;gt;ch[1] = Merge(A-&amp;gt;ch[1], B);
        A-&amp;gt;Pushup();
        return A;
    }
    else
    {
        B-&amp;gt;Pushdown();
        B-&amp;gt;ch[0] = Merge(A, B-&amp;gt;ch[0]);
        B-&amp;gt;Pushup();
        return B;
    }
}
typedef pair&amp;lt;Node*, Node*&amp;gt; DNode;
DNode Split(Node *rt, int k)
{
    if (!rt) return DNode(NULL, NULL);
    DNode o;
    rt-&amp;gt;Pushdown();
    if (size(rt-&amp;gt;ch[0]) &amp;gt;= k)
    {
        o = Split(rt-&amp;gt;ch[0], k);
        rt-&amp;gt;ch[0] = o.second;
        rt-&amp;gt;Pushup();
        o.second = rt;
    }
    else
    {
        o = Split(rt-&amp;gt;ch[1], k - size(rt-&amp;gt;ch[0]) - 1);
        rt-&amp;gt;ch[1] = o.first;
        rt-&amp;gt;Pushup();
        o.first = rt;
    }
    return o;
}
int Rank(Node *rt, int x)
{
    if (!rt) return 0;
    return x &amp;lt;= rt-&amp;gt;v ? Rank(rt-&amp;gt;ch[0], x) : Rank(rt-&amp;gt;ch[1], x) + size(rt-&amp;gt;ch[0]) + 1;
}
void Insert(int x)
{
    int k = Rank(root, x);
    DNode y = Split(root, k);
    Node *n = new Node(x);
    root = Merge(y.first, Merge(n, y.second));
}
void Update(int x, int c)
{
    int k = Rank(root, x);
    DNode y = Split(root, k);
    if (y.second) y.second-&amp;gt;Pushlazy(c);
    root = Merge(y.first, y.second);
}
void Update(int l, int r, int c)
{
    int k = Rank(root, l);
    DNode x = Split(root, k);
    int k2 = Rank(x.second, r + 1);
    DNode y = Split(x.second, k2);
    if (y.first) y.first-&amp;gt;Pushlazy(c);
    root = Merge(x.first, Merge(y.first, y.second));
}
int Calc_Max(Node *rt)
{
    if (!rt-&amp;gt;ch[1]) return rt-&amp;gt;v;
    else return Calc_Max(rt-&amp;gt;ch[1]);
}
int Query(int x)
{
    int k = Rank(root, x);
    DNode y = Split(root, k);
    int ans = _Max(y.second);
    root = Merge(y.first, y.second);
    return ans + 1;
}
set&amp;lt;int&amp;gt; t1, t2;
struct data
{
    int v, id, Mx;
    bool operator &amp;lt; (const data &amp;amp;a) const
    {
        return v &amp;lt; a.v;
    }
};
set&amp;lt;data&amp;gt; t3;
int n;
int a[MAXN], b[MAXN];
long long S[MAXN];
#define lowbit(_) ((_) &amp;amp; (-_))
void add(int x, int c)
{
    for (int i = x; i &amp;lt;= n; i += lowbit(i))
        S[i] += c;
}
long long Q(int x)
{
    long long ans = 0;
    for (int i = x; i &amp;gt;= 1; i -= lowbit(i))
        ans += S[i];
    return ans;
}
int st1[MAXN], st2[MAXN], top1, top2;
int main()
{
    // freopen (&quot;columns3_2.in&quot;, &quot;r&quot;, stdin);
    // freopen (&quot;columns.out&quot;, &quot;w&quot;, stdout);
    n = read();
    for (int i = 1; i &amp;lt;= n; i++)
        b[i] = a[i] = read();
    sort(b + 1, b + n + 1);
    for (int i = 1; i &amp;lt;= n; i++)
        a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b;
    long long Sum = 0;
    for (int i = 1; i &amp;lt;= n; i++)
        Sum += Q(n) - Q(a[i]), add(a[i], 1);
    st1[++top1] = 1;
    t1.insert(1);
    for (int i = 2; i &amp;lt;= n; i++)
        if (a[i] &amp;gt; a[st1[top1]])
            st1[++top1] = i, t1.insert(i);
    st2[++top2] = n;
    t2.insert(n);
    for (int i = n - 1; i &amp;gt;= 1; i--)
        if (a[i] &amp;lt; a[st2[top2]])
            st2[++top2] = i, t2.insert(i);
    reverse(st2 + 1, st2 + top2 + 1);
    int ans = 0;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        if (!t1.count(i) &amp;amp;&amp;amp; !t2.count(i))
        {
            Update(a[i], 1);
            t3.insert((data){a[i], i, Calc_Max(root)});
        }
        else
        {
            if (t1.count(i))
                Insert(a[i]);
            if (t2.count(i))
            {
                for (auto x : t3)
                    if (x.v &amp;gt; a[i]) break;
                    else
                        Update(x.v, x.Mx, -1);
                auto x2 = t3.begin();
                if (x2 != t3.end()) x2++;
                for (auto x = t3.begin(); x != t3.end(); )
                {
                    if (x-&amp;gt;v &amp;gt; a[i]) break;
                    else
                        t3.erase(x);
                    x = x2;
                    if (x2 != t3.end())
                        x2++;
                }
                ans = max(ans, Query(a[i]));
            }
        }
    }
    printf (&quot;%lld\n&quot;, min(Sum, Sum - (ans - 2) * 2));
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ3884 上帝与集合的正确用法</title><link>https://www.nekomio.com/posts/141/</link><guid isPermaLink="true">https://www.nekomio.com/posts/141/</guid><pubDate>Sat, 24 Mar 2018 20:33:58 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;根据一些书上的记载，上帝的一次失败的创世经历是这样的：
第一天，上帝创造了一个世界的基本元素，称做“元”。&lt;br /&gt;
第二天，上帝创造了一个新的元素，称作“$\alpha$”。“$\alpha$”被定义为“元”构成的集合。容易发现，一共有两种不同的“$\alpha$”。&lt;br /&gt;
第三天，上帝又创造了一个新的元素，称作“$\beta$”。“$\beta$”被定义为“$\alpha$”构成的集合。容易发现，一共有四种不同的“$\beta$”。&lt;br /&gt;
第四天，上帝创造了新的元素“$\gamma$”，“$\gamma$”被定义为“$\beta$”的集合。显然，一共会有$16$种不同的“$\gamma$”。&lt;br /&gt;
如果按照这样下去，上帝创造的第四种元素将会有$65536$种，第五种元素将会有$2^{65536}$种。这将会是一个天文数字。&lt;br /&gt;
然而，上帝并没有预料到元素种类数的增长是如此的迅速。他想要让世界的元素丰富起来，因此，日复一日，年复一年，他重复地创造着新的元素……&lt;br /&gt;
然而不久，当上帝创造出最后一种元素“$\theta$”时，他发现这世界的元素实在是太多了，以致于世界的容量不足，无法承受。因此在这一天，上帝毁灭了世界。&lt;br /&gt;
至今，上帝仍记得那次失败的创世经历，现在他想问问你，他最后一次创造的元素“$\theta$”一共有多少种？&lt;br /&gt;
上帝觉得这个数字可能过于巨大而无法表示出来，因此你只需要回答这个数对$p$取模后的值即可。
你可以认为上帝从“$\alpha$”到“$\theta$”一共创造了$10^9$次元素，或$10^{18}$次，或者干脆$\infty$次。&lt;br /&gt;
一句话题意：
求
$$2^{2^{2^{2^{\cdots}}}}$$&lt;br /&gt;
对$p$取模后的值&lt;br /&gt;
&amp;lt;!-- &lt;img src=&quot;http://www.lydsy.com/JudgeOnline/upload/201502/1.png&quot; alt=&quot;1.png&quot; /&gt; --&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;接下来$T$行，每行一个正整数$p$，代表你需要取模的值&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;$T$行，每行一个正整数，为答案对$p$取模后的值&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;3
2
3
6
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;0
1
4
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;对于$100%$的数据，$T&amp;lt;=1000$,$p&amp;lt;=10^7$&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;根据扩展欧拉定理
$$x^b \equiv x^{b MOD \phi(p) + \phi(p)} (MOD P)$$
对于所有的$P$都成立&lt;br /&gt;
然后我们就可以做了&lt;br /&gt;
已知任何数模$1$等于$0$&lt;br /&gt;
递归求解&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
	while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
	return x*f;
}
long long pow_mod(long long a, int b, int MOD)
{
	long long ans = 1;
	while (b)
	{
		if (b &amp;amp; 1) ans = ans * a % MOD;
		b &amp;gt;&amp;gt;= 1;
		a = a * a % MOD;
	}
	return ans;
}
int phi(int x)
{
	int ans = x;
	for (int i = 2; i * i &amp;lt;= x; i++)
	{
		if (x % i == 0)
		{
			while (x % i == 0) x /= i;
			ans = ans - ans / i;
		}
	}
	if (x != 1) ans = ans - ans / x;
	return ans;
}
int Calc(int P)
{
	if (P == 1) return 0;
	int x = phi(P);
	return (int)pow_mod(2, Calc(x) + x, P);
}
int main()
{
	int T = read();
	while (T--)
	{
		int p = read();
		printf (&quot;%d\n&quot;, Calc(p));
	}
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ3640 JC的小苹果</title><link>https://www.nekomio.com/posts/140/</link><guid isPermaLink="true">https://www.nekomio.com/posts/140/</guid><pubDate>Sat, 24 Mar 2018 20:05:41 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;让我们继续JC和DZY的故事。&lt;br /&gt;
“你是我的小丫小苹果，怎么爱你都不嫌多！”&lt;br /&gt;
“点亮我生命的火，火火火火火！”&lt;br /&gt;
话说$JC$历经艰辛来到了城市$B$，但是由于他的疏忽$DZY$偷走了他的小苹果！没有小苹果怎么听歌！他发现邪恶的$DZY$把他的小苹果藏在了一个迷宫里。$JC$在经历了之前的战斗后他还剩下$hp$点血。开始$JC$在$1$号点，他的小苹果在$N$号点。$DZY$在一些点里放了怪兽。当$JC$每次遇到位置在$i$的怪兽时他会损失$A_i$点血。当$JC$的血小于等于$0$时他就会被自动弹出迷宫并且再也无法进入。&lt;br /&gt;
但是$JC$迷路了，他每次只能从当前所在点出发等概率的选择一条道路走。所有道路都是双向的，一共有$m$条，怪兽无法被杀死。现在$JC$想知道他找到他的小苹果的概率。&lt;br /&gt;
P.S.大家都知道这个系列是提高组模拟赛，所以这是一道送分题balabala&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行三个整数表示$n$，$m$，$hp$。接下来一行整数，第$i$个表示$JC$到第$i$个点要损失的血量。保证第$1$个和$n$个数为$0$。接下来$m$行每行两个整数$a$，$b$表示$ab$间有一条无向边。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;仅一行，表示JC找到他的小苹果的期望概率，保留八位小数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;3 3 2
0 1 0
1 2
1 3
2 3
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;0.87500000
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;对于$100%$的数据 $2 \leq n \leq 150$，$hp \leq 10000$，$m \leq 5000$，保证图联通。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;设$F[i][j]$ 表示剩余血量为$i$现在在点$j$的概率&lt;br /&gt;
首先相等的血量之间的转移有环， 要用高斯消元&lt;br /&gt;
然而这样的复杂度为$hp*n^3$是不能过的&lt;br /&gt;
然后可以观察到，对于不同的$hp$方程组中只有常数项不同&lt;br /&gt;
那么我们可以先不考虑常数项, 求出每一个解是如何由常数项线性构造出来的&lt;br /&gt;
每次将常数项带入就好了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 155;
struct edge
{
    int END, next;
}v[10005];
int first[MAXN], p;
int du[MAXN], t[MAXN];
void add(int a, int b)
{
    v[p].END = b;
    v[p].next = first[a];
    first[a] = p++;
}
double a[MAXN][MAXN], c[MAXN][MAXN];
double DP[10005][MAXN], tmp[MAXN];
void Gauss_Jordan(int n)
{
    for (int i = 1; i &amp;lt;= n; i++)
    {
        int k = i;
        for (int j = i + 1; j &amp;lt;= n; j++)
            if (fabs(a[j][i]) &amp;gt; fabs(a[k][i]))
                k = j;
        if (k != i)
        {
            for (int j = i; j &amp;lt;= n; j++)
                swap(a[i][j], a[k][j]);
            for (int j = 1; j &amp;lt;= n; j++)
                swap(c[i][j], c[k][j]);
        }
        for (int j = 1; j &amp;lt;= n; j++)
            if (j != i)
            {
                double t = a[j][i] / a[i][i];
                for (k = i; k &amp;lt;= n; k++)
                    a[j][k] -= a[i][k] * t;
                for (k = 1; k &amp;lt;= n; k++)
                    c[j][k] -= c[i][k] * t;
            }
    }
    for (int i = 1; i &amp;lt;= n; i++)
        for (int j = 1; j &amp;lt;= n; j++)
            c[i][j] /= a[i][i];
}

int main()
{
    int n = read(), m = read(), hp = read();
    memset (first, -1, sizeof (first));
    for (int i = 1; i &amp;lt;= n; i++) t[i] = read();
    for (int i = 1; i &amp;lt;= m; i++)
    {
        int b = read(), d = read();
        add(b, d), du[b]++;
        if (b != d) add(d, b), du[d]++;
    }
    for (int i = 1; i &amp;lt;= n; i++)
    {
        a[i][i] = 1, c[i][i] = 1;
        if (t[i] == 0)
        {
            for (int j = first[i]; j != -1; j = v[j].next)
                if (v[j].END != n)
                    a[i][v[j].END] -= 1.0 / du[v[j].END];
        }
    }
    Gauss_Jordan(n);
    double ans = 0;
    for (int i = hp; i &amp;gt;= 1; i--)
    {
        memset (tmp, 0, sizeof (tmp));
        if (i == hp)
            tmp[1] = 1;
        for (int j = 1; j &amp;lt;= n; j++)
            if (t[j] &amp;amp;&amp;amp; i + t[j] &amp;lt;= hp)
                for (int k = first[j]; k != -1; k = v[k].next)
                    if (v[k].END != n)
                        tmp[j] += DP[i + t[j]][v[k].END] / du[v[k].END];
        for (int j = 1; j &amp;lt;= n; j++)
            for (int k = 1; k &amp;lt;= n; k++)
                DP[i][j] += tmp[k] * c[j][k];
        ans += DP[i][n];
    }
    printf (&quot;%.8f\n&quot;, ans);
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ1129 [POI2008]Per</title><link>https://www.nekomio.com/posts/139/</link><guid isPermaLink="true">https://www.nekomio.com/posts/139/</guid><pubDate>Sat, 24 Mar 2018 19:46:46 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;给你一个序列s，你把这个序列的所有不同排列按字典序排列后，求s的排名mod m&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;序列的长度$n &amp;lt; 300000,m$&lt;br /&gt;
$n$个数，代表序列s&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;排名mod m&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;4 1000
2 1 10 2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;5
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;All the permutations smaller (with respect to lexicographic order) than the one given are: (1,2,2,10), (1,2,10,2), (1,10,2,2) and (2,1,2,10). $2 \leq m \leq 10^9$, $1 \leq S_i \leq 300000$&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;逐位考虑&lt;br /&gt;
考虑前$i-1$位与这个数列相等， 第$i$位比他小的数量&lt;br /&gt;
设有$g[i]$个数比他这一位小，那么答案为$g[i]*\frac{F[n - 1]}{\prod_{j = 1}^{n}{F[w[i]]}}$&lt;br /&gt;
其中$F[i]$位$i$的阶乘,$W[i]$为排除了前面已经确定的数后$i$的数量&lt;/p&gt;
&lt;p&gt;这样就可以算出答案了&lt;br /&gt;
然而我们发现模数可能不是质数，那怎么办呢?&lt;br /&gt;
我们可以把他质因数分解，将模数拆成$p^k$相乘的形式&lt;br /&gt;
对于每一个$p^k$求模他的结果然后使用$CRT$合并&lt;br /&gt;
可是阶乘如果是$p^k$的倍数就会得$0$, 我们可以将阶乘拆成$a*p^b$的形式&lt;br /&gt;
可以实现乘法与除法。&lt;br /&gt;
然后解决了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 300005;
long long a[MAXN], b[MAXN], c[MAXN], g[MAXN];
int Sum[MAXN], n, m;
long long B, P, PhiP, K;
long long pow_mod(long long a, int b, long long MP)
{
    long long ans = 1;
    while (b)
    {
        if (b &amp;amp; 1) ans = ans * a % MP;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % MP;
    }
    return ans;
}
long long Inv(long long x)
{
    return pow_mod(x, PhiP - 1, P);
}
struct Num
{
    long long a, b;
    Num(){a = 0, b = 0; }
    Num(int _a)
    {
        a = _a;
        while (a % B == 0)
            a /= B, b++;
    }
    Num(long long _a, long long _b): a(_a), b(_b) {}
    Num operator * (const Num &amp;amp;c) { return Num(a * c.a % P, b + c.b); }
    Num operator / (const Num &amp;amp;c) { return Num(a * Inv(c.a) % P, b - c.b); }
    long long val()
    {
        if (!a || b &amp;gt;= K) return 0;
        long long x = a, k = b, c = B;
        while (k)
        {
            if (k &amp;amp; 1) x = x * c % P;
            k &amp;gt;&amp;gt;= 1;
            c = c * c % P;
        }
        return x;
    }
    void Set(int x)
    {
        a = x, b = 0;
        while (a % B == 0)
            a /= B, b++;
    }
}F[MAXN];
#define lowbit(_) ((_) &amp;amp; (-_))
void A(int x, int c)
{
    for (int i = x; i &amp;lt;= n; i += lowbit(i))
        Sum[i] += c;
}
int Q(int x)
{
    int ans = 0;
    for (int i = x; i &amp;gt;= 1; i -= lowbit(i))
        ans += Sum[i];
    return ans;
}
int cnt;
long long ans[5000], Mp[5000], Phi[5000];
void Solve()
{
    cnt++;
    Mp[cnt] = P, Phi[cnt] = PhiP;
    F[0].Set(1);
    for (int i = 1; i &amp;lt;= n; i++) F[i].Set(i);
    for (int i = 1; i &amp;lt;= n; i++) F[i] = F[i] * F[i - 1];
    for (int i = 1; i &amp;lt;= n; i++) c[i] = 0;
    for (int i = 1; i &amp;lt;= n; i++) c[a[i]]++;
    Num t(1, 0), tmp;
    for (int i = 1; i &amp;lt;= n; i++) t = t * F[c[i]];
    for (int i = 1; i &amp;lt;= n; i++)
    {
        if (g[i]) tmp.Set(g[i]), ans[cnt] = (ans[cnt] + (tmp * F[n - i] / t).val()) % P;
        t = t / F[c[a[i]]] * F[c[a[i]] - 1];
        c[a[i]]--;
    }
}
void Divide(int x)
{
    for (int i = 2; i * i &amp;lt;= x; i++)
        if (x % i == 0)
        {
            B = i, P = 1, PhiP = 1, K = 0;
            while (x % i == 0)
                P *= i, PhiP *= i, K++, x /= i;
            PhiP /= i, PhiP *= i - 1;
            Solve();
        }
    if (x != 1)
    {
        B = x, P = x, PhiP = x - 1, K = 1;
        Solve();
    }
}
long long CRT(long long *a, long long *b, int n)
{
    long long N = 1, Ni, now, ans = 0;
    for (int i = 1; i &amp;lt;= n; i++) N *= a[i];
    for (int i = 1; i &amp;lt;= n; i++)
    {
        Ni = N / a[i];
        now = pow_mod(Ni, Phi[i] - 1, a[i]);
        ans = (ans + (b[i] * now % N) * Ni % N) % N;    
    }
    return ans;
}
int main()
{
    n = read(), m = read();
    for (int i = 1; i &amp;lt;= n; i++)
        b[i] = a[i] = read();
    sort(b + 1, b + n + 1);
    int cnt = unique(b + 1, b + n + 1) - b - 1;
    for (int i = 1; i &amp;lt;= n; i++)
        a[i] = lower_bound(b + 1, b + cnt + 1, a[i]) - b;
    for (int i = 1; i &amp;lt;= n; i++)
        c[a[i]]++;
    for (int i = 1; i &amp;lt;= n; i++) A(i, c[i]);
    for (int i = 1; i &amp;lt;= n; i++)
        g[i] = Q(a[i] - 1), A(a[i], -1);
    Divide(m);
    printf (&quot;%lld\n&quot;, (CRT(Mp, ans, ::cnt) + 1) % m);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>省选集训日记</title><link>https://www.nekomio.com/posts/138/</link><guid isPermaLink="true">https://www.nekomio.com/posts/138/</guid><pubDate>Mon, 19 Mar 2018 21:37:47 GMT</pubDate><content:encoded>&lt;h3&gt;2018-3-19 多云&lt;/h3&gt;
&lt;p&gt;第一天写日记
昨天打了一场UR今天把题改了一下。
又做了一下放假前的那场考试题，还没有做完，还要找时间补。
今天一天下来打的题都不简单，刚放假回来状态也不是很好，主要是比较困。
中午起来想了很多，想到去年的我这时在干什么，不知不觉都过去一年了。
好怀念那时轻松的日子。
但现在还是要面对啊，先过了省选再说，无论结果如何，也都会确定了。&lt;/p&gt;
&lt;h3&gt;2018-3-20 ~ 21&lt;/h3&gt;
&lt;p&gt;生活就是改题吧。。&lt;br /&gt;
一连考了两天, 题还都没有改完
都是神题。&lt;br /&gt;
D1T1贪心, D1T2 是一道2-SAT + Trie, D1T3 是一个DP&lt;br /&gt;
D2T1计算几何的DP, D2T2 是一个平横树维护的模拟, D2T3是一个多项式算法。&lt;br /&gt;
博客还是要尽力更新的吧。&lt;/p&gt;
&lt;h3&gt;2018-3-22&lt;/h3&gt;
&lt;p&gt;终于把题给改完了&lt;br /&gt;
D2T3，D1T3真是不好改。&lt;br /&gt;
晚上打了一道题，还没打完，一道CRT合并的组合数的题目&lt;br /&gt;
&lt;strong&gt;组合数模非质数&lt;/strong&gt;: 将模数分解质因子,对于每一个$P ^ k$都算出$%$他意义下的答案， 然后用CRT合并， 对阶乘搞一下拆成$a*p^b$ 以为$a$与$p^k$互质所以可以求逆元了。&lt;br /&gt;
然后听ryf分享一道题&lt;a href=&quot;http://uoj.ac/problem/76&quot;&gt;UOJ76&lt;/a&gt;懒癌， 看到题面感觉很熟悉啊。 解法也是非常的强大， 将搜索转化为图论。&lt;/p&gt;
&lt;h3&gt;2018-3-23&lt;/h3&gt;
&lt;p&gt;又是考试的一天&lt;br /&gt;
第三题有点熟悉， 这道题的处理方法和昨天那道题好像一样啊。&lt;br /&gt;
然后就打了， 结果还是没A, 有一个地方没开&lt;code&gt;long long&lt;/code&gt;在计算过程中炸掉了。&lt;br /&gt;
前两题都是神题， 第二题是一道看不出来是杜教筛的杜教筛， 用的容斥系数$\mu$ 然后推一下式子。&lt;br /&gt;
第一题又是一道记忆化搜索DP&lt;/p&gt;
&lt;h3&gt;2018-3-24&lt;/h3&gt;
&lt;p&gt;今天没考试，那就去刷题吧。&lt;br /&gt;
简单的做了一下数学专题&lt;br /&gt;
学了一下高斯约当消元法。 又打了一道$LCT$的题目&lt;br /&gt;
补了一点博客。&lt;br /&gt;
计划再看看概率期望相关的题目&lt;/p&gt;
&lt;h3&gt;2018-3-25&lt;/h3&gt;
&lt;p&gt;考试考试考试&lt;br /&gt;
第一道题是一道比较简单的网络流, 可以先二分然后跑类似于文理分科的最小割&lt;br /&gt;
第二题是一道三维的几何题, 考试的时候没敢写， 主要是没想到用单位向量的倍数来列方程， 然后就用一些高考数学的知识就能解决了&lt;br /&gt;
第三题是一道$DP$对小质数状压，大质数枚举，可以跑过纯状压跑不过的测试点&lt;br /&gt;
然后就没了&lt;/p&gt;
&lt;h3&gt;2018-3-26&lt;/h3&gt;
&lt;p&gt;考试考试考试&lt;br /&gt;
第一题看起来是一道莫比乌斯反演? 推了推没推出式子,先打个部分分再说吧。&lt;br /&gt;
然后看第二题，暴搜有分? 等等, 我好想会$n^3$的做法, 码码码, 打完调过样例, 好让我打个对拍, $n = 3$一拍就出错，额，调调调，调过了我的小数据，再一测样例，(⊙o⊙)… 又不对了，啊啊啊。 我这个好像不对??? 不要啊，然后还是弃疗了2333&lt;br /&gt;
弃疗后看第三题，好像不难啊，等等，这不是半平面交裸题么，十几分钟就打完了，结果死活不出样例，什么鬼啊? 我半平面交没错啊。 考试结束也没改出来， 最后发现代码里这样一句&lt;code&gt;const int eps = 1e-8&lt;/code&gt;成功把我炸死。 改了就过了。&lt;br /&gt;
第一题的正解是一个优化了的暴力, 根据调和级数得复杂度为$n^2log(n)$还卡常。&lt;br /&gt;
第二题是一个看起来很简单的$DP$，不知道是因为想的太难还是真的很难没做出来。&lt;br /&gt;
明天还考试。。&lt;/p&gt;
&lt;h3&gt;2018-3-27&lt;/h3&gt;
&lt;p&gt;一天两试真爽啊&lt;br /&gt;
上午考了一场，第一题先把暴力打了，然后看第二题，咦，这不是原题么? 好像连样例都一样的啊。 码码码， 打完之后简单拍了一下感觉没问题了去做第三题，第一眼二分图，感觉不对，在一眼好想可以用网络流，先建了个最大费用最大流，发现不对，然后想是不是可以最小割啊。画了画图，然后发现这图好想有点熟悉啊，等等， 我是不是做过一道和这个一样的题啊， 然后就开打了， 没对拍， 眼动查了几发错， 好想没什么问题。&lt;br /&gt;
最后得分和我的估分一致，没有什么问题。&lt;br /&gt;
考完之后， 于老师说， 下午再考一场， 我心里一惊，我的天还考啊。啊啊啊。&lt;br /&gt;
下午起来之后有点困，一点四十七到了机房，坐着犯困，本来说好的两点考试， 然后老师看我们没什么事干， 就直接开考了&lt;br /&gt;
上来先浏览一下题面，发现暴力分给很多，这种类型题做起来也挺舒服。 看完题面， 周围一片键盘声， 心里有点慌， 他们不会都要$A$题了吧&lt;br /&gt;
不，我要冷静一下，我想的和他们应该也差不多，那，先让我上个厕所冷静一下。&lt;br /&gt;
回来之后发现，三道题好想都可以拿到不少的分数啊， 然后剩下的时间就用在码题上了。&lt;br /&gt;
第一题是一道分类讨论， 看起来不是很好搞。&lt;br /&gt;
第二题前$30$分可以直接枚举， 还有二十分可以$DP$出来。&lt;br /&gt;
第三题我好想会一个$nlog^2(n)$的做法啊， 考完试后才发现是$nlog^3(n)$的。 然而拿到了不少分啊&lt;br /&gt;
第二题的正解是将我的那个$DP$扩展到树上，打出来后发现其实非常简单， 我觉得在$NOIP$前都有可能会做，我是被省选模拟赛吓到了吗？ 怎么不敢打正解了啊？&lt;br /&gt;
第三题可以在我的程序上稍加修改去掉一个比较大的$log$就可以轻松过掉了，其实我的程序开了&lt;code&gt;O2&lt;/code&gt;也是可以过的啊， 说好的开&lt;code&gt;O2&lt;/code&gt;呢。&lt;br /&gt;
明天还考试， 题还没改完呢啊。。&lt;/p&gt;
&lt;h3&gt;2018-3-28&lt;/h3&gt;
&lt;p&gt;早上起来好困，到机房后继续看昨天的题的题解。&lt;br /&gt;
到了考试的时间就考吧。&lt;br /&gt;
上来一看，这好想和昨天的是一套题， 可是画风好想不大一样啊&lt;br /&gt;
看了看第一题，发现和昨天下午T2的一个部分分有点相似，可是数据范围大了不少，然后就开始推DP方程$O(n^3)$不用过脑子， $O(n^2log(n))$是NOIP水平的DP， 这样是$60$分， 然后想$100$分的做法， 想了一会发现好想没什么思路，然后看了一下第二题，发现没什么思路，暴力也不是很好打， 然后看第三题， 看起来好想很好拿分? 开始先把暴力打上，然后发现，好想可以用动态点分治， 是不是可以满分?(死+1)， 然后开始打， 打着打着发现好像不能处理修改操作? 没事， 没有修改也有$50$分(死+2)， 比暴力多了不少， 继续打， 调调调， 最后还是没调出来，再给我$10$分钟就行啊， 说好的四个半小时呢?为啥又是四个小时。
$T2$最后还是没打上。&lt;br /&gt;
最后$T2$好像是这三道题中最好做的?应该多给点时间给$T2$的。&lt;br /&gt;
这次考试最大是失误是错误的估计了我$T3$打法的难度，没有正确的处理好每道题的时间分配，否则第二题还是能拿不少分呢。&lt;br /&gt;
下次一定注意。&lt;/p&gt;
&lt;h3&gt;2018-3-29&lt;/h3&gt;
&lt;p&gt;又是考试的一天&lt;br /&gt;
开始考试后看第一题，想出了$70$分的$DP$然后想了想，也没想出怎么优化。&lt;br /&gt;
看第二题，只会暴力，第三题只会暴力。 然后就完了。&lt;br /&gt;
其实第一题的正解很简单，但是我没有想出来，主要的一个原因是$DP$数组转移的方式问题，以我的转移方式只能看出他是一个区间加， 但如果换一个方向， 就能看出前缀和了， 然后就是正解了。&lt;br /&gt;
第二题是一个很简单的线段树，但是我没想出来，主要是因为没有深入的挖掘$n \leq 100$这个条件。&lt;br /&gt;
第三题是真的很好，先将二维转化为一维，然后可以字符串匹配，$FFT$优化搞掉这道题， 这个真的是不容易想出来。&lt;/p&gt;
&lt;h3&gt;2018-3-30&lt;/h3&gt;
&lt;p&gt;没改完题。。。&lt;br /&gt;
T1上来一看是道水题， 结果老师说题面是错的， 然后就不会了， 其实正解也就是一个简单的$Hash$&lt;br /&gt;
T2没有什么思路， 就打了一点骗分， 其实可以用模拟退火水过去， 正解是拉格朗日乘数法。&lt;br /&gt;
T3题面中给出了精度问题， 然后就想到了取$log10$这个操作， 之后需要用线段树维护排序和区间和。&lt;/p&gt;
&lt;h3&gt;2018-3-31 ~ 4-1&lt;/h3&gt;
&lt;p&gt;3-31号上午考了一场试
上来先看$T1$发现一眼看出了非常水的$50$分，然后发现不会了，尝试去想$100$分发现复杂度一直不对，后来加了一个单调偏分，又多拿了$10$分。&lt;br /&gt;
然后看$T2$发现暴力不是很好打， 想了想， 发现他的状态的检验非常快， 然后想到了昨天学习的模拟退火， 然后一发退火上去， 过了样例， 然后造极限数据， 发现跑一次一个数， 每次都不是最优， 想了想算了， 应该能拿到点分， 但应该不多， 然后发现有$50$分，很开心， 真·信仰退火， $T3$真的是一点都不会。。。&lt;br /&gt;
其实$T1$可以通过两个单调用线段树维护， $T2$是网络流，$T3$是一道$Hash$+$BurnSide$的题。&lt;br /&gt;
4-1做题，先把前天的$T3$改掉， 用了快一个上午，真是打不动数据结构了啊。&lt;br /&gt;
然后做了做NOI泳池因为不会特征多项式，用快速幂跑了$90$分就这样了。 然后做&lt;a href=&quot;http://uoj.ac/problem/141&quot;&gt;【UER #4】量子态的棋盘&lt;/a&gt; 一道不是很显然的轮廓线$DP$，但打起来不是很难。&lt;br /&gt;
还要把Normal打完啊&lt;/p&gt;
&lt;h3&gt;2018-4-2&lt;/h3&gt;
&lt;p&gt;考了两场，两场的$T2$和$T3$都不难， 但是$T1$都不是很简单。&lt;br /&gt;
$T1$ 全场最佳。&lt;br /&gt;
题还没有改完。&lt;/p&gt;
&lt;h3&gt;2018-4-3&lt;/h3&gt;
&lt;p&gt;上午考了一场试，算下来还有一两天就省选了啊。&lt;br /&gt;
一看$T1$看起来部分分很好拿， 事实也确实如此， 先打$60$分的部分分， 然后想先看看其他题， 然后留一点时间给第一题。&lt;br /&gt;
然后看$T2$发现不是很会做， 先打了$20$分的暴力， 感觉还有$10$分好像可以拿， 然后我先看第三题去了。&lt;br /&gt;
$T3$不是很会打暴力， 打了一个多小时的暴力， 最后因为重边， 出了问题。&lt;br /&gt;
因为$T3$费了太多时间， $T2$和$T1$也没有再去打， 本来以为还有一个半小时的， 其实只要半个小时了。&lt;br /&gt;
然后就没打我本来应该得到的那部分分。&lt;/p&gt;
&lt;h3&gt;ENDL&lt;/h3&gt;
</content:encoded></item><item><title>UR17 题解</title><link>https://www.nekomio.com/posts/137/</link><guid isPermaLink="true">https://www.nekomio.com/posts/137/</guid><pubDate>Mon, 19 Mar 2018 20:42:51 GMT</pubDate><content:encoded>&lt;h2&gt;A. 【UR #17】滑稽树上滑稽果&lt;/h2&gt;
&lt;p&gt;“滑稽树上滑稽果，滑稽树下你和我” 听到这熟悉的句子，他猛然忆起年少时最喜欢的节目，彼时单纯而简单的生活，以及那幼稚而天真的苦恼。
幼年的他常常苦恼这么一个问题：
他有 $n$ 个滑稽果，第 $i$ 个滑稽果的大小为 $a_i$。
他现在想把它们构成一棵任意形态的有根树，每个点的&lt;strong&gt;滑稽度&lt;/strong&gt;为它的&lt;strong&gt;大小&lt;/strong&gt;和它父亲的&lt;strong&gt;滑稽度&lt;/strong&gt;的 $and$，其中 $and$ 表示按位与运算，例如 $2\ and\ 3=2,1\ and\ 0=0,\ 1\ and\ 1=1$。特别地，根的滑稽度等于他的大小。
为了世界的和平，他希望能最小化这棵树上所有滑稽果的滑稽度之和。请问你能帮他解决这个问题吗？&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2018/03/19/5aafb0feb6c81.jpg&quot; alt=&quot;006fbYi5gw1f9djtje2mdj30hs0dcwfe.jpg&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;输入格式&lt;/h3&gt;
&lt;p&gt;第一行一个正整数 $n$。
接下来一行有 $n$ 个正整数 $a_i$, 表示 $i$ 个滑稽果的大小。&lt;/p&gt;
&lt;h3&gt;输出格式&lt;/h3&gt;
&lt;p&gt;一行一个整数，表示最小的滑稽度之和。&lt;/p&gt;
&lt;h3&gt;样例一&lt;/h3&gt;
&lt;h4&gt;input&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;5
12 9 14 17 15
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;output&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;10
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;样例二&lt;/h3&gt;
&lt;h4&gt;input&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;10
42256 116359 103553 58560 49680 99204 37408 57353 110732 33797
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;output&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;328709
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;table&amp;gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th width=&quot;10%&quot;&amp;gt;子任务&amp;lt;/th&amp;gt;
&amp;lt;th width=&quot;10%&quot;&amp;gt;分值&amp;lt;/th&amp;gt;
&amp;lt;th width=&quot;13%&quot;&amp;gt;$n$的规模&amp;lt;/th&amp;gt;
&amp;lt;th width=&quot;13%&quot;&amp;gt;$a_i$的规模&amp;lt;/th&amp;gt;
&amp;lt;th&amp;gt;特殊性质&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 9$&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;6&quot;&amp;gt;$1 \leq a_i \leq 2 \times 10^5$&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;无&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;10&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 12$&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;保证存在合法的最优解是一条链&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;3&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;10&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 100$&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;2&quot;&amp;gt;保证存在合法的最优解是一条链。并且从根开始的每个滑稽值构成了一个序列，保证解的这个序列的字典序，在所有链对应的序列中最小&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;4&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;15&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 10^5$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;30&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 100$&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;2&quot;&amp;gt;无&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;6&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;30&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 10^5$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/tbody&amp;gt;&amp;lt;/table&amp;gt;&lt;/p&gt;
&lt;h2&gt;A. 题解&lt;/h2&gt;
&lt;p&gt;这题面有毒吧。。。&lt;/p&gt;
&lt;p&gt;对于第一个Subtask可以直接枚举父节点时间复杂度$O(n^n)$&lt;br /&gt;
然后是第二个Subtask据说可以用$n!$的时间复杂度枚举，但不知道为什么过不去。。。&lt;br /&gt;
第三四的Subtask保证了字典序最小，我们可以暴力跑一下$O(n^2)$过掉$n&amp;lt;=100$的数据，
而对于$n&amp;lt;=10^5$的数据我们可以Sort一下$O(nlog^2(n))$跑过去
核心代码在下面&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for (int i = 1; i &amp;lt;= n; i++) a[i] = read();
Now = 0x7fffffffffffffffll;
long long ans = 0;
sort(a + 1, a + n + 1, cmp);
for (int i = 1; i &amp;lt;= n; i++)
{
    ans += (Now &amp;amp; a[i]);
    if ((Now &amp;amp; a[i]) != Now)
    {
        Now = (Now &amp;amp; a[i]);
        sort(a + i + 1, a + n + 1, cmp);
    }
}
printf (&quot;%lld\n&quot;, ans);
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;bool cmp(long long c, long long d)
{
    if ((Now &amp;amp; c) == (Now &amp;amp; d)) return c &amp;gt; d;
    return (Now &amp;amp; c) &amp;lt; (Now &amp;amp; d);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;剩下的就是正解了&lt;br /&gt;
把相同的位拿出来，这些位要么一定是每次没贡献，要么一定是每次有贡献。&lt;br /&gt;
所以我们一样先把每个数都一样的那些位拿出来，剩下的位我们等于是希望尽快把他们变成0。&lt;br /&gt;
用一个DP&lt;br /&gt;
$f[S]$表示当$S$集合的值为$1$时将他消为$0$的最小代价&lt;br /&gt;
转移的时候枚举$a[i]$，令$F[S] = F[S \&amp;amp; a[i]] + (S \&amp;amp; a[i])$&lt;br /&gt;
这样是$O(na)$的配合上前面的部分分，可以有70分了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 1e5 + 5;
long long a[MAXN], C[MAXN];
int n;
bool rm[10];
int Count[10];
inline void Trans(int x, long long *c)
{
    int cnt = 0;
    for (int i = 1; i &amp;lt;= n - 2; i++) c[i] = 0;
    while (x) c[++cnt] = x % n, x = x / n;
    for (int i = 1; i &amp;lt;= n - 2; i++) c[i]++;
}
struct edge
{
    int END, next;
}v[20];
int first[10], p;
bool flag[100005];
void add(int a, int b)
{
    v[p].END = b;
    v[p].next = first[a];
    first[a] = p++;
}
int Sum;
void DFS(int rt, int fa)
{
    if (fa != 0) C[rt] = (C[fa] &amp;amp; a[rt]);
    Sum += C[rt];
    for (int i = first[rt]; i != -1; i = v[i].next)
    {
        if (v[i].END == fa) continue;
        DFS(v[i].END, rt);
    }
}
long long Now;
bool cmp(long long c, long long d)
{
    if ((Now &amp;amp; c) == (Now &amp;amp; d)) return c &amp;gt; d;
    return (Now &amp;amp; c) &amp;lt; (Now &amp;amp; d);
}
long long f[(1 &amp;lt;&amp;lt; 18) + 1], S[(1 &amp;lt;&amp;lt; 18) + 1];
int main()
{
    n = read();
    if (n &amp;lt;= 100)
    {
        long long SAME = 0x7fffffffffffffffll;
        for (int i = 1; i &amp;lt;= n; i++) a[i] = read(), SAME = (SAME &amp;amp; a[i]);
        int N = (1 &amp;lt;&amp;lt; 18) - 1;
        int cnt = 0;
        for (int i = 1; i &amp;lt;= N; i++)
            S[++cnt] = (i | SAME) ^ SAME;
        memset (f, 0x3f, sizeof (f));
        f[0] = 0;
        sort(S + 1, S + cnt + 1);
        for (int i = 1; i &amp;lt;= cnt; i++)
            for (int j = 1; j &amp;lt;= n; j++)
                f[S[i]] = min(f[S[i]], f[S[i] &amp;amp; a[j]] + (S[i] &amp;amp; a[j]));
        printf (&quot;%lld\n&quot;, 1ll * SAME * n + f[S[cnt]]);
    }
    else
    {
        for (int i = 1; i &amp;lt;= n; i++) a[i] = read();
        Now = 0x7fffffffffffffffll;
        long long ans = 0;
        sort(a + 1, a + n + 1, cmp);
        for (int i = 1; i &amp;lt;= n; i++)
        {
            ans += (Now &amp;amp; a[i]);
            if ((Now &amp;amp; a[i]) != Now)
            {
                Now = (Now &amp;amp; a[i]);
                sort(a + i + 1, a + n + 1, cmp);
            }
        }
        printf (&quot;%lld\n&quot;, ans);
    }
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于满分做法
我们可以每次不枚举一个$a[i]$，而是枚举一个子集$T$，强制把这个子集$T$变成$0$。&lt;br /&gt;
我们需要知道哪些$T$可以变为$0$&lt;br /&gt;
可以用枚举子集的方法，(但是因为太暴力被Hack了 2333)
转移是相似的。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 1e5 + 5;
long long a[MAXN], C[MAXN];
int n;
long long Now;
bool cmp(long long c, long long d)
{
    if ((Now &amp;amp; c) == (Now &amp;amp; d)) return c &amp;gt; d;
    return (Now &amp;amp; c) &amp;lt; (Now &amp;amp; d);
}
long long f[(1 &amp;lt;&amp;lt; 18) + 1], S[(1 &amp;lt;&amp;lt; 18) + 1];
int cnt[(1 &amp;lt;&amp;lt; 18) + 1];
int main()
{
    n = read();
    if (n &amp;lt;= 100000)
    {
        long long SAME = (1 &amp;lt;&amp;lt; 18) - 1;
        for (int i = 1; i &amp;lt;= n; i++) a[i] = read(), SAME = (SAME &amp;amp; a[i]);
        int N = (1 &amp;lt;&amp;lt; 18) - 1;
        for (int i = 1; i &amp;lt;= n; i++) a[i] ^= SAME;
        for (int i = 1; i &amp;lt;= n; i++)
        {
            long long t = N ^ a[i];
            for (int j = t; j; j = (j - 1) &amp;amp; t)
                cnt[j] = 1;
        }
        memset (f, 0x3f, sizeof (f));
        for (int i = 1; i &amp;lt;= n; i++) f[a[i]] = a[i];
        for (int i = N; i &amp;gt;= 1; i--) 
            if (f[i] &amp;lt; 0x3f3f3f3f3f3f3f3f)
                for (int j = i; j &amp;gt; 0; j = (j - 1) &amp;amp; i)
                    if (cnt[j])
                        f[i ^ j] = min(f[i ^ j], f[i] + (i ^ j));
        printf (&quot;%lld\n&quot;, 1ll * SAME * n + f[0]);
    }
    else
    {
        for (int i = 1; i &amp;lt;= n; i++) a[i] = read();
        Now = 0x7fffffffffffffffll;
        long long ans = 0;
        sort(a + 1, a + n + 1, cmp);
        for (int i = 1; i &amp;lt;= n; i++)
        {
            ans += (Now &amp;amp; a[i]);
            if ((Now &amp;amp; a[i]) != Now)
            {
                Now = (Now &amp;amp; a[i]);
                sort(a + i + 1, a + n + 1, cmp);
            }
        }
        printf (&quot;%lld\n&quot;, ans);
    }
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;B. 【UR #17】滑稽树下你和我&lt;/h2&gt;
&lt;p&gt;我，年幼的人赢，总是和我的同桌一起在滑稽树下讨论问题。&lt;br /&gt;
我的滑稽树是一棵长在平面上的，有 $n$ 个点的树。点从 $1$ 到 $n$ 标号。这 $n$ 个点满足任意三点互不共线，并且树的边不相交。&lt;br /&gt;
现在我都和我的同桌一起在滑稽树上每人各控制一个点。我的点最开始在 $\mathrm{stx}$，我的同桌的点最开始在 $\mathrm{sty}$。我们可以任意沿着树的边移动各自的点。当两个点都在树上的某个叶子的时候游戏就结束了。&lt;br /&gt;
现在，我想要最小化任意时刻我们两个所控制的点之间距离的最大值。请问你能帮我解决这个问题吗？注意某个时刻两个点可能都在某一条边上，这时候的距离也要统计入答案。&lt;br /&gt;
一句话题意：给定一棵平面上的树，两个点在树上任意移动，最小化从开始到两个点都到达叶子的任意时刻两个点直线距离的最大值。&lt;br /&gt;
&amp;lt;h3&amp;gt;输入格式&amp;lt;/h3&amp;gt;
第一行三个正整数 $n,\mathrm{stx},\mathrm{sty}$。&lt;br /&gt;
接下来 $n$ 行有 $2$ 个整数 $x_i,y_i$，表示第 $i$ 号节点的坐标。&lt;br /&gt;
接下来 $n-1$ 行有 $2$ 个整数 $a_i,b_i$，表示树上的一条边。&lt;br /&gt;
&amp;lt;h3&amp;gt;输出格式&amp;lt;/h3&amp;gt;
输出一行，包含一个实数，表示最小的任意时刻我们两个所控制的点之间距离的最大值。&lt;br /&gt;
你的答案与参考答案的绝对误差或相对误差不超过 $10^{−6}$ 时被认为是正确的。&lt;br /&gt;
&amp;lt;h3&amp;gt;样例一&amp;lt;/h3&amp;gt;
&amp;lt;h4&amp;gt;input&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;4 2 3
0 1
1 1
1 0
0 0
1 2
2 3
3 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;output&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1.0000000000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/pre&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h3&amp;gt;样例二&amp;lt;/h3&amp;gt;
&amp;lt;h4&amp;gt;input&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;4 2 4
0 0
51 49
100 100
100 0
1 2
2 3
3 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;output&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;69.2964645563
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h3&amp;gt;限制与约定&amp;lt;/h3&amp;gt;
对于全部数据，$3\le n\le 1000$，$0\le x_i,y_i \le 10^6$。
&amp;lt;table&amp;gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;子任务&amp;lt;/th&amp;gt;
&amp;lt;th&amp;gt;分值&amp;lt;/th&amp;gt;
&amp;lt;th&amp;gt;$n$&amp;lt;/th&amp;gt;
&amp;lt;th&amp;gt;特殊性质&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;1&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;5&amp;lt;/td&amp;gt;
&amp;lt;td rowspan=&quot;2&quot;&amp;gt;$\le 10$&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;$\mathrm{stx}$ 和 $\mathrm{sty}$ 均为叶子&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;2&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;25&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;无&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;3&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;25&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;$\le 200$&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;无&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;4&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;15&amp;lt;/td&amp;gt;
&amp;lt;td rowspan=&quot;2&quot;&amp;gt;$\le 1000$&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;保证存在最优方案，在任意时刻至少有一端点位于树的某结点上&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;5&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;30&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;无&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;&amp;lt;/tbody&amp;gt;&amp;lt;/table&amp;gt;&lt;/p&gt;
&lt;h2&gt;B. 题解&lt;/h2&gt;
&lt;p&gt;第一个Subtask可以直接输出两点距离&lt;br /&gt;
对于保证存在最优方案，在任意时刻至少有一端点位于树的某结点上的部分&lt;br /&gt;
先二分答案&lt;br /&gt;
定义$f[i][j]$表示两个点为$i, j$是否可行, 按照定义枚举转移&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
bool Judge(double mid)
{
    memset (f, 0, sizeof (f));
    f[stx][sty] = f[sty][stx] = 1;
    queue&amp;lt;pair&amp;lt;int, int&amp;gt; &amp;gt; Q;
    Q.push(pair&amp;lt;int, int&amp;gt;(stx, sty));
    while (!Q.empty())
    {
        pair&amp;lt;int, int&amp;gt; k = Q.front(); Q.pop();
        int x = k.first, y = k.second;
        if (x == y || (du[x] == 1 &amp;amp;&amp;amp; du[y] == 1)) return 1;
        for (int i = first[x]; i != -1; i = v[i].next)
        {
            if (!f[v[i].END][y] &amp;amp;&amp;amp; dis(a[v[i].END], a[y]) &amp;lt;= mid)
            {
                f[v[i].END][y] = f[y][v[i].END] = 1;
                Q.push(pair&amp;lt;int, int&amp;gt;(v[i].END, y));
            }
        }
        for (int i = first[y]; i != -1; i = v[i].next)
        {
            if (!f[x][v[i].END] &amp;amp;&amp;amp; dis(a[v[i].END], a[x]) &amp;lt;= mid)
            {
                f[v[i].END][x] = f[x][v[i].END] = 1;
                Q.push(pair&amp;lt;int, int&amp;gt;(x, v[i].END));
            }
        }
    }
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后就是正解了&lt;br /&gt;
与20分的相似， 还是先二分答案&lt;br /&gt;
定义$f[i][j]$为一个点在点$i$,一个点在边$j$上距离点$i$最近的那个点上是否可行&lt;br /&gt;
然后$f[i][j]&amp;lt;=1$要求$i$到$j$的最小距离小于二分的答案, 且存在某个$f[k][x]$为$1$,其中$k$是$j$的某个端点,$x$是某个以$i$为端点的边，或存在某个$f[t][j]$为$1$，其中$t$与$i$有边相连， $BFS$转移。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cmath&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
struct Point
{
    double x, y;
    Point(double _x = 0, double _y = 0): x(_x), y(_y) {}
    Point operator - (const Point &amp;amp;a)
    {
        return Point(x - a.x, y - a.y);
    }
    double operator * (const Point &amp;amp;a)
    {
        return x * a.x + y * a.y;
    }
    double operator ^ (const Point &amp;amp;a)
    {
        return x * a.y - y * a.x;
    }
}a[1005];
int du[1005];
struct edge
{
    int S, END, next, id;
}v[2005];
int first[1005], p;
void add(int c, int b, int id)
{
    v[p].S = c;
    v[p].END = b;
    v[p].next = first[c];
    v[p].id = id;
    first[c] = p++;
}
double dis(const Point &amp;amp;x, const Point &amp;amp;y)
{
    return sqrt((x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y));
}
struct line
{
    Point a, b, c;
    double k;
    line() {}
    line(Point x, Point y) 
    {
        a = x, b = y;
        c = a - b;
        k = atan2(b.y - a.y, b.x - a.x);
    }
}l[1005];
double dis(Point &amp;amp;x, line &amp;amp;y)
{
    if ((y.c * (y.a - x)) * (y.c * (y.b - x)) &amp;lt;= 0)
        return abs((y.a - x) ^ (y.b - x)) / dis(y.a, y.b);
    return min(dis(y.a, x), dis(y.b, x));
}
bool f[1005][1005];
int n, stx, sty;
bool Judge(double mid)
{
    memset (f, 0, sizeof (f));
    queue&amp;lt;pair&amp;lt;int, int&amp;gt; &amp;gt; Q;
    for (int i = first[stx]; i != -1; i = v[i].next)
        f[sty][v[i].id] = 1, Q.push(pair&amp;lt;int, int&amp;gt;(sty, v[i].id));
    for (int i = first[sty]; i != -1; i = v[i].next)
        f[stx][v[i].id] = 1, Q.push(pair&amp;lt;int, int&amp;gt;(stx, v[i].id));
    while (!Q.empty())
    {
        pair&amp;lt;int, int&amp;gt; k = Q.front(); Q.pop();
        int x = k.first, y = k.second;
        for (int i = first[x]; i != -1; i = v[i].next)
        {
            if (!f[v[i].END][y] &amp;amp;&amp;amp; dis(a[v[i].END], l[y]) &amp;lt;= mid)
            {
                f[v[i].END][y] = 1;
                Q.push(pair&amp;lt;int, int&amp;gt;(v[i].END, y));
            }
            if (!f[v[(y - 1) &amp;lt;&amp;lt; 1].S][v[i].id] &amp;amp;&amp;amp; dis(a[v[(y - 1) &amp;lt;&amp;lt; 1].S], l[v[i].id]) &amp;lt;= mid)
            {
                f[v[(y - 1) &amp;lt;&amp;lt; 1].S][v[i].id] = 1;
                Q.push(pair&amp;lt;int, int&amp;gt;(v[(y - 1) &amp;lt;&amp;lt; 1].S, v[i].id));
            }
            if (!f[v[(y - 1) &amp;lt;&amp;lt; 1].END][v[i].id] &amp;amp;&amp;amp; dis(a[v[(y - 1) &amp;lt;&amp;lt; 1].END], l[v[i].id]) &amp;lt;= mid)
            {
                f[v[(y - 1) &amp;lt;&amp;lt; 1].END][v[i].id] = 1;
                Q.push(pair&amp;lt;int, int&amp;gt;(v[(y - 1) &amp;lt;&amp;lt; 1].END, v[i].id));
            }
        }
    }
    for (int i = 1; i &amp;lt;= n; i++) if (du[i] == 1)
        for (int j = 1; j &amp;lt;= n; j++) if (du[j] == 1)
            if (f[i][v[first[j]].id] &amp;amp;&amp;amp; dis(a[i], a[j]) &amp;lt;= mid)
                return 1;
    return 0;
}
int main()
{
    memset (first, -1, sizeof (first));
    n = read(), stx = read(), sty = read();
    for (int i = 1; i &amp;lt;= n; i++)
        a[i].x = read(), a[i].y = read();
    for (int i = 1; i &amp;lt; n; i++)
    {
        int b = read(), c = read();
        du[b]++, du[c]++;
        add(b, c, i);
        add(c, b, i);
        l[i] = line(a[b], a[c]);
    }
    double l = dis(a[stx], a[sty]), r = 1e9;
    while (abs(r - l) &amp;gt;= 1e-8)
    {
        double mid = (l + r) / 2;
        if (Judge(mid)) r = mid;
        else l = mid;
    }
    printf (&quot;%.10f&quot;, l);
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;C题先坑着，还不会做呢， 过一段时间在填。&lt;/p&gt;
</content:encoded></item><item><title>BZOJ1038 [ZJOI2008]瞭望塔</title><link>https://www.nekomio.com/posts/136/</link><guid isPermaLink="true">https://www.nekomio.com/posts/136/</guid><pubDate>Fri, 09 Mar 2018 19:18:32 GMT</pubDate><content:encoded>&lt;h4&gt;题目描述&lt;/h4&gt;
&lt;p&gt;致力于建设全国示范和谐小村庄的$H$村村长$dadzhi$，决定在村中建立一个瞭望塔，以此加强村中的治安。&lt;br /&gt;
我们将$H$村抽象为一维的轮廓。如下图所示&lt;/p&gt;
&lt;p&gt;我们可以用一条山的上方轮廓折线$(x_1, y_1)$, $(x_2, y_2)$, $...$ $(x_n, y_n)$来描述H村的形状，这里$x_1 &amp;lt; x_2 &amp;lt; ... &amp;lt; x_n$。瞭望塔可以建造在$[x_1, x_n]$间的任意位置, 但必须满足从瞭望塔的顶端可以看到$H$村的任意位置。可见在不同的位置建造瞭望塔，所需要建造的高度是不同的。为了节省开支，$dadzhi$村长希望建造的塔高度尽可能小。&lt;/p&gt;
&lt;p&gt;请你写一个程序，帮助$dadzhi$村长计算塔的最小高度。&lt;/p&gt;
&lt;h4&gt;输入格式：&lt;/h4&gt;
&lt;p&gt;输入文件$tower.in$第一行包含一个整数n，表示轮廓折线的节点数目。接下来第一行n个整数, 为$x_1 ~ x_n$. 第三行n个整数，为$y_1 ~ y_n$。&lt;/p&gt;
&lt;h4&gt;输出格式：&lt;/h4&gt;
&lt;p&gt;输出文件$tower.out$仅包含一个实数，为塔的最小高度，精确到小数点后三位。&lt;/p&gt;
&lt;h4&gt;Sample Input&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;6
1 2 4 5 6 7
1 2 2 4 2 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Sample Output&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;1.000
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;将所有的直线延长在上面做一个半平面交&lt;br /&gt;
答案一定取在直线的交点或下面山是顶点上&lt;/p&gt;
&lt;p&gt;枚举半平面的每个交点向下做垂线，计算出他与山之间的距离&lt;br /&gt;
然后枚举山的每个顶点做垂线，计算出他与半平面之间的距离&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 305;
const double eps = 1e-20;
struct Point
{
    double x, y;
    Point(double _x = 0, double _y = 0) : x(_x), y(_y) {}
    Point operator - (const Point &amp;amp;a)
    {
        return Point(x - a.x, y - a.y);
    }
    double operator * (const Point &amp;amp;a) 
    {
        return x * a.y - y * a.x;
    }
}a[MAXN], c[MAXN];
struct line
{
    Point a, b;
    line(){}
    line(Point _a, Point _b)
    {
        a = _a;
        b = _b;
    }
    double k;
}l[MAXN];
bool cmp(line a, line b)
{
    if (a.k == b.k) return (b.a - a.a) * (b.b - a.a) &amp;gt;= eps;
    return a.k &amp;lt; b.k;
}
Point Get_Point(line a, line b)
{
    Point x;
    double dot1, dot2;
    dot1 = (b.a - a.a) * (b.b - a.a);
    dot2 = (b.b - a.b) * (b.a - a.b);
    x.x = (a.a.x * dot2 + a.b.x * dot1) / (dot1 + dot2);
    x.y = (a.a.y * dot2 + a.b.y * dot1) / (dot1 + dot2);
    return x;
}
bool Judge(line a, line b, line c)
{
    Point x = Get_Point(b, c);
    return (a.b - x) * (a.a - x) &amp;gt;= eps;
}
int Q[MAXN];
int main()
{
    int n = read();
    for (int i = 1; i &amp;lt;= n; i++)
        a[i].x = read();
    for (int i = 1; i &amp;lt;= n; i++)
        a[i].y = read();
    a[0].x = a[1].x - 1, a[0].y = 10000000;
    a[n + 1].x = a[n].x + 1, a[n + 1].y = 10000000;
    n++;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        l[i].a = a[i - 1], l[i].b = a[i];
        l[i].k = atan2(a[i].y - a[i - 1].y, a[i].x - a[i - 1].x);
    }
    int cnt = 1;
    sort(l + 1, l + n + 1, cmp);
    for (int i = 2; i &amp;lt;= n; i++)
        if (l[i].k - l[i - 1].k &amp;gt;= eps)
            l[++cnt] = l[i];
    int h = 1, t = 2;
    Q[1] = 1, Q[2] = 2;
    for (int i = 3; i &amp;lt;= cnt; i++)
    {
        while (t &amp;gt; h &amp;amp;&amp;amp; Judge(l[i], l[Q[t - 1]], l[Q[t]])) t--;
        while (t &amp;gt; h &amp;amp;&amp;amp; Judge(l[i], l[Q[h + 1]], l[Q[h]])) h++;
        Q[++t] = i;
    }
    while (t &amp;gt; h &amp;amp;&amp;amp; Judge(l[h], l[Q[t - 1]], l[Q[t]])) t--;
    while (t &amp;gt; h &amp;amp;&amp;amp; Judge(l[t], l[Q[h + 1]], l[Q[h]])) h++;
    int tot = 0;
    for (int i = h + 1; i &amp;lt;= t; i++)
        c[++tot] = Get_Point(l[Q[i - 1]], l[Q[i]]);
    double ans = 1e60;
    for (int i = 1; i &amp;lt; n - 1; i++)
        for (int j = 1; j &amp;lt;= tot; j++)
            if (a[i].x &amp;lt;= c[j].x &amp;amp;&amp;amp; c[j].x &amp;lt;= a[i + 1].x)
            {
                Point t(c[j].x, -1);
                ans = min(ans, c[j].y - Get_Point(line(a[i + 1], a[i]), line(c[j], t)).y);
            }
    for (int i = 1; i &amp;lt;= tot; i++)
        for (int j = 1; j &amp;lt; n; j++)
            if (c[i].x &amp;lt;= a[j].x &amp;amp;&amp;amp; a[j].x &amp;lt;= c[i + 1].x)
            {
                Point t(a[j].x, -1);
                ans = min(ans, Get_Point(line(c[i], c[i + 1]), line(a[j], t)).y - a[j].y);
            }
    printf (&quot;%.3f\n&quot;, ans);
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ1478/1815 Sgu282 Isomorphism/[Shoi2006]color 有色图</title><link>https://www.nekomio.com/posts/135/</link><guid isPermaLink="true">https://www.nekomio.com/posts/135/</guid><pubDate>Tue, 06 Mar 2018 18:40:10 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;给 定一个$N$个结点的无向完全图（ 任意两个结点之间有一条边）， 现在你可以用 $M$ 种颜色对这个图的每条边进行染色，每条边必须染一种颜色。 若两个已染色的图，其中一个图可以通过结点重新编号而与另一个图完全相同， 就称这两个染色方案相同。 现在问你有多少种本质不同的染色方法，输出结果 $mod P$。$P$ 是一个大于$N$的质数。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;仅一行包含三个数，$N$、$M$、$P$。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;仅一行，为染色方法数 $mod P$ 的结果。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;3 4 97
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;20
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;假定一个点置换，把它表示为循环，比如是$(a_1,a_2,....)(b_1,b_2...)(c_1,c_2...)...$&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;对于不在一个循环里面的点： 比如$a1,b1$, 那么会有边循环$((a1,b1),(a2,b2)...)$设$a$循环的循环节是$l1,b$循环的循环节是$l2$,那么形成的边循环的循环节显然是$LCM(l1,l2)$。一共有$l1&lt;em&gt;l2$个点对，每个点对都在一个循环节为$LCM(l1,l2)$的循环上，所以一共有$l1&lt;/em&gt;l2/LCM(l1,l2)=GCD(l1,l2)$个循环节，所以$C(f)=m^GCD(l1,l2)$。（回到$Burnside$引理，$C$为置换之后仍为本身的数目，就是说要循环节里的每条边都一样的颜色）&lt;/li&gt;
&lt;li&gt;对于在一个循环里面的点： 比如$a1$、$a2$。设这个$a$循环的循环节为$l1$。
&lt;ul&gt;
&lt;li&gt;如果$l1$是奇数，那么循环长度为$l1$，一共有$C(l1,2)$个点对，所以是$(l1-1)/2$个循环节，所以$C(f)=m^((l1-1)/2)$。&lt;/li&gt;
&lt;li&gt;如果$l1$是偶数，除了上面这种情况之外，还有一种的循环节是$l1/2$（就是两个点刚好相隔半个周期，而边是双向的），所以一共有$(C(l1,2)-l1/2)/l1+1=l1/2$个点对。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;整理一下：&lt;/p&gt;
&lt;p&gt;$$C = \sum_{i = 1}^{k}{\lfloor \frac{L_i}{2} \rfloor} + \sum_{i = 1}^{k - 1}{\sum_{j = i + 1}^{k} {gcd(L_i, L_j)} }$$&lt;/p&gt;
&lt;p&gt;$$S = \frac{ N! }{\prod_{i = 1} ^ {k} \times \prod_{i = 1}^{k}{ B_i! } }$$&lt;/p&gt;
&lt;p&gt;$$Ans = Ans + S \times m^C$$&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
int MOD;
const int MAXN = 1005;
int gcd(int a, int b)
{
    return b == 0 ? a : gcd(b, a % b);
}
int gd[MAXN][MAXN], f[MAXN];
long long pow_mod(long long a, int b)
{
    long long ans = 1;
    while (b)
    {
        if (b &amp;amp; 1) ans = ans * a % MOD;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % MOD;
    }
    return ans;
}
int l[MAXN];
long long ans;
int n, m;
void Get_Ans(int cnt)
{
    long long C = 0;
    for (int i = 1; i &amp;lt;= cnt; i++) C = (C + l[i] / 2) % MOD;
    for (int i = 1; i &amp;lt;= cnt; i++)
        for (int j = i + 1; j &amp;lt;= cnt; j++)
            C = (C + gd[l[i]][l[j]]) % MOD;
    long long now = 1, len = 0;
    for (int i = 1; i &amp;lt;= cnt; i++)
    {
        if (l[i] != l[i - 1])
        {
            now = now * f[len] % MOD;
            len = 0;
        }
        len++;
    }
    now = now * f[len] % MOD;
    for (int i = 1; i &amp;lt;= cnt; i++) now = now * l[i] % MOD;
    long long S = f[n] * pow_mod(now, MOD - 2) % MOD;
    ans = (ans + S * pow_mod(m, C) % MOD) % MOD;
}
void DFS(int cnt, int x, int les)
{
    if (les == 0) return Get_Ans(cnt);
    if (les &amp;lt; x) return;
    cnt++;
    while (x &amp;lt;= les)
    {
        l[cnt] = x;
        DFS(cnt, x, les - x);
        x++;
    }
}
int main()
{
    n = read(), m = read();
    MOD = read();
    for (int i = 1; i &amp;lt;= n; i++)
        for (int j = 1; j &amp;lt;= n; j++)
            gd[i][j] = gcd(i, j);
    0[f] = 1;
    for (int i = 1; i &amp;lt;= n; i++)
        i[f] = 1ll * ((i - 1)[f]) * i % MOD;
    ans = 0;
    DFS(0, 1, n);
    printf (&quot;%lld\n&quot;, ans * pow_mod(f[n], MOD - 2) % MOD);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ1547 周末晚会</title><link>https://www.nekomio.com/posts/134/</link><guid isPermaLink="true">https://www.nekomio.com/posts/134/</guid><pubDate>Tue, 06 Mar 2018 17:30:33 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;Irena和Sirup正准备下个周末的Party。为这个Party,他们刚刚买了一个非常大的圆桌。他们想邀请每个人，但他们现在不知道如何分配座次。Irena说当有超过K个女孩座位相邻（即这些女孩的座位是连续的，中间没有男孩）的话，她们就会说一整晚的话而不和其他人聊天。 Sirup没有其他选择，只有同意她。然而，作为一名数学家，他很快地痴迷于所有可能方案。 题目说明： $N$个人围绕着圆桌坐着，其中一些是男孩，另一些是女孩。你的任务是找出所有合法的方案数，使得不超过$K$个女孩座位是连续的。 循环同构会被认为是同一种方案。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行有一个数$T$，表示以下有$T$组数据，每组数据有两个整数$N$，$K$。 每组数据之间有一个空行隔开。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;输出$T$行，每行顺次对应一组测试数据。 每组数据你需要输出最后的方案数除以$100000007$的余数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;3
3 1
3 3
4 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;2
4
3
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;解释：&lt;/h5&gt;
&lt;p&gt;第一组数据的方案是：$MMM$，$MMW$ ($M$是男孩, $W$是女孩)。&lt;br /&gt;
第二组数据的方案是：$MMM$，$MMW$，$MWW$，$WWW$。&lt;br /&gt;
第三组数据的方案是：$MMMM$, $MMMW$, $MWMW$。&lt;/p&gt;
&lt;h5&gt;约束和限制：&lt;/h5&gt;
&lt;p&gt;对于20%的数据$T &amp;lt;= 20$;&lt;br /&gt;
对于100%的数据$T &amp;lt;= 50$;&lt;br /&gt;
对于20%的数据$N,K &amp;lt;= 20$;&lt;br /&gt;
对于100%的数据$N,K &amp;lt; = 2000$;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;这又是一道$Burnside$的题目&lt;br /&gt;
首先这是一个环的旋转&lt;br /&gt;
对于每一个$N$，$K$ 都 $DP$ 一发算出$f[i][j]$表示$i$个人最后$j$个为女生,且合法的的方案数&lt;br /&gt;
然后枚举$gcd$的值x， 这个值为循环节个数， 这是可能的旋转次数为$\phi{(\frac{n}{i})}$&lt;br /&gt;
对于这个循环节个数， 我们枚举他前后的女生数目的和&lt;br /&gt;
对于中间不是女生的我们强制第一个和最后一个为男生，乘上$DP$出的值&lt;br /&gt;
在乘上因为前后数目不同而形成的不同方案&lt;br /&gt;
就算完了一个&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MOD = 100000007;
int phi[2005], prime[2005], cnt;
bool isnprime[2005];
void Get_phi()
{
    isnprime[1] = 1;
    for (int i = 2; i &amp;lt;= 2000; i++)
    {
        if (!isnprime[i]) prime[++cnt] = i, phi[i] = i - 1;
        for (int j = 1; j &amp;lt;= cnt; j++)
        {
            if (i * prime[j] &amp;gt; 2000) break;
            isnprime[i * prime[j]] = 1;
            if (i % prime[j] == 0)
            {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            phi[i * prime[j]] = phi[i] * phi[prime[j]];
        }
    }
    phi[1] = 1;
}
long long DP[2005][2005];
int n, k;
long long Calc(int x)
{
    int m = min(x, k);
    long long ans = 0;
    for (int i = 0; i &amp;lt;= m; i++)
    {
        if (i != x) ans = (ans + DP[x - i - 1][0] * (i + 1) % MOD) % MOD;
        if (i == x &amp;amp;&amp;amp; n &amp;lt;= k) ans = (ans + 1) % MOD;
    }
    return ans;
}
long long pow_mod(long long a, int b)
{
    long long ans = 1;
    while (b)
    {
        if (b &amp;amp; 1) ans = ans * a % MOD;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % MOD;
    }
    return ans;
}
int main()
{
    Get_phi();
    int T = read();
    while (T--)
    {
        n = read(), k = read();
        memset (DP, 0, sizeof (DP));
        DP[0][0] = 1;
        for (int i = 0; i &amp;lt; n; i++)
            for (int j = 0; j &amp;lt;= k; j++)
            {
                if (j &amp;lt; k) (DP[i + 1][j + 1] += DP[i][j]) %= MOD;
                (DP[i + 1][0] += DP[i][j]) %= MOD;
            }
        long long ans = 0;
        for (int i = 1; i * i &amp;lt;= n; i++)
            if (n % i == 0)
            {
                ans = (ans + Calc(i) * phi[n / i] % MOD) % MOD;
                if (i * i != n) ans = (ans + Calc(n / i) * phi[i] % MOD) % MOD;
            }
        printf (&quot;%d\n&quot;, ans * pow_mod(n, MOD - 2) % MOD);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ1004 [HNOI2008] Cards</title><link>https://www.nekomio.com/posts/133/</link><guid isPermaLink="true">https://www.nekomio.com/posts/133/</guid><pubDate>Mon, 05 Mar 2018 21:13:22 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有$3$种颜色:红色,蓝色,绿色.他询问 Sun 有多少种染色方案, Sun 很快就给出了答案.进一步,小春要求染出$Sr$张红色,$Sb$张蓝色,$Sg$张绝色.他又询问有多少种方案, Sun 想了一下,又给出了正确答案. 最后小春发明了$M$种不同的洗牌法,这里他又问 Sun 有多少种不同的染色方案.两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种. Sun 发现这个问题有点难度,决定交给你,答案可能很大,只要求出答案除以$P$的余数($P$为质数).&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行输入 $5$ 个整数：$Sr,Sb,Sg,m,p(m&amp;lt;=60,m+1&amp;lt;p&amp;lt;100)$。$n=Sr+Sb+Sg$。&lt;br /&gt;
接下来 $m$ 行，每行描述一种洗牌法，每行有 n 个用格隔开的整数 $X_1 X_2...X_n$，恰为 $1$ 到 $n$ 的一个排列，表示使用这种洗牌法，第 $i$ 位变为原来的 $X_i$ 位的牌。输入数据保证任意多次洗牌都可用这 $m$ 种洗牌法中的一种代替，且对每种洗牌法，都存在一种洗牌法使得能回到原状态。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;不同染法除以$P$的余数&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;1 1 1 2 7
2 3 1
3 1 2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;有 $2$ 种本质上不同的染色法 $RGB$ 和 $RBG$，使用洗牌法 $231$ 一次可得 $GBR$ 和 $BGR$ ，使用洗牌法 $312$ 一次可得 $BRG$ 和 $GRB$。&lt;br /&gt;
$100%$ 数据满足 $Max{Sr,Sb,Sg}&amp;lt;=20$。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;一道比较基础的$Burnside$题目&lt;br /&gt;
这里先介绍一下$Burnside$定理&lt;br /&gt;
设$D(a_j)$为在置换$a_j$下不变的元素的个数。 $L$表示本质不同的方案数&lt;br /&gt;
则$$L = \frac{1}{|G|}\sum_{j = 1}^{|G|}{D(a_j)}$$&lt;/p&gt;
&lt;p&gt;在本题中&lt;br /&gt;
我们群的大小为$m+1$&lt;br /&gt;
对于每一个置换，我们都可以求出它不变的元素个数&lt;br /&gt;
首先求出所有的环， 因为我们的环上必须是同一种颜色才能使他这个元素在置换下不变(这里把涂色方案看做是一个元素)&lt;br /&gt;
我们求出所有环之后就可以$DP$出方案的个数&lt;/p&gt;
&lt;p&gt;!要注意如果要使所有的洗牌法构成一个群，我们必须有一个单位元， 也就是存在一个置换使得任意一个置换与他运算完不变&lt;br /&gt;
在本题中显然是一下$i-&amp;gt;i$的的置换， 但这个置换不是读入的， 而是要自己加上去的。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
int MOD; 
const int MAXN = 65;
int a[MAXN];
long long pow_mod(long long a, int b)
{
    long long ans = 1;
    while (b)
    {
        if (b &amp;amp; 1) ans = ans * a % MOD;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % MOD;
    }
    return ans;
}
int vis[MAXN], st[MAXN];
int dfs(int x, int C)
{
    if (vis[x] == C) return 0;
    vis[x] = C;
    return dfs(a[x], C) + 1;
}
int DP[2][25][25][25];
int main()
{
    int Sr = read(), Sb = read(), Sg = read(), m = read();
    MOD = read();
    int n = Sr + Sb + Sg;
    int Ans = 0;
    memset (vis, -1, sizeof (vis));
    for (int i = 0; i &amp;lt;= m; i++)
    {
        for (int j = 1; j &amp;lt;= n; j++)
            a[j] = (i == 0 ? (j) : read());
        int cnt = 0;
        for (int j = 1; j &amp;lt;= n; j++)
            if (vis[j] != i)
                st[++cnt] = dfs(j, i);
        memset (DP, 0, sizeof (DP));
        DP[0][Sr][Sb][Sg] = 1;
        int now = 0;
        for (int j = 1; j &amp;lt;= cnt; j++)
        {
            now ^= 1;
            memset(DP[now], 0, sizeof (DP[now]));
            for (int r = 0; r &amp;lt;= Sr; r++)
                for (int b = 0; b &amp;lt;= Sb; b++)
                    for (int g = 0; g &amp;lt;= Sg; g++)
                    {
                        if (r + st[j] &amp;lt;= Sr) DP[now][r][b][g] = (DP[now][r][b][g] + DP[now ^ 1][r + st[j]][b][g]) % MOD;
                        if (b + st[j] &amp;lt;= Sb) DP[now][r][b][g] = (DP[now][r][b][g] + DP[now ^ 1][r][b + st[j]][g]) % MOD;
                        if (g + st[j] &amp;lt;= Sg) DP[now][r][b][g] = (DP[now][r][b][g] + DP[now ^ 1][r][b][g + st[j]]) % MOD;
                    }
        }
        Ans = (DP[now][0][0][0] + Ans) % MOD;
    }
    printf (&quot;%d\n&quot;, 1ll * Ans * pow_mod(m + 1, MOD - 2) % MOD);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>UOJ182 【UR #12】a^-1 + b problem</title><link>https://www.nekomio.com/posts/132/</link><guid isPermaLink="true">https://www.nekomio.com/posts/132/</guid><pubDate>Thu, 01 Mar 2018 06:08:11 GMT</pubDate><content:encoded>&lt;p&gt;在你的帮助下，跳蚤国王终于打开了最后一间房间的大门。然而，picks 博士和他的猴子们早已通过地道逃跑了。万幸的是，因为阿姆斯特朗回旋加速喷气式阿姆斯特朗炮本身太过笨重，无法从地道中运走，所以还被静静的停放在房间的正中央。&lt;br /&gt;
拥有了征服世界的力量，跳蚤国王感觉非常一颗赛艇。为了试验这个传说中的武器的威力，跳蚤国王让士兵们把炮口对准空无一人的实验室开炮。&lt;br /&gt;
然而，事情总是没有这么顺利。片刻之后，一个士兵匆匆跑到跳蚤国王身前：“报！picks 博士给它设置了保险！但是我们根本不知道解除方法！”&lt;br /&gt;
经过研究，跳蚤国王发现，picks 博士所设置的保险措施可以简化为这样一个问题：&lt;br /&gt;
首先炮身的屏幕上显示了 $n$ 个数，接着在模 $998244353(7\times 17 \times 2^{23}+1$，一个质数) 意义下，给出了 $m$ 条指令，每一条指令都是下列两种之一：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;给&lt;strong&gt;所有&lt;/strong&gt;数加上某一个数。&lt;/li&gt;
&lt;li&gt;让&lt;strong&gt;所有&lt;/strong&gt;数都变成原来的逆元。（保证这时所有数的逆元都存在）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在每个指令完成之后，你要回答当前屏幕上&lt;strong&gt;所有&lt;/strong&gt;数的和。&lt;br /&gt;
跳蚤国王思索了片刻，发现这个问题奥妙重重，于是他让你——这附近最著名的民间科学家来帮他解决这个难题。&lt;/p&gt;
&lt;h3&gt;输入格式&lt;/h3&gt;
&lt;p&gt;第一行两个正整数 $n,m$，含义如题意所述。&lt;/p&gt;
&lt;p&gt;第二行$n$个数，表示屏幕上最初显示的 $n$ 个数。&lt;/p&gt;
&lt;p&gt;接下来$m$行，表示 $m$ 条指令，第 $i$ 行第一个数$t_i$表示第 $i$ 个操作的类型。&lt;/p&gt;
&lt;p&gt;若 $t_i=1$ 则接下来有一个整数 $x_i$，表示给所有数都加上 $x_i$。&lt;/p&gt;
&lt;p&gt;若 $t_i=2$ 则表示将所有数都变成原来的逆元。&lt;/p&gt;
&lt;h3&gt;输出格式&lt;/h3&gt;
&lt;p&gt;输出$m$行，第$i$行一个整数表示第$i$条指令之后当前屏幕上每个数的和。&lt;/p&gt;
&lt;h3&gt;样例一&lt;/h3&gt;
&lt;h4&gt;input&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;5 5
1 2 3 4 5
1 1
2
1 1
2
2
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;output&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;20
349385525
349385530
292342993
349385530
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;explanation&lt;/p&gt;
&lt;h4&gt;执行每个指令后的数列分别如下：&lt;/h4&gt;
&lt;p&gt;2 3 4 5 6&lt;br /&gt;
499122177 332748118 748683265 598946612 166374059&lt;br /&gt;
499122178 332748119 748683266 598946613 166374060&lt;br /&gt;
665496236 249561089 399297742 831870295 142606337&lt;br /&gt;
499122178 332748119 748683266 598946613 166374060&lt;/p&gt;
&lt;h3&gt;限制与约定&lt;/h3&gt;
&lt;p&gt;&amp;lt;table class=&quot;table table-bordered table-text-center table-vertical-middle&quot;&amp;gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;测试点编号&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;限制与约定&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;1&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;$n, m \leq 1000$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;2&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;$n \leq 100000$, $m \leq 60000$, $t_i = 1$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;3&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;$n, m \leq 10000$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;4&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;$n, m \leq 20000$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;5&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;1&quot;&amp;gt;$n, m \leq 30000$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;6&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;2&quot;&amp;gt;$n \leq 100000$, $m \leq 30000$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;7&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;8&amp;lt;/td&amp;gt;&amp;lt;td rowspan=&quot;3&quot;&amp;gt;$n \leq 100000$, $m \leq 60000$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;9&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;10&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/tbody&amp;gt;&amp;lt;/table&amp;gt;&lt;/p&gt;
&lt;p&gt;对于所有数据$1 \le n \le 100000$，$1 \le m \le 60000$, $t_i \in {1, 2}$其他所有数均为区间中的整数。&lt;/p&gt;
&lt;p&gt;保证任何时候每个数的逆元均存在。&lt;/p&gt;
&lt;p&gt;时间限制：$4s$
空间限制：$256MB$&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;出门左拐&lt;a href=&quot;http://jiry-2.blog.uoj.ac/blog/1375&quot;&gt;UOJ&lt;/a&gt;;
那一毫秒的距离&lt;br /&gt;
&lt;img src=&quot;https://i.loli.net/2018/02/28/5a96b2464c28b.png&quot; alt=&quot;PNG&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
const int MAXN = 1e6 * 4;
const int MOD  = 998244353;
const int L = (1 &amp;lt;&amp;lt; 18) + 1;
const int LM = (1 &amp;lt;&amp;lt; 16) + 1;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
int N, Inv, rev[MAXN];
int Sum = 0, n, m;
struct data
{
    int e, f, g, id;
}s[60005];
long long pow_mod(long long a, int b)
{
    long long ans = 1;
    while (b)
    {
        if (b &amp;amp; 1)
            ans = ans * a % MOD;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % MOD;
    }
    return ans;
}
int ans[MAXN], cnt;
void insert(int a, int b, int c, int d, int id)
{
    if (b == 0)
    {
        ans[id] = ((1ll * a * Sum) + (1ll * c * n)) % MOD * pow_mod(d, MOD - 2) % MOD;
        return;
    }
    s[++cnt].f = (1ll * b * c - 1ll * a * d) % MOD;
    b = pow_mod(b, MOD - 2);
    s[cnt].e = 1ll * a * b % MOD, s[cnt].g = 1ll * d * b % MOD;
    b = 1ll * b * b % MOD; s[cnt].f = 1ll * s[cnt].f * b % MOD;
    if (s[cnt].f &amp;lt; 0) s[cnt].f += MOD;
    s[cnt].id = id;
}
void Init(int x)
{
    N = 1;
    while (N &amp;lt; (x &amp;lt;&amp;lt; 1)) N &amp;lt;&amp;lt;= 1;
    Inv = pow_mod(N, MOD - 2);
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
}
inline int Calc(int x)
{
    N = 1;
    while (N &amp;lt; (x &amp;lt;&amp;lt; 1)) N &amp;lt;&amp;lt;= 1;
    return N;
}
void FFt(int *a, int op)
{
    int w, wn, t;
    for (int i = 0; i &amp;lt; N; i++)
        if (i &amp;lt; rev[i])
            swap(a[i], a[rev[i]]);
    for (int k = 2; k &amp;lt;= N; k &amp;lt;&amp;lt;= 1)
    {
        wn = pow_mod(3, op == 1 ? (MOD - 1) / k : MOD - 1 - (MOD - 1) / k);
        for (int j = 0; j &amp;lt; N; j += k)
        {
            w = 1;
            for (int i = 0; i &amp;lt; (k &amp;gt;&amp;gt; 1); i++, w = 1ll * w * wn % MOD)
            {
                t = 1ll * a[i + j + (k &amp;gt;&amp;gt; 1)] * w % MOD;
                a[i + j + (k &amp;gt;&amp;gt; 1)] = (a[i + j] - t + MOD) % MOD;
                a[i + j] = (a[i + j] + t) % MOD;
            }
        }
    }
    if (op == -1)
        for (int i = 0; i &amp;lt; N; i++)
            a[i] = 1ll * a[i] * Inv % MOD;
}
int tmp[MAXN], x[MAXN];
void Get_Inv(int *a, int *b, int n)
{
    if (n == 1) return b[0] = pow_mod(a[0], MOD - 2), void();
    Get_Inv(a, b, n + 1 &amp;gt;&amp;gt; 1);
    Init(n);
    for (int i = 0; i &amp;lt; n; i++) tmp[i] = a[i];
    for (int i = n; i &amp;lt; N; i++) tmp[i] = 0;
    FFt(tmp, 1), FFt(b, 1);
    for (int i = 0; i &amp;lt; N; i++) 
        b[i] = 1ll * b[i] * ((2 - 1ll * b[i] * tmp[i] % MOD + MOD) % MOD) % MOD;
    FFt(b, -1);
    for (int i = n; i &amp;lt; N; i++) b[i] = 0;
}
int Get_mod(int *a, int ra, int *b, int rb, int *c)
{
    while (ra &amp;amp;&amp;amp; !a[ra - 1]) --ra;
    while (rb &amp;amp;&amp;amp; !b[rb - 1]) --rb;
    if (ra &amp;lt; rb)
    {
        memcpy (c, a, ra &amp;lt;&amp;lt; 2);
        memset (c + ra, 0, (rb - ra) &amp;lt;&amp;lt; 2);
        return rb;
    }
    static int tmp1[MAXN], tmp2[MAXN];
    int rc = ra - rb + 1;
    int l = Calc(rc);
    for (int i = 0; i &amp;lt; l; i++) tmp1[i] = 0;
    reverse_copy(b, b + rb, tmp1);
    for (int i = 0; i &amp;lt; l; i++) tmp2[i] = 0;
    // for (int i = 0; i &amp;lt; rb; i++) printf (&quot;1: %d, tmp1: %d\n&quot;, rb, tmp1[i]);    
    Get_Inv(tmp1, tmp2, rc);
    for (int i = rc; i &amp;lt; l; i++) tmp2[i] = 0;
    reverse_copy(a, a + ra, tmp1);
    for (int i = rc; i &amp;lt; l; i++) tmp1[i] = 0;
    Init(rc), FFt(tmp1, 1), FFt(tmp2, 1);
    for (int i = 0; i &amp;lt; N; i++) tmp1[i] = 1ll * tmp1[i] * tmp2[i] % MOD;
    FFt(tmp1, -1);
    // for (int i = 0; i &amp;lt; rb; i++) printf (&quot;2: %d, tmp1: %d\n&quot;, rb, tmp1[i]);    
    reverse(tmp1, tmp1 + rc);
    // for (int i = 0; i &amp;lt; rb; i++) printf (&quot;3: %d, tmp1: %d\n&quot;, rb, tmp1[i]);    
    Init(ra);
    for (int i = 0; i &amp;lt; rb; i++) tmp2[i] = b[i];
    for (int i = rb; i &amp;lt; N; i++) tmp2[i] = 0;
    for (int i = rc; i &amp;lt; N; i++) tmp1[i] = 0;
    FFt(tmp1, 1), FFt(tmp2, 1);
    for (int i = 0; i &amp;lt; N; i++) tmp1[i] = 1ll * tmp1[i] * tmp2[i] % MOD;
    FFt(tmp1, -1);
    // for (int i = 0; i &amp;lt; rb; i++) printf (&quot;4: %d, tmp1: %d\n&quot;, rb, tmp1[i]);
    for (int i = 0; i &amp;lt; rb; i++) c[i] = (a[i] - tmp1[i] + MOD) % MOD;
    for (int i = rb; i &amp;lt; N; i++) c[i] = 0;
    // for (int i = 0; i &amp;lt; rb; i++) printf (&quot;C: %d, %d\n&quot;, rb, c[i]);
    while (rb &amp;amp;&amp;amp; !c[rb - 1]) --rb;
    return rb;
}
int Solve0(int *a, int l, int r)
{
    int ra = r - l + 2;
    if (ra &amp;lt;= 256)
    {
        memset(a, 0, ra &amp;lt;&amp;lt; 2), a[0] = 1;
        for (int i = l; i &amp;lt;= r; i++)
            for (int v = x[i], j = i - l; j != -1; j--)
            {
                a[j + 1] = (a[j + 1] + a[j]) % MOD;
                a[j] = 1ll * a[j] * v % MOD;
            }
        return ra;
    }
    int mid = l + r &amp;gt;&amp;gt; 1;
    int *f1 = a, r1 = Solve0(f1, l, mid);
    int *f2 = a + r1, r2 = Solve0(f2, mid + 1, r);
    N = 1;
    while (N &amp;lt; ra) N &amp;lt;&amp;lt;= 1;
    Inv = pow_mod(N, MOD - 2);
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    static int tmp1[L], tmp2[L];
    memcpy(tmp1, f1, r1 &amp;lt;&amp;lt; 2), memset (tmp1 + r1, 0, (N - r1) &amp;lt;&amp;lt; 2), FFt(tmp1, 1);
    memcpy(tmp2, f2, r2 &amp;lt;&amp;lt; 2), memset (tmp2 + r2, 0, (N - r2) &amp;lt;&amp;lt; 2), FFt(tmp2, 1);
    for (int i = 0; i &amp;lt; N; i++) a[i] = 1ll * tmp1[i] * tmp2[i] % MOD;
    FFt(a, -1);
    return ra;
}
int *p[L];
int sta[MAXN];
int mem[LM &amp;lt;&amp;lt; 4], *head = mem;
inline int Solve1(int id, int l, int r)
{
    int ra = r - l + 2;
    if (ra &amp;lt;= 256)
    {
        int *f = p[id] = head; head += ra;
        memset (f, 0, ra &amp;lt;&amp;lt; 2), 0[f] = 1;
        for (int i = l; i &amp;lt;= r; i++)
            for (int v = (MOD - sta[i]) % MOD, j = i - l; j != -1; j--)
                f[j + 1] = (f[j + 1] + f[j]) % MOD, f[j] = 1ll * f[j] * v % MOD;
        return ra;
    }
    int mid = l + r &amp;gt;&amp;gt; 1;
    int r1 = Solve1(id &amp;lt;&amp;lt; 1, l, mid), *f1 = p[id &amp;lt;&amp;lt; 1];
    int r2 = Solve1(id &amp;lt;&amp;lt; 1 | 1, mid + 1, r), *f2 = p[id &amp;lt;&amp;lt; 1 | 1];
    N = 1;
    while (N &amp;lt; ra) N &amp;lt;&amp;lt;= 1;
    Inv = pow_mod(N, MOD - 2);
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    static int tmp1[LM], tmp2[LM];
    memcpy(tmp1, f1, r1 &amp;lt;&amp;lt; 2), memset (tmp1 + r1, 0, (N - r1) &amp;lt;&amp;lt; 2), FFt(tmp1, 1);
    memcpy(tmp2, f2, r2 &amp;lt;&amp;lt; 2), memset (tmp2 + r2, 0, (N - r2) &amp;lt;&amp;lt; 2), FFt(tmp2, 1);
    int *f = p[id] = head; head += ra;
    for (int i = 0; i &amp;lt; N; i++) f[i] = 1ll * tmp1[i] * tmp2[i] % MOD;
    FFt(f, -1);
    return ra; 
}
int val0[LM], val[LM];
void Solve2(int id, int *a, int *b, int l, int r, int deg)
{
    int ra = r - l + 2;
    if (deg &amp;lt;= 256)
    {
        int F, G;
        for (int i = l; i &amp;lt;= r; i++)
        {
            F = G = 0;
            int u = sta[i], v = 1;
            for (int j = 0; j &amp;lt;= deg; j++)
            {
                F = (F + 1ll * v * a[j]) % MOD;
                G = (G + 1ll * v * b[j]) % MOD;
                v = 1ll * v * u % MOD;
            }
            val0[i] = F, val[i] = G;
        }
        return;
    }
    int mid = l + r &amp;gt;&amp;gt; 1;
    int r1 = Get_mod(a, deg, p[id], ra, a + deg); a += deg;
    int r2 = Get_mod(b, deg, p[id], ra, b + deg); b += deg;
    ra = min(r1, r2);
    Solve2(id &amp;lt;&amp;lt; 1, a, b, l, mid, ra), Solve2(id &amp;lt;&amp;lt; 1 | 1, a, b, mid + 1, r, ra);
}
int g[MAXN], h[MAXN];
int main()
{
    // freopen (&quot;1.in&quot;, &quot;r&quot;, stdin);
    // freopen (&quot;1.out&quot;, &quot;w&quot;, stdout);
    n = read(), m = read();
    Sum = 0;
    for (int i = 1; i &amp;lt;= n; i++)
        x[i] = read() % MOD, Sum = (Sum + x[i]) % MOD;
    int A = 1, B = 0, C = 0, D = 1;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        if (read() == 1)
        {
            int v = read() % MOD;
            A = (A + 1ll * v * B % MOD) % MOD;
            C = (C + 1ll * v * D % MOD) % MOD;
            insert(A, B, C, D, i);
        }
        else
        {
            swap(A, B);
            swap(C, D);
            insert(A, B, C, D, i);
        }
    }
    if (cnt)
    {
        for (int i = 1; i &amp;lt;= cnt; i++) sta[i] = s[i].g;
        sort(sta + 1, sta + cnt + 1);
        int lenth = unique(sta + 1, sta + cnt + 1) - sta - 1;
        for (int i = 1; i &amp;lt;= cnt; i++)
            s[i].g = lower_bound(sta + 1, sta + lenth + 1, s[i].g) - sta;
        Solve0(g, 1, n);
        for (int i = 1; i &amp;lt;= n; i++) h[i - 1] = 1ll * g[i] * i % MOD;
        Solve1(1, 1, lenth);
        Solve2(1, g, h, 1, lenth, n + 1);
        for (int i = 1; i &amp;lt;= cnt; i++)
            ans[s[i].id] = (1ll * s[i].e * n % MOD + 1ll * s[i].f * val[s[i].g] % MOD * pow_mod(val0[s[i].g], MOD - 2) % MOD) % MOD;
    }
    for (int i = 1; i &amp;lt;= m; i++)
        printf (&quot;%d\n&quot;, ans[i]);
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>UOJ50 【UR #3】链式反应</title><link>https://www.nekomio.com/posts/131/</link><guid isPermaLink="true">https://www.nekomio.com/posts/131/</guid><pubDate>Wed, 28 Feb 2018 19:04:10 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;p&amp;gt;著名核物理专家 Picks 最近发现了一种非常适合核裂变的元素叫囧元素。囧元素原子序数为 1024，囧-2333 如果被一个中子撞击后会分裂成 蒟-1234 和 蒻-1098 同时&amp;lt;strong&amp;gt;释放出恰好 $2$ 个中子&amp;lt;/strong&amp;gt;，并且&amp;lt;strong&amp;gt;以破坏死光的方式释放光子&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;核物理专家 Picks 做实验从来不用实验仪器。他用手指从宇宙中挑选出了 $n$ 个 囧-2333 原子并编号为 $1$ 到 $n$，并用帅气的眼神发射中子撞击了编号为 $1$ 的囧原子，启动了链式反应。&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;当一个囧-2333原子被中子撞击时，有两种情况。要么这个囧-2333原子变为了囧-2334 并不再参与后续反应，要么囧-2333会进行核裂变，一方面，裂变产生的破坏死光会&amp;lt;strong&amp;gt;照射到 $c$ 个不同的囧-2333原子&amp;lt;/strong&amp;gt;并且这些原子会极为神奇地分解为氢和氦的混合物并不再参与后续反应。另一方面，裂变后产生的 $2$ 个中子会&amp;lt;strong&amp;gt;分别撞上两个不同的囧-2333原子&amp;lt;/strong&amp;gt;。显然被破坏死光照射后就不是囧-2333了，所以不可能又被中子撞上又被破坏死光照射到。&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;经过反复实验，核物理专家 Picks 终于确定了 $c$ 的范围 $A$，其中 $A$ 是一个非负整数集合。每次破坏死光会照射并影响到的囧-2333原子数量 $c$ 满足 $c \in A$ 。&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;链式反应时 Picks 会用肉眼观察实验中出现的事件（仅包括中子的撞击和破坏死光的信息），结束后 Picks 会写下实验记录。&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;但是很不幸 Picks 的实验记录丢失了。他只记得链式反应后&amp;lt;strong&amp;gt;没有剩余的囧-2333原子&amp;lt;/strong&amp;gt;，而且每次一个囧-2333原子核裂变时，中子总是撞击&amp;lt;strong&amp;gt;编号比它大的囧-2333原子&amp;lt;/strong&amp;gt;，破坏死光也总是照射&amp;lt;strong&amp;gt;编号比它大的囧-2333原子&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;求可能会有多少种不同的实验记录。你需要对于 $n = 1, \dots, n_{max}$ 输出答案。你只用输出答案对 $998244353$（$7 \times 17 \times 2^{23} + 1$，一个质数）取模后的值。&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;两个实验记录 $T_1$，$T_2$ 被认为是相同的当且仅当：&amp;lt;/p&amp;gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;“编号为 $v$ 的囧-2333分裂产生的中子撞上了编号为 $u$ 的囧-2333” 这个事件在 $T_1$ 中当且仅当这个事件在 $T_2$ 中。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;“编号为 $v$ 的囧-2333分裂产生的破坏死光照射了编号为 $u$ 的囧-2333” 这个事件在 $T_1$ 中当且仅当这个事件在 $T_2$ 中。&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;&amp;lt;h3&amp;gt;输入格式&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;第一行一个正整数 $n_{max}$。&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;第二行是一个长度为 $n_{max}$ 的01字符串。如果把字符从 $0$ 开始编号，那么第 $i$ 个字符为 $0$ 表示 $i$ 不在集合 $A$ 内，否则表示 $i$ 在集合 $A$ 内。&amp;lt;/p&amp;gt;
&amp;lt;h3&amp;gt;输出格式&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;$n_{max}$ 行，如果把行从 $1$ 开始编号，那么第 $i$ 行表示 $n = i$ 时该问题的答案。&amp;lt;/p&amp;gt;
&amp;lt;h3&amp;gt;样例一&amp;lt;/h3&amp;gt;
&amp;lt;h4&amp;gt;input&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;5
10100
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;output&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;1
0
1
0
10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;explanation&amp;lt;/h4&amp;gt;
&amp;lt;p&amp;gt;$n = 1$ 时，只有一种实验记录。&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;$n = 2$ 时，没有可能的实验记录。&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;$n = 3$ 时，唯一可能的实验记录为：&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的中子撞上了编号为 $2$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的中子撞上了编号为 $3$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&amp;lt;p&amp;gt;$n = 4$ 时，没有可能的实验记录。&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;$n = 5$ 时，有十种可能的实验记录。第一种是：&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的中子撞上了编号为 $2$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的中子撞上了编号为 $3$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $2$ 的囧-2333分裂产生的中子撞上了编号为 $4$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $2$ 的囧-2333分裂产生的中子撞上了编号为 $5$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&amp;lt;p&amp;gt;第二种是：&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的中子撞上了编号为 $2$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的中子撞上了编号为 $4$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $2$ 的囧-2333分裂产生的中子撞上了编号为 $3$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $2$ 的囧-2333分裂产生的中子撞上了编号为 $5$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&amp;lt;p&amp;gt;第三种是：&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的中子撞上了编号为 $2$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的中子撞上了编号为 $5$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $2$ 的囧-2333分裂产生的中子撞上了编号为 $3$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $2$ 的囧-2333分裂产生的中子撞上了编号为 $4$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&amp;lt;p&amp;gt;第四种是：&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的中子撞上了编号为 $2$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的中子撞上了编号为 $3$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $3$ 的囧-2333分裂产生的中子撞上了编号为 $4$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $3$ 的囧-2333分裂产生的中子撞上了编号为 $5$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&amp;lt;p&amp;gt;第五种是：&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的中子撞上了编号为 $2$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的中子撞上了编号为 $3$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的破坏死光照射了编号为 $4$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;编号为 $1$ 的囧-2333分裂产生的破坏死光照射了编号为 $5$ 的囧-2333。&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&amp;lt;p&amp;gt;第六种到第十种均与第五种类似。空白太小我就不演示了。&amp;lt;/p&amp;gt;
&amp;lt;h3&amp;gt;样例二&amp;lt;/h3&amp;gt;
&amp;lt;h4&amp;gt;input&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;8
10000000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;output&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1
0
1
0
4
0
34
0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h3&amp;gt;样例三&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;见样例数据下载&amp;lt;/p&amp;gt;
&amp;lt;h3&amp;gt;样例四&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;见样例数据下载&amp;lt;/p&amp;gt;
&amp;lt;h3&amp;gt;限制与约定&amp;lt;/h3&amp;gt;
&amp;lt;div class=&quot;table-responsive&quot;&amp;gt;
&amp;lt;table class=&quot;table table-bordered table-text-center table-vertical-middle&quot;&amp;gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;测试点编号&amp;lt;/th&amp;gt;
&amp;lt;th&amp;gt;$n$&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 8$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 100$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;3&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 100$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;4&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 200$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 5000$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;6&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 5000$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;7&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 50000$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;8&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 50000$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;9&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 70000$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;10&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$n \leq 200000$&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/tbody&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;时间限制：&amp;lt;/strong&amp;gt;$4\texttt{s}$&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;空间限制：&amp;lt;/strong&amp;gt;$256\texttt{MB}$&amp;lt;/p&amp;gt;
&amp;lt;h3&amp;gt;下载&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&quot;/download.php?type=problem&amp;amp;id=50&quot;&amp;gt;样例数据下载&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;设$f[i]$为$n$个节点的树的方案数$f[1] = 1$&lt;br /&gt;
我们设两个中子打中的子树大小为j,k&lt;br /&gt;
则答案为$f[n] = \sum_{j}\sum_{k}C_{n - 1}^{j}C_{n - 1 - j}^{k}*f[j]*f[k]$&lt;br /&gt;
然后DP有40分&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
# define int long long 
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 1000;
const int MOD = 998244353;
char s[MAXN];
int F[MAXN];
int c[MAXN][MAXN];
int Inv2 = 499122177;
int DP(int x)
{
    if (F[x] != -1) return F[x];
    if (x == 1) return F[x] = 1;
    else F[x] = 0;
    for (int i = 1; i &amp;lt;= x; i++)
        for (int j = 1; j &amp;lt;= x; j++)
            if (x - 1 - i - j &amp;gt;= 0 &amp;amp;&amp;amp; s[x - 1 - i - j])
                (F[x] += 1ll * DP(i) * DP(j) % MOD * c[x - 1][i] % MOD * c[x - 1 - i][j] % MOD * Inv2 % MOD) %= MOD;
    return F[x];
}
signed main()
{
    int n = read();
    scanf (&quot;%s&quot;, s);
    for (int i = 0; i &amp;lt; n; i++) s[i] -= &apos;0&apos;;
    c[0][0] = 1;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        c[i][0] = 1;
        for (int j = 1; j &amp;lt;= n; j++)
            c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % MOD;
    }
    memset (F, -1, sizeof (F));
    for (int i = 1; i &amp;lt;= n; i++) 
        printf (&quot;%d\n&quot;, DP(i));
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;建立生成函数&lt;br /&gt;
设$f(x)$为答案的生成函数&lt;br /&gt;
设$g(x)$为限制条件的生成函数&lt;br /&gt;
则$f&apos;(x)=\frac{1}{2}f^{2}(x)g(x)+1$&lt;br /&gt;
可以CDQ+FFT用$0 \cdots n-1$的$f$来更新$f(n)$&lt;br /&gt;
时间复杂度$O(n\log^{2}{n})$&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 200005 * 4;
const int MOD = 998244353;
long long pow_mod(long long a, int b)
{
    long long ans = 1;
    while (b)
    {
        if (b &amp;amp; 1) ans = ans * a % MOD;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % MOD;
    }
    return ans;
}
char s[MAXN];
int F[MAXN], FInv[MAXN];
int g[MAXN], f[MAXN], h[MAXN];
int N, Inv;
int rev[MAXN];
int tmp1[MAXN], tmp2[MAXN];
int Init(int x)
{
    N = 1;
    while (N &amp;lt; (x &amp;lt;&amp;lt; 1)) N &amp;lt;&amp;lt;= 1;
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    Inv = pow_mod(N, MOD - 2);
}
void FFt(int *a, int op)
{
    int w, wn, t;
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;lt; rev[i])
            swap(a[i], a[rev[i]]);
    for (int k = 2; k &amp;lt;= N; k &amp;lt;&amp;lt;= 1)
    {
        wn = pow_mod(3, op == 1 ? (MOD - 1) / k : MOD - 1 - (MOD - 1) / k);
        for (int j = 0; j &amp;lt; N; j += k)
        {
            w = 1;
            for (int i = 0; i &amp;lt; (k &amp;gt;&amp;gt; 1); i++, w = 1ll * w * wn % MOD)
            {
                t = 1ll * a[i + j + (k &amp;gt;&amp;gt; 1)] * w % MOD;
                a[i + j + (k &amp;gt;&amp;gt; 1)] = (a[i + j] - t + MOD) % MOD;
                a[i + j] = (a[i + j] + t) % MOD;
            }
        }
    }
    if (op == -1)
        for (int i = 0; i &amp;lt; N; i++)
            a[i] = 1ll * a[i] * Inv % MOD;
}
void Solve(int l, int r)
{
    if (l == r) return;
    int mid = l + r &amp;gt;&amp;gt; 1;
    Solve(l, mid);
    Init(r - l + 1);
    memset (tmp1, 0, N &amp;lt;&amp;lt; 2);
    memset (tmp2, 0, N &amp;lt;&amp;lt; 2);
    for (int i = l; i &amp;lt;= mid; i++) tmp1[i - l] = f[i];
    for (int i = 0; i &amp;lt;= r - l; i++)
        if (i &amp;lt; l) tmp2[i] = 2 * f[i] % MOD;
        else if (i &amp;lt;= mid) tmp2[i] = f[i];
    FFt(tmp1, 1), FFt(tmp2, 1);
    for (int i = 0; i &amp;lt; N; i++) tmp1[i] = 1ll * tmp1[i] * tmp2[i] % MOD;
    FFt(tmp1, -1);
    for (int i = mid + 1; i &amp;lt;= r; i++) h[i] = (h[i] + tmp1[i - l]) % MOD;
    memset (tmp1, 0, N &amp;lt;&amp;lt; 2);
    memset (tmp2, 0, N &amp;lt;&amp;lt; 2);
    for (int i = l; i &amp;lt;= mid; i++) tmp1[i - l] = h[i];
    for (int i = 0; i &amp;lt;= r - l; i++) tmp2[i] = g[i];
    FFt(tmp1, 1), FFt(tmp2, 1);
    for (int i = 0; i &amp;lt; N; i++) tmp1[i] = 1ll * tmp1[i] * tmp2[i] % MOD;
    FFt(tmp1, -1);
    for (int i = mid + 1; i &amp;lt;= r; i++) f[i] = (f[i] + 1ll * tmp1[i - l - 1] * F[i - 1] % MOD * FInv[i] % MOD) % MOD;
    Solve(mid + 1, r);
}
int main()
{
    int n = read();
    scanf (&quot;%s&quot;, s);
    for (int i = 0; i &amp;lt; n; i++) s[i] -= &apos;0&apos;;
    F[0] = 1;
    for (int i = 1; i &amp;lt;= n; i++) F[i] = 1ll * F[i - 1] * i % MOD;
    FInv[n] = pow_mod(F[n], MOD - 2);
    for (int i = n - 1; i &amp;gt;= 0; i--) FInv[i] = 1ll * FInv[i + 1] * (i + 1) % MOD;
    for (int i = 0; i &amp;lt; n; i++) g[i] = 1ll * s[i] * FInv[i] * FInv[2] % MOD;
    f[1] = 1;
    Solve(1, n);
    for (int i = 1; i &amp;lt;= n; i++)
        printf (&quot;%d\n&quot;, 1ll * f[i] * F[i] % MOD);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ3684: 大朋友和多叉树</title><link>https://www.nekomio.com/posts/130/</link><guid isPermaLink="true">https://www.nekomio.com/posts/130/</guid><pubDate>Mon, 26 Feb 2018 08:52:23 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;我们的大朋友很喜欢计算机科学，而且尤其喜欢多叉树。对于一棵带有正整数点权的有根多叉树，如果它满足这样的性质，我们的大朋友就会将其称作神犇的：点权为1的结点是叶子结点；对于任一点权大于1的结点u，u的孩子数目deg[u]属于集合D，且u的点权等于这些孩子结点的点权之和。
给出一个整数s，你能求出根节点权值为s的神犇多叉树的个数吗？请参照样例以更好的理解什么样的两棵多叉树会被视为不同的。
我们只需要知道答案关于950009857（453*2^21+1，一个质数）取模后的值。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行有2个整数s,m。
第二行有m个互异的整数，d[1],d[2],…,d[m]，为集合D中的元素。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;输出一行仅一个整数，表示答案模950009857的值。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;4 2
2 3
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;10
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2018/02/26/5a935c934121c.jpg&quot; alt=&quot;aa.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;数据规模：
$1 \leq m &amp;lt; s \leq 10^5$, $2 \leq d[i] \leq s$，有3组小数据和3组大数据。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;求出树的生成函数$T(x) = \sum_{i\ge 0} t_ix^i$
$$T(x) = x + \sum_{k \in S}T(x)^k$$&lt;/p&gt;
&lt;p&gt;移一下项
$$T(x) - \sum_{k \in S}T(x)^k = x$$&lt;/p&gt;
&lt;p&gt;设$G(y) = y - \sum_{k \in S}{y^k}$&lt;/p&gt;
&lt;p&gt;$$x = G(T(x))$$&lt;/p&gt;
&lt;p&gt;$T(x)$为$G(x)$的复合逆&lt;/p&gt;
&lt;p&gt;上拉格朗日反演&lt;/p&gt;
&lt;p&gt;$$ [x^n]T(x) = \frac{1}{n}[x^{n-1}] ( \frac {x}{G(x)} )^n $$&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
const int MOD = 950009857;
const int MAXN = 2e6 + 5;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
long long pow_mod(long long a, int b)
{
    long long ans = 1;
    while (b)
    {
        if (b &amp;amp; 1) ans = ans * a % MOD;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % MOD;
    }
    return ans;
}
int rev[MAXN];
int Inv;
void FFt(int *a, int N, int op)
{
    int w, wn, t;
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;lt; rev[i])
            swap(a[i], a[rev[i]]);
    for (int k = 2; k &amp;lt;= N; k &amp;lt;&amp;lt;= 1)
    {
        wn = pow_mod(7, op == 1 ? (MOD - 1) / k : MOD - 1 - (MOD - 1) / k);
        for (int j = 0; j &amp;lt; N; j += k)
        {
            w = 1;
            for (int i = 0; i &amp;lt; (k &amp;gt;&amp;gt; 1); i++, w = 1ll * w * wn % MOD)
            {
                t = 1ll * a[i + j + (k &amp;gt;&amp;gt; 1)] * w % MOD;
                a[i + j + (k &amp;gt;&amp;gt; 1)] = (a[i + j] - t + MOD) % MOD;
                a[i + j] = (a[i + j] + t) % MOD;
            }
        }
    }
    if (op == -1)
        for (int i = 0; i &amp;lt; N; i++)
            a[i] = 1ll * a[i] * Inv % MOD;
}
int tmp[MAXN];
void Get_Inv(int dep, int *a, int *b)
{
    if (dep == 1) return b[0] = pow_mod(a[0], MOD - 2), void();
    Get_Inv((dep + 1) &amp;gt;&amp;gt; 1, a, b);
    int N = 1;
    while (N &amp;lt; (dep &amp;lt;&amp;lt; 1))
        N &amp;lt;&amp;lt;= 1;
    Inv = pow_mod(N, MOD - 2);
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    //copy(a, a + dep, tmp);
    for (int i = 0; i &amp;lt; dep; i++)
        tmp[i] = a[i];
    for (int i = dep; i &amp;lt; N; i++)
        tmp[i] = 0;
    //fill(tmp + dep, tmp + N, 0);
    FFt(tmp, N, 1);
    FFt(b, N, 1);
    for (int i = 0; i &amp;lt; N; i++)
        b[i] = 1ll * b[i] * ((2 - 1ll * b[i] * tmp[i] % MOD + MOD) % MOD) % MOD;
    FFt(b, N, -1);
    for (int i = dep; i &amp;lt; N; i++)
        b[i] = 0;
    //fill(b + dep, b + N, 0);
}
int G[MAXN], Ans[MAXN], C[MAXN];
int main()
{
    int n = read(), m = read();
    C[0] = 1;
    for (int i = 1; i &amp;lt;= m; i++)
        C[read() - 1] = MOD - 1;
    Get_Inv(n, C, G);
    Ans[0] = 1;
    int b = n;
    int N = 1;
    while (N &amp;lt; 2 * n)
        N &amp;lt;&amp;lt;= 1;
    Inv = pow_mod(N, MOD - 2);
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    while (b)
    {
        if (b &amp;amp; 1)
        {
            FFt(Ans, N, 1);
            FFt(G, N, 1);
            for (int i = 0; i &amp;lt; N; i++) Ans[i] = 1ll * Ans[i] * G[i] % MOD;
            FFt(Ans, N, -1);
            FFt(G, N, -1);
            for (int i = n; i &amp;lt; N; i++)
                Ans[i] = 0;
        }
        b &amp;gt;&amp;gt;= 1;
        FFt(G, N, 1);
        for (int i = 0; i &amp;lt; N; i++) G[i] = 1ll * G[i] * G[i] % MOD;
        FFt(G, N, -1);
        for (int i = n; i &amp;lt; N; i++)
            G[i] = 0;
        // fill(G + n, G + N, 0);
    }
    printf (&quot;%d\n&quot;, 1ll * Ans[n - 1] * pow_mod(n, MOD - 2) % MOD);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ3456: 城市规划</title><link>https://www.nekomio.com/posts/129/</link><guid isPermaLink="true">https://www.nekomio.com/posts/129/</guid><pubDate>Mon, 26 Feb 2018 08:10:23 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.
刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.
好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目.
由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;仅一行一个整数n(&amp;lt;=130000)&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;仅一行一个整数, 为方案数 mod 1004535809.&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt; 3
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt; 4
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;对于 100%的数据, n &amp;lt;= 130000&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;设无向图的生成函数为$G(x)$, 无向联通图的生成函数为$f(x)$
$$g(x) = 2^{C_n^2}$$
枚举无向图是由几个联通图构成的:
$$g(n) = \sum_{i = 1}^{n} { {n - 1} \choose {i - 1} } f(i) G(n - i)$$
$$2^{n \choose 2} = \sum_{i = 1}^{n} { {n - 1} \choose {i - 1} } f(i) 2^{ {n - i} \choose 2}$$
然后两边同时除以 $$(n-1)!$$
$$\frac{2^{n \choose 2} }{(n-1)!} = \sum_{i = 1}^{n} \frac{f(i)}{(i-1)!} \frac{2^{ {n - i} \choose 2} }{(n-i)!}$$&lt;/p&gt;
&lt;p&gt;定义函数 $F(x),G(x),C(x)$&lt;/p&gt;
&lt;p&gt;$$F(x) = \sum_{n=1}^{\infty} \frac{f(n)}{(n-1)!}x^n$$&lt;br /&gt;
$$G(x) = \sum_{n=0}^{\infty} \frac{2^{n \choose 2} }{n!}x^n $$
$$C(x) = \sum_{n=0}^{\infty} \frac{2^{n \choose 2} }{(n-1)!}x^n$$&lt;/p&gt;
&lt;p&gt;$$C(x) = F(x)G(x)$$&lt;/p&gt;
&lt;p&gt;$$C(x) \equiv F(x)G(x) mod { x^{n+1} }$$&lt;/p&gt;
&lt;p&gt;$$F(x) \equiv C(x)G^{-1}(x) mod { x^{n+1} }$$&lt;/p&gt;
&lt;p&gt;多项式求逆&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MOD = 1004535809;
const int MAXN = 1 &amp;lt;&amp;lt; 18 + 1;
long long pow_mod(long long a, int b)
{
    long long ans = 1;
    while (b)
    {
        if (b &amp;amp; 1) ans = ans * a % MOD;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % MOD;
    }
    return ans;
}
long long Inv;
int N;
int rev[MAXN];
void FFt(long long *a, int op)
{
    long long w, wn, t;
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;lt; rev[i])
            swap(a[i], a[rev[i]]);
    for (int k = 2; k &amp;lt;= N; k &amp;lt;&amp;lt;= 1)
    {
        wn = pow_mod(3, op == 1 ? (MOD - 1) / k : MOD - 1 - (MOD - 1) / k);
        for (int j = 0; j &amp;lt; N; j += k)
        {
            w = 1;
            for (int i = 0; i &amp;lt; (k &amp;gt;&amp;gt; 1); i++, w = w * wn % MOD)
            {
                t = a[i + j + (k &amp;gt;&amp;gt; 1)] * w % MOD;
                a[i + j + (k &amp;gt;&amp;gt; 1)] = (a[i + j] - t + MOD) % MOD;
                a[i + j] = (a[i + j] + t) % MOD;
            }
        }
    }
    if (op == -1)
        for (int i = 0; i &amp;lt; N; i++)
            a[i] = a[i] * Inv % MOD;
}
long long tmp[MAXN];
void Get_Inv(int dep, long long *a, long long *b)
{
    if (dep == 1)
        return b[0] = pow_mod(a[0], MOD - 2), void();
    Get_Inv((dep + 1) &amp;gt;&amp;gt; 1, a, b);
    N = 1;
    while (N &amp;lt; (dep &amp;lt;&amp;lt; 1))
        N &amp;lt;&amp;lt;= 1;
    Inv = pow_mod(N, MOD - 2);
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    copy(a, a + dep, tmp);
    fill(tmp + dep, tmp + N, 0);
    FFt(tmp, 1);
    FFt(b, 1);
    for (int i = 0; i &amp;lt; N; i++)
        b[i] = b[i] * ((2 - b[i] * tmp[i] % MOD + MOD) % MOD) % MOD;
    FFt(b, -1);
    fill(b + dep, b + N, 0);
}
long long F_Inv[MAXN];
long long F[MAXN];
long long C[MAXN], G[MAXN], G_Inv[MAXN];
int main()
{
    int n = read();
    F[0] = 1;
    for (int i = 1; i &amp;lt;= n; i++)
        F[i] = F[i - 1] * i % MOD;
    F_Inv[n] = pow_mod(F[n], MOD - 2);
    for (int i = n - 1; i &amp;gt;= 0; i--) F_Inv[i] = F_Inv[i + 1] * (i + 1) % MOD;
    for (int i = 0; i &amp;lt;= n; i++)
        G[i] = (i &amp;lt; 2) ? (1) : pow_mod(2, 1ll * i * (i - 1) / 2 % (MOD - 1)) * F_Inv[i] % MOD;
    for (int i = 0; i &amp;lt;= n; i++) C[i] = i * G[i] % MOD;
    Get_Inv(n + 1, G, G_Inv);
    N = 1;
    while (N &amp;lt;= n &amp;lt;&amp;lt; 1)
        N &amp;lt;&amp;lt;= 1;
    Inv = pow_mod(N, MOD - 2);
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    FFt(G_Inv, 1), FFt(C, 1);
    for (int i = 0; i &amp;lt; N; i++) C[i] = C[i] * G_Inv[i] % MOD;
    FFt(C, -1);
    printf (&quot;%d\n&quot;, C[n] * F[n - 1] % MOD);
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ3771: Triple</title><link>https://www.nekomio.com/posts/128/</link><guid isPermaLink="true">https://www.nekomio.com/posts/128/</guid><pubDate>Mon, 26 Feb 2018 07:32:23 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;我们讲一个悲伤的故事。
从前有一个贫穷的樵夫在河边砍柴。
这时候河里出现了一个水神，夺过了他的斧头，说：
“这把斧头，是不是你的？”
樵夫一看：“是啊是啊！”
水神把斧头扔在一边，又拿起一个东西问：
“这把斧头，是不是你的？”
樵夫看不清楚，但又怕真的是自己的斧头，只好又答：“是啊是啊！”
水神又把手上的东西扔在一边，拿起第三个东西问：
“这把斧头，是不是你的？”
樵夫还是看不清楚，但是他觉得再这样下去他就没法砍柴了。
于是他又一次答：“是啊是啊！真的是！”
水神看着他，哈哈大笑道：
“你看看你现在的样子，真是丑陋！”
之后就消失了。
樵夫觉得很坑爹，他今天不仅没有砍到柴，还丢了一把斧头给那个水神。
于是他准备回家换一把斧头。
回家之后他才发现真正坑爹的事情才刚开始。
水神拿着的的确是他的斧头。
但是不一定是他拿出去的那把，还有可能是水神不知道怎么偷偷从他家里拿走的。
换句话说，水神可能拿走了他的一把，两把或者三把斧头。
樵夫觉得今天真是倒霉透了，但不管怎么样日子还得过。
他想统计他的损失。
樵夫的每一把斧头都有一个价值，不同斧头的价值不同。总损失就是丢掉的斧头价值和。
他想对于每个可能的总损失，计算有几种可能的方案。
注意：如果水神拿走了两把斧头a和b，(a,b)和(b,a)视为一种方案。拿走三把斧头时，(a,b,c),(b,c,a),(c,a,b),(c,b,a),(b,a,c),(a,c,b)视为一种方案。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行是整数N，表示有N把斧头。
接下来n行升序输入N个数字Ai，表示每把斧头的价值。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;若干行，按升序对于所有可能的总损失输出一行x y，x为损失值，y为方案数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;4
4
5
6
7
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;4 1
5 1
6 1
7 1
9 1
10 1
11 2
12 1
13 1
15 1
16 1
17 1
18 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;样例解释&lt;/h3&gt;
&lt;p&gt;11
有两种方案是4+7和5+6，其他损失值都有唯一方案，例如4=4,5=5,10=4+6,18=5+6+7.&lt;/p&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;所有数据满足：Ai&amp;lt;=40000&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;一把，两把或者三把&lt;/p&gt;
&lt;p&gt;首先写出生成函数$F(x) = x^{a_1}+x^{a_2}+x^{a_3}+...+x^{a_n}$&lt;br /&gt;
两把就是$F^2(x)$减去$B(x)=x^{2a_1}+x^{2a_2}+x^{2a_3}+...+x^{2a_n}$&lt;br /&gt;
三把就是$F^3(x)$减去$3*F(x)*B(x)$加上$C(x)=x^{3a_1}+x^{3a_2}+x^{3a_3}+...+x^{3a_n}$
FFT优化乘法&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const double pi = acos(-1.);
struct Complex
{
    double x, y;
    Complex() { x = y = 0; }
    Complex(double a, double b) : x(a), y(b) {}
    Complex operator+(const Complex &amp;amp;a) { return Complex(x + a.x, y + a.y); }
    Complex operator-(const Complex &amp;amp;a) { return Complex(x - a.x, y - a.y); }
    Complex operator*(const Complex &amp;amp;a) { return Complex(x * a.x - y * a.y, x * a.y + y * a.x); }
    Complex operator*(const double a) { return Complex(x * a, y * a); }
    Complex Get() { return Complex(x, -y); }
};
double Inv;
const int MAXN = 5e5 + 5;
int N;
int rev[MAXN];
void FFt(Complex *a, int op)
{
    Complex wn, w, t;
    for (int i = 0; i &amp;lt; N; i++)
        if (i &amp;lt; rev[i])
            swap(a[i], a[rev[i]]);
    for (int k = 2; k &amp;lt;= N; k &amp;lt;&amp;lt;= 1)
    {
        wn = Complex(cos(pi / (k &amp;gt;&amp;gt; 1)), op * sin(pi / (k &amp;gt;&amp;gt; 1)));
        for (int j = 0; j &amp;lt; N; j += k)
        {
            w = Complex(1, 0);
            for (int i = 0; i &amp;lt; (k &amp;gt;&amp;gt; 1); i++, w = w * wn)
            {
                t = a[i + j + (k &amp;gt;&amp;gt; 1)] * w;
                a[i + j + (k &amp;gt;&amp;gt; 1)] = a[i + j] - t;
                a[i + j] = a[i + j] + t;
            }
        }
    }
    if (op == -1)
        for (int i = 0; i &amp;lt; N; i++)
            a[i] = a[i] * Inv;
}
Complex A[MAXN], B[MAXN], C[MAXN];
Complex tmp[MAXN];
long long ans[MAXN];
int m = 0;
int main()
{
    int n = read();
    for (int i = 1; i &amp;lt;= n; i++)
    {
        int x = read();
        ans[x]++;
        A[x].x = 1;
        B[2 * x].x = 1;
        C[3 * x].x = 1;
        m = max(m, 3 * x);
    }
    m = m + m + 1;
    N = 1;
    while (N &amp;lt; m) 
        N &amp;lt;&amp;lt;= 1;
    for (int i = 1; i &amp;lt; N; i++) 
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    Inv = 1. / N;
    FFt(A, 1);
    for (int i = 0; i &amp;lt; N; i++) tmp[i] = A[i] * A[i];
    FFt(tmp, -1);
    for (int i = 0; i &amp;lt; N; i++) ans[i] += round((tmp[i].x - B[i].x) / 2);
    // for (int i = 0; i &amp;lt; N; i++)
    //     if (ans[i])
    //         printf (&quot;%d %lld\n&quot;, i, ans[i]);
    // printf (&quot;======================================\n&quot;);
    FFt(B, 1);
    for (int i = 0; i &amp;lt; N; i++) B[i] = B[i] * A[i];
    FFt(B, -1);
    for (int i = 0; i &amp;lt; N; i++) tmp[i] = A[i] * A[i] * A[i];
    FFt(tmp, -1);
    for (int i = 0; i &amp;lt; N; i++) ans[i] += round((tmp[i].x - B[i].x * 3 + C[i].x * 2) / 6);
    for (int i = 0; i &amp;lt;= m / 2; i++)
        if (ans[i])
            printf (&quot;%d %lld\n&quot;, i, ans[i]);
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ3509: [CodeChef] COUNTARI</title><link>https://www.nekomio.com/posts/127/</link><guid isPermaLink="true">https://www.nekomio.com/posts/127/</guid><pubDate>Mon, 26 Feb 2018 06:28:02 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;给定一个长度为N的数组A[]，求有多少对i, j, k（1&amp;lt;=i&amp;lt;j&amp;lt;k&amp;lt;=N）满足A[k]-A[j]=A[j]-A[i]。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行一个整数N（N&amp;lt;=10^5）。
接下来一行N个数A[i]（A[i]&amp;lt;=30000）。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;一行一个整数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;10
3 5 3 6 3 4 10 4 5 2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分块FFT&lt;br /&gt;
先分块， 暴力求出有三个在同一块，和两个在同一块的答案&lt;br /&gt;
三个都不在一块的FFT&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cmath&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 1e6;
const int MOD = 998244353;
long long pow_mod(long long a, long long b, long long P)
{
    long long ans = 1;
    while (b)
    {
        if (b &amp;amp; 1) ans = ans * a % P;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % P;
    }
    return ans;
}
long long Inv, N;
int rev[MAXN];
void FFt(long long *a, int op)
{
    long long wn, w, t;
    for (int i = 0; i &amp;lt; N; i++)
        if (i &amp;lt; rev[i])
            swap(a[i], a[rev[i]]);
    for (int k = 2; k &amp;lt;= N; k &amp;lt;&amp;lt;= 1)
    {
        wn = pow_mod(3, op == 1 ? (MOD - 1) / k : MOD - 1 - (MOD - 1) / k, MOD);
        for (int j = 0; j &amp;lt; N; j += k)
        {
            w = 1;
            for (int i = 0; i &amp;lt; (k &amp;gt;&amp;gt; 1); i++, w = w * wn % MOD)
            {
                t = a[i + j + (k &amp;gt;&amp;gt; 1)] * w % MOD;
                a[i + j + (k &amp;gt;&amp;gt; 1)] = (a[i + j] - t + MOD) % MOD;
                a[i + j] = (a[i + j] + t) % MOD;
            }
        }
    }
    if (op == -1)
        for (int i = 0; i &amp;lt; N; i++)
            a[i] = a[i] * Inv % MOD;
}
int Sum1[MAXN], Sum2[MAXN];
int W[MAXN];
int l[MAXN], r[MAXN];
long long A[65537], B[65537];
int main()
{
    int n = read();
    for (int i = 0; i &amp;lt; n; i++)
        W[i] = read();
    int len = min((int)sqrt(n) * 6, n);
    int num = n / len;
    if (n % len) num++;
    long long ans = 0;
    for (int i = 1; i &amp;lt;= num; i++)
    {
        l[i] = (i - 1) * len;
        r[i] = min(l[i] + len - 1, n - 1);
    }
    for (int i = 1; i &amp;lt;= num; i++)
    {
        for (int j = l[i]; j &amp;lt;= r[i]; j++)
        {
            for (int k = j + 1; k &amp;lt;= r[i]; k++) 
                if (2 * W[j] - W[k] &amp;gt;= 0)
                    ans += Sum1[2 * W[j] - W[k]];
            Sum1[W[j]]++;
        }
    }
    for (int i = num; i &amp;gt;= 1; i--)
    {
        for (int j = l[i]; j &amp;lt;= r[i]; j++)
        {
            for (int k = j + 1; k &amp;lt;= r[i]; k++)
                if (2 * W[k] - W[j] &amp;gt;= 0)
                    ans += Sum2[2 * W[k] - W[j]];
        }
        for (int j = l[i]; j &amp;lt;= r[i]; j++)
            Sum2[W[j]]++;
    }
    N = 65536;
    Inv = pow_mod(N, MOD - 2, MOD);
    for (int i = 1; i &amp;lt; N; i++)
        if (i &amp;amp; 1) 
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    for (int i = 2; i &amp;lt; num; i++)
    {
        memset (A, 0, sizeof (A));
        memset (B, 0, sizeof (B));
        for (int j = 0; j &amp;lt; l[i]; j++) A[W[j]]++;
        for (int j = r[i] + 1; j &amp;lt; n; j++) B[W[j]]++;
        FFt(A, 1), FFt(B, 1);
        for (int j = 0; j &amp;lt; N; j++) A[j] = A[j] * B[j];
        FFt(A, -1);
        for (int j = l[i]; j &amp;lt;= r[i]; j++) ans += A[2 * W[j]];
    }
    printf (&quot;%lld\n&quot;, ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ3527: [ZJOI2014] 力</title><link>https://www.nekomio.com/posts/126/</link><guid isPermaLink="true">https://www.nekomio.com/posts/126/</guid><pubDate>Sun, 25 Feb 2018 21:16:40 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;给出n个数qi，给出Fj的定义如下：
&lt;img src=&quot;https://i.loli.net/2018/02/25/5a92b7c5d85cd.jpg&quot; alt=&quot;11.jpg&quot; /&gt;&lt;br /&gt;
令Ei=Fi/qi，求Ei.&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行一个整数n。&lt;br /&gt;
接下来n行每行输入一个数，第i行表示qi。&lt;br /&gt;
n≤100000，0&amp;lt;qi&amp;lt;1000000000&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;n行，第i行输出Ei。与标准答案误差不超过1e-2即可。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;5
4006373.885184
15375036.435759
1717456.469144
8514941.004912
1410681.345880
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;-16838672.693
3439.793
7509018.566
4595686.886
10903040.872
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;写写题解证明自己还活着&lt;/p&gt;
&lt;p&gt;这道题是一道比较基础的题目&lt;/p&gt;
&lt;p&gt;先把Ei写出来得&lt;/p&gt;
&lt;p&gt;$$ E_i = \sum_{i&amp;lt;j} {\frac{p_i}{(i - j) ^ 2}} - \sum_{i&amp;gt;j}{\frac{qi}{(i - j)^2}}$$&lt;/p&gt;
&lt;p&gt;令 $f(i) = q_i,\ g(i) = \frac{1}{i^2}$&lt;/p&gt;
&lt;p&gt;$$E_j=\sum_{i=1}^{j-1}f(i) \times g(j-i)-\sum_{i=j+1}^nf(i) \times g(j-i)$$&lt;/p&gt;
&lt;p&gt;前一部分直接FFT算。&lt;/p&gt;
&lt;p&gt;后一部分$\sum_{i=j+1}^nf(i) \times g(j-i)=\sum_{i=1}^{n-j}f(i+j) \times g(i)$&lt;/p&gt;
&lt;p&gt;令 $f&apos;(n-i-j)=f(i+j)$ ，则第二部分变为 $\sum_{i=0}^{n-j-1}f&apos;(n-i-j-1) \times g(i)$，转化为卷积的形式用FFT解即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
#include &amp;lt;complex&amp;gt;
using namespace std;
#define Complex complex&amp;lt;double&amp;gt;
const double pi = acos(-1.);
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 100005 * 8;
int rev[MAXN]; 
double Inv;
int N;
void FFt(Complex *a, int op)
{
    Complex t, w;
    for (int i = 0; i &amp;lt; N; i++)
        if (i &amp;gt; rev[i]) swap(a[i], a[rev[i]]);
    for (int k = 2; k &amp;lt;= N; k &amp;lt;&amp;lt;= 1)
    {
        Complex wn(cos(pi / (k &amp;gt;&amp;gt; 1)), op * sin(pi / (k &amp;gt;&amp;gt; 1)));
        for (int j = 0; j &amp;lt; N; j += k)
        {
            w = Complex(1, 0);
            for (int i = 0; i &amp;lt; (k &amp;gt;&amp;gt; 1); i++, w = w * wn)
            {
                t = a[i + j + (k &amp;gt;&amp;gt; 1)] * w;
                a[i + j + (k &amp;gt;&amp;gt; 1)] = a[i + j] - t;
                a[i + j] = a[i + j] + t;
            }
        }
    }
    if (op == -1)
        for (int i = 0; i &amp;lt; N; i++)
            a[i] *= Inv;
}
Complex a[MAXN], b[MAXN], g[MAXN];
int main()
{
    int n = read();
    n--;
    for (int i = 0; i &amp;lt;= n; i++)
    {
        double x;
        scanf (&quot;%lf&quot;, &amp;amp;x);
        b[n - i] = a[i] = x;
    }
    for (int i = 1; i &amp;lt;= n; i++) g[i] = (1. / i / i);
    int m = n + n + 1;
    N = 1;
    while (N &amp;lt; m)
        N &amp;lt;&amp;lt;= 1;
    Inv = 1. / N;
    for (int i = 0; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    FFt(a, 1), FFt(b, 1), FFt(g, 1);
    for (int i = 0; i &amp;lt; N; i++) a[i] = a[i] * g[i];
    for (int i = 0; i &amp;lt; N; i++) b[i] = b[i] * g[i];
    FFt(a, -1), FFt(b, -1);
    for (int i = 0; i &amp;lt;= n; i++)
        printf (&quot;%.3f\n&quot;, a[i].real() - b[n - i].real());
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ2688: Green Hackenbush</title><link>https://www.nekomio.com/posts/125/</link><guid isPermaLink="true">https://www.nekomio.com/posts/125/</guid><pubDate>Thu, 18 Jan 2018 20:57:55 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;有一个古老的游戏叫做Green Hackenbush，游戏是这样进行的：两个人轮流在一棵树上删边，每次删边后不与根联通的子树直接被ignore，不能删边的游戏者输。Alice和Bob也在玩这个游戏，不过他们面对的是n棵树，第i棵树是含有a[i]个节点的二叉树。先手的Alice想知道自己有多大的概率获胜(假设我们的Alice和Bob同学都是无限聪明的)。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行一个数n。
接下来每行一个数a[i]。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;一个保留6位小数的实数ans。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;1
2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;1.000000
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;对于100%的数据，n&amp;lt;=100，a[i]&amp;lt;=100&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;首先我们考虑正常的Green Hackenbush游戏&lt;/p&gt;
&lt;h4&gt;Step1:&lt;/h4&gt;
&lt;p&gt;让我们先从最简单的开始&lt;br /&gt;
假设树退化为一条链&lt;br /&gt;
那么我们会发现这好像就是一个Nim游戏&lt;br /&gt;
那么我们可以通过异或来解决这个问题&lt;/p&gt;
&lt;h4&gt;Step2:&lt;/h4&gt;
&lt;p&gt;再让我们考虑一颗树&lt;br /&gt;
那么根据Colon Principle原理&lt;br /&gt;
一个点的SG函数值为它的所有的子树的SG+1的异或和&lt;br /&gt;
举个例子
从网上找的一张图&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2018/01/18/5a609c4e07868.jpg&quot; alt=&quot;1344074319_7883.jpg&quot; /&gt;&lt;br /&gt;
大家可以自己算一下&lt;/p&gt;
&lt;h5&gt;感性证明&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;首先不考虑这个点以下的部分(我们一会再去管他) ， 在这个点以上的部分先不考虑链接这个点的那些边。&lt;br /&gt;
那么他上面可以看做是几个子游戏。 我们可以递归的计算他们是SG值&lt;br /&gt;
把他们等效成一条链， 然后加上链接这个点的那些边， 及SG+1&lt;br /&gt;
根据Nim 的结论， 我们可以将他们异或起来。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;现在让我们考虑下面的部分&lt;br /&gt;
假设一个任意固定的图G，一个任意节点x，让H1和H2为任意的树，且拥有相同的SG值。考虑这样两个图G1=Gx:H1和G2=Gx:H2，Gx：Hi表示该图是把树Hi连接图的x节点。&lt;br /&gt;
则我们需要证明G1与G2的SG值相等&lt;br /&gt;
G1、G2拥有相同的SG值意味着两个游戏的总SG值为0，G1+G2的和是一个P局面，也就是必败&lt;br /&gt;
先手一旦在其中一幅图中取走任意一条边，后手即可在另一幅图中取走相对应的一条边。轮流下去，最后肯定是后手获胜。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然后我们搞定了正常的Green Hackenbush游戏&lt;/p&gt;
&lt;p&gt;现在让我们来看这道题&lt;br /&gt;
对应$x$个点去建一颗二叉树有多少种方法?&lt;br /&gt;
分别考虑左右子树&lt;br /&gt;
我们有&lt;br /&gt;
$$h[x] = \sum_{i = 0}^{n - 1}{h[i] * h[n - i - 1]}$$&lt;br /&gt;
这好像就是卡特兰数。&lt;br /&gt;
然后我们设$g[i][j]$为有$i$个点的树SG值为$j$的概率&lt;/p&gt;
&lt;p&gt;得DP方程为&lt;/p&gt;
&lt;p&gt;$$g[n][(x + 1) ^ (y + 1)] = \sum_{i = 0}^{n - 1}{ h[i] * g[i][x] * h[n - 1 - i] * g[n - 1 - i][y]}$$&lt;/p&gt;
&lt;p&gt;f[i][j]表示的是前i颗子树异或值为j的概率&lt;/p&gt;
&lt;p&gt;$$f[i][j ^ k]=f[i-1][j] * g[a[i]][k]$$&lt;/p&gt;
&lt;p&gt;搞定
$ans = 1-f[n][0]$&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while(ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
int a[105];
double h[150];
double g[350][350], f[350][350];
int main()
{
    int n = read(), m = 0;
    for (int i = 1; i &amp;lt;= n; i++)
        a[i] = read(), m = max(m, a[i]);
    h[0] = 1;
    for (int i = 1; i &amp;lt;= m; i++)
        h[i] = h[i - 1] * (4 * i - 2) / (i + 1);
    g[1][0] = 1;
    for (int i = 2; i &amp;lt;= m; i++)
    {
        for (int j = 0; j &amp;lt;= 127; j++) g[i][j + 1] += h[i - 1] * 2 * g[i - 1][j];
        for (int j = 1; j &amp;lt; i - 1; j++)
        {
            int k = i - j - 1;
            for (int x = 0; x &amp;lt;= 127; x++)
                for (int y = 0; y &amp;lt;= 127; y++)
                    g[i][(x + 1) ^ (y + 1)] += h[j] * g[j][x] * h[k] * g[k][y];
        }
        for (int j = 0; j &amp;lt;= n - 1; j++) g[i][j] /= h[i];
    }
    for (int i = 0; i &amp;lt;= 127; i++) f[1][i] = g[a[1]][i];
    for (int i = 2; i &amp;lt;= n; i++)
        for (int j = 0; j &amp;lt;= 127; j++)
            for (int k = 0; k &amp;lt;= 127; k++)
                f[i][j ^ k] += f[i - 1][j] * g[a[i]][k];
    printf (&quot;%.6f\n&quot;, 1.0 - f[n][0]);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ2017 [Usaco2009 Nov] 硬币游戏</title><link>https://www.nekomio.com/posts/124/</link><guid isPermaLink="true">https://www.nekomio.com/posts/124/</guid><pubDate>Thu, 18 Jan 2018 20:44:36 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;农夫约翰的奶牛喜欢玩硬币游戏，因此他发明了一种称为“Xoinc”的两人硬币游戏。 初始时，一个有N(5 &amp;lt;= N &amp;lt;= 2,000)枚硬币的堆栈放在地上，从堆顶数起的第I枚硬币的币值为$C_i$ (1 &amp;lt;= $C_i$ &amp;lt;= 100,000)。 开始玩游戏时，第一个玩家可以从堆顶拿走一枚或两枚硬币。如果第一个玩家只拿走堆顶的一枚硬币，那么第二个玩家可以拿走随后的一枚或两枚硬币。如果第一个玩家拿走两枚硬币，则第二个玩家可以拿走1，2，3，或4枚硬币。在每一轮中，当前的玩家至少拿走一枚硬币，至多拿走对手上一次所拿硬币数量的两倍。当没有硬币可拿时，游戏结束。 两个玩家都希望拿到最多钱数的硬币。请问，当游戏结束时，第一个玩家最多能拿多少钱呢？&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第1行：1个整数N&lt;/p&gt;
&lt;p&gt;第2..N+1行：第i+1行包含1个整数$C_i$&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;第1行：1个整数表示第1个玩家能拿走的最大钱数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;5
1
3
1
7
2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;9
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;样例说明：第1个玩家先取走第1枚，第2个玩家取第2枚；第1个取走第3，4两枚，第2个玩家取走最后1枚。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;DP&lt;/p&gt;
&lt;p&gt;设f[i][j]为还剩i个硬币这一次最多能取j个的最大价值&lt;br /&gt;
a[i]为硬币价值的后缀和&lt;br /&gt;
为了方便逆序读入&lt;br /&gt;
然后$f[i][j] = max(f[i][j - 1], a[i] - f[i - j][min(i - j, 2 * j)])$&lt;br /&gt;
搞定&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while(ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
int a[2005];
int f[2005][2005];
int main()
{
    int n = read();
    for (int i = n; i &amp;gt;= 1; i--) a[i] = read();
    for (int i = 1; i &amp;lt;= n; i++) a[i] += a[i - 1];
    for (int i = 1; i &amp;lt;= n; i++)
        for (int j = 1; j &amp;lt;= i; j++)
            f[i][j] = max(f[i][j - 1], a[i] - f[i - j][min(i - j, j * 2)]);
    printf (&quot;%d\n&quot;, f[n][2]);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ1095 [ZJOI2007] Hide 捉迷藏</title><link>https://www.nekomio.com/posts/123/</link><guid isPermaLink="true">https://www.nekomio.com/posts/123/</guid><pubDate>Tue, 16 Jan 2018 08:24:12 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;捉迷藏 Jiajia和Wind是一对恩爱的夫妻，并且他们有很多孩子。某天，Jiajia、Wind和孩子们决定在家里玩
捉迷藏游戏。他们的家很大且构造很奇特，由N个屋子和N-1条双向走廊组成，这N-1条走廊的分布使得任意两个屋
子都互相可达。游戏是这样进行的，孩子们负责躲藏，Jiajia负责找，而Wind负责操纵这N个屋子的灯。在起初的
时候，所有的灯都没有被打开。每一次，孩子们只会躲藏在没有开灯的房间中，但是为了增加刺激性，孩子们会要
求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性，Jiajia希望知道可能的最远的两
个孩子的距离（即最远的两个关灯房间的距离）。 我们将以如下形式定义每一种操作： C(hange) i 改变第i个房
间的照明状态，若原来打开，则关闭；若原来关闭，则打开。 G(ame) 开始一次游戏，查询最远的两个关灯房间的
距离。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行包含一个整数N，表示房间的个数，房间将被编号为1,2,3…N的整数。接下来N-1行每行两个整数a, b，
表示房间a与房间b之间有一条走廊相连。接下来一行包含一个整数Q，表示操作次数。接着Q行，每行一个操作，如
上文所示。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;对于每一个操作Game，输出一个非负整数到hide.out，表示最远的两个关灯房间的距离。若只有一个房间是关
着灯的，输出0；若所有房间的灯都开着，输出-1。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;8
1 2
2 3
3 4
3 5
3 6
6 7
6 8
7
G
C 1
G
C 2
G
C 1
G
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;4
3
3
4
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;对于100%的数据， N ≤100000, M ≤500000。&lt;/p&gt;
&lt;p&gt;动态点分治&lt;br /&gt;
将每次点分治中的重心建树&lt;br /&gt;
在每个点维护值&lt;br /&gt;
本题维护两个堆&lt;br /&gt;
C[i] 维护子树中的黑点到起分治父亲的Dis&lt;br /&gt;
B[i] 维护子树中C[i]的堆顶&lt;/p&gt;
&lt;p&gt;ans 维护答案&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#pragma GCC optimize(&quot;O3&quot;)
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include&amp;lt;ext/pb_ds/priority_queue.hpp&amp;gt;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;0&apos;)f=-1;ch=getchar();}
    while(ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
const int MAXN = 100005;
struct Priority_queue
{
    __gnu_pbds::priority_queue&amp;lt;int, less&amp;lt;int&amp;gt;, __gnu_pbds::binary_heap_tag&amp;gt; Q1, Q2;
    inline int size()
    {
        return Q1.size() - Q2.size();
    }
    inline void push(const int &amp;amp;x)
    {
        Q1.push(x);
    }
    inline void erase(const int &amp;amp;x)
    {
        Q2.push(x);
    }
    inline int top()
    {
        while (!Q2.empty() &amp;amp;&amp;amp; Q1.top() == Q2.top())
        {
            Q1.pop();
            Q2.pop();
        }
        if (!Q1.empty()) return Q1.top();
        else return 0;
    }
    inline int top2()
    {
        if (size() &amp;lt; 2) return 0;
        while (!Q2.empty() &amp;amp;&amp;amp; Q1.top() == Q2.top())
        {
            Q1.pop();
            Q2.pop();
        }
        int tmp = Q1.top(); Q1.pop();
        while (!Q2.empty() &amp;amp;&amp;amp; Q1.top() == Q2.top())
        {
            Q1.pop();
            Q2.pop();
        }
        int ans = Q1.top(); Q1.push(tmp);
        return ans;
    }
}B[MAXN], C[MAXN], ans;
struct edge
{
    int END, next;
}v[MAXN &amp;lt;&amp;lt; 1];
int first[MAXN], p;
inline void add(int a, int b)
{
    v[p].END = b;
    v[p].next = first[a];
    first[a] = p++;
}
int f[MAXN][18];
int dep[MAXN];
inline void PreDFS(int rt, int fa)
{
    dep[rt] = dep[fa] + 1;
    f[rt][0] = fa;
    for (int i = 1; i &amp;lt;= 17; i++) f[rt][i] = f[f[rt][i - 1]][i - 1];
    for (int i = first[rt]; i != -1; i = v[i].next)
    {
        if (v[i].END == fa) continue;
        PreDFS(v[i].END, rt);
    }
}
int sum, Max[MAXN], size[MAXN], root;
bool vis[MAXN];
static inline void GetRoot(int rt, int fa)
{
    size[rt] = 1; Max[rt] = 0;
    for (int i = first[rt]; i != -1; i = v[i].next)
    {
        if (vis[v[i].END] || v[i].END == fa) continue;
        GetRoot(v[i].END, rt);
        size[rt] += size[v[i].END];
        Max[rt] = max(Max[rt], size[v[i].END]);
    }
    Max[rt] = max(Max[rt], sum - size[rt]);
    if (Max[rt] &amp;lt; Max[root]) root = rt;
}
int Fa[MAXN];
static inline void Divide(int rt, int fa)
{
    vis[rt] = 1;
    Fa[rt] = fa;
    // cerr &amp;lt;&amp;lt; rt &amp;lt;&amp;lt; endl;
    for (int i = first[rt]; i != -1; i = v[i].next)
    {
        if (vis[v[i].END]) continue;
        sum = size[v[i].END], root = 0;
        GetRoot(v[i].END, 0);
        Divide(root, rt);
    }
}
static inline int LCA(int a, int b)
{
    if (dep[a] &amp;lt; dep[b]) swap(a, b);
    int d = dep[a] - dep[b];
    for (int i = 17; i &amp;gt;= 0; i--)
        if (d &amp;amp; (1 &amp;lt;&amp;lt; i))
            d -= (1 &amp;lt;&amp;lt; i), a = f[a][i];
    if (a == b) return a;
    for (int i = 17; i &amp;gt;= 0; i--)
        if (f[a][i] != f[b][i])
            a = f[a][i], b = f[b][i];
    return f[a][0];
}
static inline int dis(const int &amp;amp;a, const int &amp;amp;b)
{
    return dep[a] + dep[b] - 2 * dep[LCA(a, b)];
}
int Color[MAXN];
static inline void Change_To_Black(const int &amp;amp;Height_root, const int &amp;amp;Child)
{
    if (Height_root == Child)
    {
        B[Height_root].push(0);
        if (B[Height_root].size() == 2)
            ans.push(B[Height_root].top());
    }
    if (!Fa[Height_root]) return;
    int Father = Fa[Height_root];
    int Dis = dis(Father, Child);
    int tmp = C[Height_root].top();
    C[Height_root].push(Dis);
    if (Dis &amp;gt; tmp)
    {
        int size = B[Father].size();
        int tmp2 = B[Father].top() + B[Father].top2();
        if (tmp)
            B[Father].erase(tmp);
        B[Father].push(Dis);
        int now = B[Father].top() + B[Father].top2();
        if (now &amp;gt; tmp2)
        {
            if (size &amp;gt;= 2) ans.erase(tmp2);
            if (B[Father].size() &amp;gt;= 2)
                ans.push(now);
        }
    }
    Change_To_Black(Father, Child);
}
static inline void Change_To_White(const int &amp;amp;Height_root, const int &amp;amp;Child)
{
    if (Height_root == Child)
    {
        if (B[Height_root].size() == 2)
            ans.erase(B[Height_root].top());
        B[Height_root].erase(0);
    }
    if (!Fa[Height_root]) return;
    int Father = Fa[Height_root];
    int Dis = dis(Father, Child);
    int tmp = C[Height_root].top();
    C[Height_root].erase(Dis);
    if (tmp == Dis)
    {
        int size = B[Father].size();
        int tmp2 = B[Father].top() + B[Father].top2();
        B[Father].erase(Dis);
        if (C[Height_root].top())
            B[Father].push(C[Height_root].top());
        int now = B[Father].top() + B[Father].top2();
        if (now &amp;lt; tmp2)
        {
            if (size &amp;gt;= 2)
                ans.erase(tmp2);
            if (B[Father].size() &amp;gt;= 2)
                ans.push(now);
        }
    }
    Change_To_White(Father, Child);
}
int main()
{
    memset (first, -1, sizeof (first));
    int n = read();
    for (int i = 1; i &amp;lt; n; i++)
    {
        int a = read(), b = read();
        add(a, b);
        add(b, a);
        // cerr &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;
    }
    PreDFS(1, 0);
    
    Max[0] = sum = n;
    GetRoot(1, 0);
    
    Divide(root, 0);
    // cerr &amp;lt;&amp;lt; &quot;11!!&quot; &amp;lt;&amp;lt; endl;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        Color[i] = 1;
        // cerr &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;
        C[i].push(0);
        // Change_To_Black(i, i);
    }
    for (int i = 1; i &amp;lt;= n; i++)
    {
        Change_To_Black(i, i);
        // cerr &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;        
    }
    // for (int i = 1; i &amp;lt;= n; i++) cerr &amp;lt;&amp;lt; &quot;i fa is &quot; &amp;lt;&amp;lt; Fa[i] &amp;lt;&amp;lt; endl;
    int m = read();
    char s[10];
    for (int i = 1; i &amp;lt;= m; i++)
    {
        // cerr &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;
        scanf (&quot;%s&quot;, s);
        if (s[0] == &apos;C&apos;)
        {
            int k = read();
            if (Color[k])
            {
                Color[k] = 0;
                Change_To_White(k, k);
            }
            else
            {
                Color[k] = 1;
                Change_To_Black(k, k);
            }
        }
        else
            printf (&quot;%d\n&quot;, ans.top());
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>上下界网络流笔记</title><link>https://www.nekomio.com/posts/122/</link><guid isPermaLink="true">https://www.nekomio.com/posts/122/</guid><pubDate>Tue, 16 Jan 2018 07:19:34 GMT</pubDate><content:encoded>&lt;h3&gt;无源汇可行流&lt;/h3&gt;
&lt;p&gt;将上下界的网络流转化为普通网络流。&lt;/p&gt;
&lt;p&gt;建图:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;添加源点 $S$ 与汇点 $T$&lt;/li&gt;
&lt;li&gt;对于原图中的边 $a \to b$ 流量限制为$[c, d]$, 则连边 $a \to b$, 流量为 $d-c$&lt;/li&gt;
&lt;li&gt;对于原图中的每一个点 $i$ , 记 $d(i)$ 为流入这个点的所有边的下界 $-$ 流出这个点的所有边的下界
&lt;ul&gt;
&lt;li&gt;若$d(i) &amp;gt; 0$连 $S \to i$, 流量为 $d(i)$&lt;/li&gt;
&lt;li&gt;若$d(i) &amp;lt; 0$连 $i \to T$, 流量为 $-d(i)$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在新图上跑 $S \to T$ 的最大流&lt;br /&gt;
若新图满流则原图存在可行流&lt;br /&gt;
原图中边流量为新图中对应边的流量加下界。&lt;/p&gt;
&lt;h3&gt;有源汇可行流&lt;/h3&gt;
&lt;p&gt;建图:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在原图中加一条 $t \to s$ 的边流量为 $[0, INF]$&lt;/li&gt;
&lt;li&gt;用无源汇求解&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;有源汇最大流&lt;/h3&gt;
&lt;p&gt;建图 同上&lt;/p&gt;
&lt;p&gt;在新图上跑 $S \to T$ 最大流
记此时 $\sum{f(s, i)} = sum1$&lt;br /&gt;
讲 $t \to s$ 的边拆掉， 跑 $s \to t$ 的最大流&lt;br /&gt;
记此时 $\sum{f(s, i)} = sum2$&lt;br /&gt;
则答案为 $sum1+sum2$&lt;/p&gt;
&lt;h3&gt;有源汇最小流&lt;/h3&gt;
&lt;p&gt;建图方法同无源汇可行流&lt;br /&gt;
求 $S \to T$ 最大流&lt;br /&gt;
连边 $t \to s,INF$&lt;br /&gt;
求 $S \to T$ 最大流&lt;br /&gt;
答案为 $t \to s$ 的实际流量&lt;/p&gt;
&lt;h3&gt;有源汇费用流&lt;/h3&gt;
&lt;p&gt;将上下界的网络流转化为普通网络流。&lt;/p&gt;
&lt;p&gt;建图:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;添加源点 $S$ 与汇点 $T$&lt;/li&gt;
&lt;li&gt;对于原图中的边 $a \to b$ 流量限制为 $[c, d]$, 费用为 $v$ , 则连边 $a \to b$ , 流量为 $d-c$ , 费用为 $v$&lt;/li&gt;
&lt;li&gt;对于原图中的每一个点 $i$, 记 $d(i)$ 为流入这个点的所有边的下界 $-$ 流出这个点的所有边的下界
&lt;ul&gt;
&lt;li&gt;若$d(i) &amp;gt; 0$连 $S \to i$, 流量为 $d(i)$, 费用为 $0$&lt;/li&gt;
&lt;li&gt;若$d(i) &amp;lt; 0$连 $i \to T$, 流量为 $-d(i)$, 费用为 $0$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;连边 $t \to s$，流量为 $INF$，费用为 $0$&lt;/p&gt;
&lt;p&gt;跑 $S \to T$ 的最小费用最大流&lt;br /&gt;
答案为 $ans+$原图中边的下界$\times$边的费用&lt;/p&gt;
</content:encoded></item><item><title>BZOJ2716 [Violet 3]天使玩偶</title><link>https://www.nekomio.com/posts/121/</link><guid isPermaLink="true">https://www.nekomio.com/posts/121/</guid><pubDate>Thu, 14 Dec 2017 14:16:10 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/12/14/5a3217db068a2.gif&quot; alt=&quot;T3des(2).gif&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/12/14/5a3217ff16911.gif&quot; alt=&quot;T3input(2).gif&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/12/14/5a32181b4a7e4.gif&quot; alt=&quot;T3output(2).gif&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://gist.coding.net/u/WildRage/7d0ed646ecbf4c2bbba59382e1288dbe&quot;&gt;Sample Input &amp;amp; Output&lt;/a&gt;&lt;/h3&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/12/14/5a3218388c880.gif&quot; alt=&quot;T3hint(2).gif&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;KD-Tree带插入的板子。&lt;br /&gt;
应该&lt;code&gt;rebuild&lt;/code&gt;的。&lt;br /&gt;
但没&lt;code&gt;rebuild&lt;/code&gt;就过了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;

using namespace std;

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while (ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}

const int INF = 0x3f3f3f3f;
const double alpha = 0.756;
const int MAXN = 5e5 + 5;

int now;

struct Point
{
    int d[2];
    int &amp;amp;operator[](const int &amp;amp;x)
    {
        return d[x];
    }
    inline bool operator &amp;lt; (const Point &amp;amp;x) const 
    {
        return d[now] == x.d[now] ? d[now ^ 1] &amp;lt; x.d[now ^ 1] : d[now] &amp;lt; x.d[now];
    }
}a[MAXN], cur;

#define dis(_, __) (\
    int(abs(_[0] - __[0]) + abs(_[1] - __[1]))\
)

#define size(_) ((_) ? (_)-&amp;gt;s : 0)

struct Node
{
    Node *ch[2];
    Point v;
    int s, d;
    int Max[2], Min[2];
    Node(Point x)
    {
        ch[0] = ch[1] = NULL;
        v = x;
        s = 1, d = now;
        Max[0] = Min[0] = x[0];
        Max[1] = Min[1] = x[1];
    }
    Node(){;}
    inline bool operator &amp;lt; (const Node &amp;amp;x) const 
    {
        return v &amp;lt; x.v;
    }
    bool IsBad()
    {
        return ((size(ch[0]) &amp;gt; s * alpha) || (size(ch[1]) &amp;gt; s * alpha));
    }
    void Pushup(Node *x)
    {
        if (!x) return;
        for (int i = 0; i &amp;lt;= 1; i++) Min[i] = min(Min[i], x-&amp;gt;Min[i]);
        for (int i = 0; i &amp;lt;= 1; i++) Max[i] = max(Max[i], x-&amp;gt;Max[i]);
        s += x-&amp;gt;s;
    }
    int min_dis()
    {
        int ans = 0;
        ans += max(Min[0] - cur[0], 0) + max(cur[0] - Max[0], 0);
        ans += max(Min[1] - cur[1], 0) + max(cur[1] - Max[1], 0);
        return ans;
    }
}*root;

inline void Build(Node *&amp;amp;rt, int l, int r, int d = 0)
{
    if (l &amp;gt; r) return;
    int mid = l + r &amp;gt;&amp;gt; 1;
    now = d;
    nth_element(a + l, a + mid, a + r + 1);
    rt = new Node(a[mid]);
    Build(rt-&amp;gt;ch[0], l, mid - 1, d ^ 1);
    Build(rt-&amp;gt;ch[1], mid + 1, r, d ^ 1);
    rt-&amp;gt;s = 1;
    rt-&amp;gt;Pushup(rt-&amp;gt;ch[0]);
    rt-&amp;gt;Pushup(rt-&amp;gt;ch[1]);
}

Node **res;

inline void Insert(Node *&amp;amp;rt)
{
    if (rt == NULL)
    {
        rt = new Node(cur);
        res = NULL;
        return;
    }
    now = rt-&amp;gt;d;
    if (cur &amp;lt; rt-&amp;gt;v) Insert(rt-&amp;gt;ch[0]);
    else Insert(rt-&amp;gt;ch[1]);
    rt-&amp;gt;s = 1;
    rt-&amp;gt;Pushup(rt-&amp;gt;ch[0]);
    rt-&amp;gt;Pushup(rt-&amp;gt;ch[1]);
    if (rt-&amp;gt;IsBad()) res = &amp;amp;rt;
}


inline void Insert(Point x)
{
    cur = x;
    Insert(root);
}

int Min_ans;

inline void Query(Node *rt)
{
    if (!rt) return;
    // if (rt-&amp;gt;min_dis() &amp;gt; Min_ans) return;
    Min_ans = min(Min_ans, dis(rt-&amp;gt;v, cur));
    int dis_l = rt-&amp;gt;ch[0] ? rt-&amp;gt;ch[0]-&amp;gt;min_dis() : INF;
    int dis_r = rt-&amp;gt;ch[1] ? rt-&amp;gt;ch[1]-&amp;gt;min_dis() : INF;
    if (dis_l &amp;lt; dis_r)
    {
        Query(rt-&amp;gt;ch[0]);
        if (dis_r &amp;lt; Min_ans) Query(rt-&amp;gt;ch[1]);
    }
    else
    {
        Query(rt-&amp;gt;ch[1]);
        if (dis_l &amp;lt; Min_ans) Query(rt-&amp;gt;ch[0]);
    }
}

inline int Query(Point x)
{
    cur = x;
    Min_ans = INF;
    Query(root);
    return Min_ans;
}

int main()
{
    // freopen(&quot;1.in&quot;, &quot;r&quot;, stdin);
    // freopen(&quot;2.out&quot;, &quot;w&quot;, stdout);
    int n, m;
    n = read(), m = read();
    for (int i = 1; i &amp;lt;= n; i++)
        a[i][0] = read(), a[i][1] = read();
    Build(root, 1, n);
    Point x;
    while (m--)
    {
        int t = read();
        if (t == 1)
        {
            x[0] = read(), x[1] = read();
            Insert(x);
        }
        else
        {
            x[0] = read(), x[1] = read();
            printf (&quot;%d\n&quot;, Query(x));
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>NOIP 考前，考中，考后</title><link>https://www.nekomio.com/posts/120/</link><guid isPermaLink="true">https://www.nekomio.com/posts/120/</guid><pubDate>Sat, 11 Nov 2017 08:14:15 GMT</pubDate><content:encoded>&lt;hr /&gt;
&lt;p&gt;2017-11-9&lt;/p&gt;
&lt;p&gt;明天就出发了，还有不少东西没有复习，心里好虚啊。&lt;br /&gt;
觉得自己什么都不会， 不知道怎么办。&lt;br /&gt;
很压抑啊， 题也做不下去了， 下午去吃了个火锅。 放松了些。&lt;br /&gt;
但回到机房又是一种压抑的感觉。&lt;br /&gt;
好难受。&lt;br /&gt;
果然是还没有做好退役的准备啊。&lt;/p&gt;
&lt;p&gt;唉...&lt;/p&gt;
&lt;p&gt;2017-11-13&lt;/p&gt;
&lt;p&gt;考完了， 也是回到了学校。&lt;br /&gt;
先是一个假期， 然而我好象并不能回家。&lt;br /&gt;
在机房待着。&lt;br /&gt;
反正也是考完了， 考的怎样就不想管了。&lt;br /&gt;
不管能不能参加省选， 首先迎接我们的是恐怖的文化课补课。&lt;br /&gt;
以及那让人讨厌的会考。。&lt;/p&gt;
</content:encoded></item><item><title>BZOJ3925 状压DP+概率DP</title><link>https://www.nekomio.com/posts/119/</link><guid isPermaLink="true">https://www.nekomio.com/posts/119/</guid><pubDate>Mon, 30 Oct 2017 08:14:15 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;转载自 Cooook
&lt;a href=&quot;http://cooook.coding.me/2017/10/30/BZOJ3925/&quot;&gt;BZOJ3925 状压DP+概率DP&lt;/a&gt;
转载请注明原文地址&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;傲娇少女幽香是一个很萌很萌的妹子，而且她非常非常地有爱心，很喜欢为幻想乡的人们做一些自己力所能及的事情来帮助他们。 这不，幻想乡突然发生了地震，所有的道路都崩塌了。现在的首要任务是尽快让幻想乡的交通体系重新建立起来。幻想乡一共有n个地方，那么最快的方法当然是修复n-1条道路将这n个地方都连接起来。 幻想乡这n个地方本来是连通的，一共有m条边。现在这m条边由于地震的关系，全部都毁坏掉了。每条边都有一个修复它需要花费的时间，第i条边所需要的时间为ei。地震发生以后，由于幽香是一位人生经验丰富，见得多了的长者，她根据以前的经验，知道每次地震以后，每个ei会是一个0到1之间均匀分布的随机实数。并且所有ei都是完全独立的。 现在幽香要出发去帮忙修复道路了，她可以使用一个神奇的大魔法，能够选择需要的那n-1条边，同时开始修复，那么修复完成的时间就是这n-1条边的ei的最大值。当然幽香会先使用一个更加神奇的大魔法来观察出每条边ei的值，然后再选择完成时间最小的方案。 幽香在走之前，她想知道修复完成的时间的期望是多少呢？&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行两个数n,m，表示地方的数量和边的数量。其中点从1到n标号。
接下来m行，每行两个数a,b，表示点a和点b之间原来有一条边。
这个图不会有重边和自环。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;一行输出答案，四舍五入保留6位小数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;5 4
1 2
1 5
4 3
5 3
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;0.800000
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;对于n个[0,1]之间的随机变量x1,x2,...,xn，第k小的那个的期望值是k/(n+1)。&lt;/p&gt;
&lt;h3&gt;题解前的扯淡&lt;/h3&gt;
&lt;p&gt;贼NB的一道题,有两种做法,PoPoQQQ大爷的积分没看懂...于是写了概率DP&lt;br /&gt;
WQ刚了一天没刚出来,ZZH还在刚...&lt;br /&gt;
听WQ说dg说这种题刚不出来就弃了吧233333&lt;/p&gt;
&lt;h3&gt;题解&lt;/h3&gt;
&lt;p&gt;题目让求的是最小生成树最大边的期望&lt;br /&gt;
我们设最小生成树的最大边的排名为$i$&lt;br /&gt;
设$F(i)$ 为最小生成树最大边排名为$i$的贡献&lt;br /&gt;
由提示可知$F(i) = \frac{i}{m+1}$&lt;br /&gt;
设$P(i)$为最小生成树最大边排名为$i$的概率&lt;br /&gt;
则$Ans=\sum_{i=1}^{m}{\frac{i*P(i)}{m+1}}$&lt;br /&gt;
然后就可以惊喜的发现这个$P(i)$并不好求&lt;br /&gt;
考虑转化&lt;br /&gt;
设$T(i)$为最小生成树最大边排名大于等于$i$的概率&lt;br /&gt;
那么$Ans=\frac{\sum_{i=1}^{m}{T(i)}}{m+1}$&lt;br /&gt;
至于为什么&lt;br /&gt;
首先根据定义$T(i)=\sum_{j=i}^{m}{P(j)}$&lt;br /&gt;
那么每个$P(i)$被累加的次数正好是$i$次&lt;br /&gt;
所以成立&lt;br /&gt;
但$T(i)$还是不好求&lt;br /&gt;
而最小生成树最大边的排名为$i$则说明排名小于$i$的边不能使图联通&lt;br /&gt;
设$M(i)$为排名小于i的边不能使图联通的概率&lt;br /&gt;
所以$T(i)=M(i)$
所以求$\frac{\sum_{i=0}^{m}{M(i)}}{m+1}$就是答案了&lt;br /&gt;
然后怎么还是不好求...&lt;br /&gt;
不联通的不好求,联通的还不好求么&lt;br /&gt;
终于进入$DP$的环节了....&lt;br /&gt;
由于$n$的范围很小,所以我们考虑状态压缩&lt;br /&gt;
设$f_{i,j}$为点集为$i$有j条边且点之间不联通的方案数&lt;br /&gt;
设$g_{i,j}$为点集为$i$有j条边且点之间联通的方案数&lt;br /&gt;
设$cnt_i$为点集为$i$的边的数量&lt;br /&gt;
从$cnt_i$条边里选$j$条边的方案数为$C_{cnt_i}^{j}$&lt;br /&gt;
而选出来$j$条边后这个点集只有联通和不联通两种状态&lt;br /&gt;
所以$f_{i,j}+g_{i,j}=C_{cnt_i}^{j}$&lt;br /&gt;
方程的转移可以通过选取这个联通块内的一个点,然后枚举那些点和这个点联通来转移&lt;br /&gt;
即为$f_{i,j}+=g_{S,k}*C_{cnt_{i-S}}^{j-k}$&lt;br /&gt;
然后根据$f_{i,j}+g_{i,j}=C_{cnt_i}^{j}$来转移$g$&lt;br /&gt;
最后统计答案的时候$\frac{\sum_{i=0}^{m}{\frac{f_{ALL,i}}{C_m^i}}}{m+1}$&lt;br /&gt;
终于完了QWQ....&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;iostream&amp;gt;
#define int long long 
#define fi first
#define se second
#define lowbit(_) ((_)&amp;amp;(-_))
typedef std::pair&amp;lt;int,int&amp;gt; pii;
int f[1&amp;lt;&amp;lt;10][50],g[1&amp;lt;&amp;lt;10][50],n,m,full,cnt[1&amp;lt;&amp;lt;10],C[50][50];
pii a[50];


char xb[1&amp;lt;&amp;lt;15],*xs,*xt;
#define getc() (xs == xt &amp;amp;&amp;amp; (xt = (xs = xb) + fread(xb,1,1&amp;lt;&amp;lt;15,stdin),xs == xt)?0:*xs++)
inline int read() {
    int x = 0, f = 1;
    char ch = getc();
    for (; ch &amp;lt; &apos;0&apos; || ch &amp;gt; &apos;9&apos;; ch = getc()) if (ch == &apos;-&apos;) f = -f;
    for (; ch &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; ch &amp;lt;= &apos;9&apos;; ch = getc()) x = x * 10 + (ch ^ 48);
    return x * f;
}

void Pre_Work() {
    for (int i = 0; i &amp;lt;= 45; i++) {
        C[i][0] = 1;
        for (int j = 1; j &amp;lt;= i; j++) C[i][j] = C[i-1][j] + C[i-1][j-1];
    }
}

inline int Cnt_Bit(int S) {
    int cnt = 0;
    for (; S; S -= lowbit(S)) cnt ++;
    return cnt;
}

signed main() {
    Pre_Work();
    n = read(); m = read(); full = (1 &amp;lt;&amp;lt; n) - 1;
    for (int i = 1; i &amp;lt;= m; i++) a[i].fi = read(),a[i].se = read();
    for (int i = 1; i &amp;lt;= full; i++) 
        for (int j = 1; j &amp;lt;= m; j++)
            if (((1&amp;lt;&amp;lt;a[j].fi-1) &amp;amp; i) &amp;amp;&amp;amp; ((1&amp;lt;&amp;lt;a[j].se-1) &amp;amp; i)) cnt[i] ++;
    for (int i = 1; i &amp;lt;= full; i++) {
        if (Cnt_Bit(i) == 1) {
            g[i][0] = 1;
            continue;
        }
        int j = lowbit(i);
        for (int S = (i - 1) &amp;amp; i; S; S = (S - 1) &amp;amp; i)
            if (j &amp;amp; S) {
                for (int k = 0; k &amp;lt;= cnt[S]; k++)
                    for (int o = 0; o &amp;lt;= cnt[i ^ S]; o++)
                        f[i][o+k] += g[S][k] * C[cnt[i^S]][o];
            }
        for (int k = 0; k &amp;lt;= cnt[i]; k++) g[i][k] = C[cnt[i]][k] - f[i][k];
    }
    double Ans = 0.0;
    for (int i = 0; i &amp;lt;= m; i++) Ans += f[full][i] / 1.0 / C[cnt[full]][i];
    printf(&quot;%.6lf\n&quot;,Ans/(m+1));
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Codeforces 671D Roads in Yusland</title><link>https://www.nekomio.com/posts/118/</link><guid isPermaLink="true">https://www.nekomio.com/posts/118/</guid><pubDate>Sun, 29 Oct 2017 20:36:20 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;Mayor of Yusland just won the lottery and decided to spent money on something good for town. For example, repair all the roads in the town.&lt;/p&gt;
&lt;p&gt;Yusland consists of n intersections connected by n - 1 bidirectional roads. One can travel from any intersection to any other intersection using only these roads.&lt;/p&gt;
&lt;p&gt;There is only one road repairing company in town, named &quot;RC company&quot;. Company&apos;s center is located at the intersection 1. RC company doesn&apos;t repair roads you tell them. Instead, they have workers at some intersections, who can repair only some specific paths. The i-th worker can be paid ci coins and then he repairs all roads on a path from ui to some vi that lies on the path from ui to intersection 1.&lt;/p&gt;
&lt;p&gt;Mayor asks you to choose the cheapest way to hire some subset of workers in order to repair all the roads in Yusland. It&apos;s allowed that some roads will be repaired more than once.&lt;/p&gt;
&lt;p&gt;If it&apos;s impossible to repair all roads print  -1.&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;The first line of the input contains two integers n and m (1 ≤ n, m ≤ 300 000) — the number of cities in Yusland and the number of workers respectively.&lt;/p&gt;
&lt;p&gt;Then follow n−1 line, each of them contains two integers xi and yi (1 ≤ xi, yi ≤ n) — indices of intersections connected by the i-th road.&lt;/p&gt;
&lt;p&gt;Last m lines provide the description of workers, each line containing three integers ui, vi and ci (1 ≤ ui, vi ≤ n, 1 ≤ ci ≤ 109). This means that the i-th worker can repair all roads on the path from vi to ui for ci coins. It&apos;s guaranteed that vi lies on the path from ui to 1. Note that vi and ui may coincide.&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;If it&apos;s impossible to repair all roads then print  -1. Otherwise print a single integer — minimum cost required to repair all roads using &quot;RC company&quot; workers.&lt;/p&gt;
&lt;h3&gt;input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;6 5
1 2
1 3
3 4
4 5
4 6
2 1 2
3 1 4
4 1 3
5 3 1
6 3 2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;8
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;题意&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;给一颗树，给定m对祖先节点关系。 每选用一对关系需要付出c的花费， 求用这些关系将所有边都覆盖的最小花费。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本题有 $nlog(n)$ 树DP做法请看&lt;a href=&quot;http://cooook.coding.me/2017/10/29/CF671D/&quot;&gt;CF671D 树形DP+数据结构优化DP&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这里我想说一下 $nlog(n)$ 的贪心做法&lt;/p&gt;
&lt;p&gt;我们将修路转化为修点， 1 号点不用修&lt;br /&gt;
首先我们设$x_i$为第$i$个工人的使用次数。 那么显然$x_i \geq 0$&lt;br /&gt;
然设一个$A$矩阵如果第$j$个工人能覆盖到第$i$点那么$A_{i,j}=1$否则$A_{i,j}=0$&lt;br /&gt;
那么很显然对于$(\forall 2 &amp;lt;= i &amp;lt;= n)$都有$\sum_{j = 1}^{m}{A_{i,j}*x_j} &amp;gt; 0$&lt;/p&gt;
&lt;p&gt;如果将这个过程看作矩阵乘， 将x看作m行1列的矩阵&lt;br /&gt;
那么
$$\begin{bmatrix}  A_{1,1} &amp;amp; A_{1,2} &amp;amp; A_{1,3} &amp;amp; \cdots &amp;amp; A_{1,m} \    A_{2,1} &amp;amp; A_{2,2} &amp;amp; A_{2,3} &amp;amp; \cdots &amp;amp; A_{2,m} \   \vdots &amp;amp; \vdots &amp;amp; \vdots &amp;amp; \ddots &amp;amp; \vdots \    A_{n,1} &amp;amp; A_{n,2} &amp;amp; A_{n,3} &amp;amp; \cdots &amp;amp; A_{n,m} \   \end{bmatrix}
\begin{bmatrix} x_{1,1} \ x_{1,2} \ x_{1,3} \ \vdots \ x_{1,m} \ \end{bmatrix} \geq \begin{bmatrix} 1 \ 1 \ 1 \ \vdots \ 1 \ \end{bmatrix}$$&lt;/p&gt;
&lt;p&gt;我们设右边的矩阵为$e$&lt;/p&gt;
&lt;p&gt;那么我们要求的答案为
$$ min\{\sum_{j=1}^{m}c_j * x_j\} $$&lt;/p&gt;
&lt;p&gt;如果将c看作矩阵则答案为
$min\{c^Tx\}$&lt;/p&gt;
&lt;p&gt;那么我们发现他是一个线性规划问题。&lt;br /&gt;
我们可以考虑它的对偶问题。&lt;br /&gt;
由于对偶问题求得到函数值与原问题相等， 那么我们只需要求出对偶问题的答案。&lt;/p&gt;
&lt;p&gt;下面说一下对偶问题的构造&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;给每个原始约束条件定义一个非负对偶变量$y_i (i=1,2,…,m)$;&lt;/li&gt;
&lt;li&gt;使原问题的目标函数系数cj变为其对偶问题约束条件的右端常数&lt;/li&gt;
&lt;li&gt;使原问题约束条件的右端常数bi变为其对偶问题目标函数的系数；&lt;/li&gt;
&lt;li&gt;将原问题约束条件的系数矩阵转置，得到其对偶问题约束条件的系数矩阵；&lt;/li&gt;
&lt;li&gt;改变约束条件不等号的方向，即将&quot;=&amp;lt;&quot;改为&quot;&amp;gt;=&quot;；&lt;/li&gt;
&lt;li&gt;原问题“max”型，对偶问题为“min”型．反之亦然.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;那么本题的对偶问题为&lt;/p&gt;
&lt;p&gt;$y &amp;gt;= 0$
$A^Ty &amp;lt;= c$&lt;/p&gt;
&lt;p&gt;求$max{e^Ty}$&lt;br /&gt;
$e$ 是上文中设的矩阵&lt;/p&gt;
&lt;p&gt;那么用人话说就是&lt;/p&gt;
&lt;p&gt;每个点可以选多次一个工人的路径上的点的选择次数的和在$c_i$以内， 求所有点选择次数的最大和。&lt;/p&gt;
&lt;p&gt;我们可以贪心的由下向上选取。&lt;br /&gt;
用一个set启发式合并就可以了。&lt;/p&gt;
&lt;p&gt;时间复杂度$nlog(n)$ 常数略大。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// #pragma GCC optimize(&quot;O3&quot;)
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;set&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
const int MAXN = 300005;
char xch,xB[1&amp;lt;&amp;lt;15],*xS=xB,*xTT=xB;
#define getc() (xS==xTT&amp;amp;&amp;amp;(xTT=(xS=xB)+fread(xB,1,1&amp;lt;&amp;lt;15,stdin),xS==xTT)?0:*xS++)
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getc();}
    while(ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getc();}
    return x*f;
}
struct edge
{
    int END, next;
}v[MAXN &amp;lt;&amp;lt; 1];
int first[MAXN], p;
void add(int a, int b)
{
    v[p].END = b;
    v[p].next = first[a];
    first[a] = p++;
}
struct data
{
    int v, cnt;
    data(int c = 0, int cn = 0)
    {
        v = c, cnt = cn;
    }
    bool operator &amp;lt; (const data &amp;amp;a) const
    {
        return cnt == a.cnt ? v &amp;lt; a.v : cnt &amp;lt; a.cnt;
    }
};
vector&amp;lt;data&amp;gt; Add[MAXN], rm[MAXN];
set&amp;lt;data&amp;gt; st[MAXN];
long long ans;
int C[MAXN], Ad[MAXN];
bool died;
void dfs(int rt, int fa)
{
    set&amp;lt;data&amp;gt;::iterator it;
    for (int i = 0; i &amp;lt; Add[rt].size(); i++)
        st[rt].insert(Add[rt][i]);
    for (int i = first[rt]; i != -1; i = v[i].next)
    {
        if (v[i].END == fa) continue;
        dfs(v[i].END, rt);
        if (died) return;
        if (st[v[i].END].size() &amp;gt; st[rt].size())
            swap(st[v[i].END], st[rt]), swap(Ad[v[i].END], Ad[rt]);
        for (it = st[v[i].END].begin(); it != st[v[i].END].end(); it++)
            st[rt].insert(data(it-&amp;gt;v, C[it-&amp;gt;v] = it-&amp;gt;cnt - Ad[v[i].END] + Ad[rt]));
    }
    for (int i = 0; i &amp;lt; rm[rt].size(); i++)
        st[rt].erase(data(rm[rt][i].v, C[rm[rt][i].v]));
    if (rt == 1) return;
    if (st[rt].empty()) {died = 1; return;}
    ans += st[rt].begin()-&amp;gt;cnt - Ad[rt];
    Ad[rt] += st[rt].begin()-&amp;gt;cnt - Ad[rt];
}
signed main()
{
    int n = read(), m = read(), a, b, c;
    memset (first, -1, sizeof (first));
    for (int i = 1; i &amp;lt; n; i++)
    {
        a = read(), b = read();
        add(a, b);
        add(b, a);
    }
    for (int i = 1; i &amp;lt;= m; i++)
    {
        a = read(), b = read(), c = read();
        Add[a].push_back(data(i, c));
        rm[b].push_back(data(i, c));
        C[i] = c;
    }
    dfs(1, 0);
    if (died) printf (&quot;-1&quot;);
    else printf (&quot;%lld&quot;, ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 3167 [Heoi2013] Sao</title><link>https://www.nekomio.com/posts/117/</link><guid isPermaLink="true">https://www.nekomio.com/posts/117/</guid><pubDate>Sat, 28 Oct 2017 20:20:20 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;WelcometoSAO(StrangeandAbnormalOnline)。这是一个VRMMORPG，含有n个关卡。但是，挑战不同关卡的顺序是一
个很大的问题。有n–1个对于挑战关卡的限制，诸如第i个关卡必须在第j个关卡前挑战，或者完成了第k个关卡才
能挑战第l个关卡。并且，如果不考虑限制的方向性，那么在这n–1个限制的情况下，任何两个关卡都存在某种程
度的关联性。即，我们不能把所有关卡分成两个非空且不相交的子集，使得这两个子集之间没有任何限制。&lt;/p&gt;
&lt;h3&gt;输入格式&lt;/h3&gt;
&lt;p&gt;第一行，一个整数T，表示数据组数。对于每组数据，第一行一个整数n，表示关卡数。接下来n–1行，每行为“i
sign j”,其中$0≤i,j≤n–1$且$i≠j$，sign为“&amp;lt;”或者“&amp;gt;”，表示第i个关卡必须在第j个关卡前/后完成。
$T≤5, 1≤n≤1000$&lt;/p&gt;
&lt;h3&gt;输出格式&lt;/h3&gt;
&lt;p&gt;对于每个数据，输出一行一个整数，为攻克关卡的顺序方案个数，mod1,000,000,007输出。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;5
10
5 &amp;gt; 8
5 &amp;gt; 6
0 &amp;lt; 1
9 &amp;lt; 4
2 &amp;gt; 5
5 &amp;lt; 9
8 &amp;lt; 1
9 &amp;gt; 3
1 &amp;lt; 7
10
6 &amp;gt; 7
2 &amp;gt; 0
9 &amp;lt; 0
5 &amp;gt; 9
7 &amp;gt; 0
0 &amp;gt; 3
7 &amp;lt; 8
1 &amp;lt; 2
0 &amp;lt; 4
10
2 &amp;lt; 0
1 &amp;gt; 4
0 &amp;gt; 5
9 &amp;lt; 0
9 &amp;gt; 3
1 &amp;lt; 2
4 &amp;gt; 6
9 &amp;lt; 8
7 &amp;gt; 1
10
0 &amp;gt; 9
5 &amp;gt; 6
3 &amp;gt; 6
8 &amp;lt; 7
8 &amp;gt; 4
0 &amp;gt; 6
8 &amp;gt; 5
8 &amp;lt; 2
1 &amp;gt; 8
10
8 &amp;lt; 3
8 &amp;lt; 4
1 &amp;gt; 3
1 &amp;lt; 9
3 &amp;lt; 7
2 &amp;lt; 8
5 &amp;gt; 2
5 &amp;lt; 6
0 &amp;lt; 9
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;2580
3960
1834
5208
3336
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;先做了&lt;a href=&quot;/2017/08/05/66/&quot;&gt;ALO&lt;/a&gt;， 又做了SAO。&lt;br /&gt;
然后就突然想看刀剑了， 虽然看来好几遍了， 不过河北的省选真会玩儿。&lt;br /&gt;
什么时候来个GGO就好了。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;回到这道题:&lt;/p&gt;
&lt;p&gt;首先将本题转化为一个树上问题（这tm的不是显然吗）。&lt;br /&gt;
然后我们发现答案只与每对点的遍历数序有关。&lt;br /&gt;
那么我们定义$f[i][j]$为一$i$为根节点的子树中有$j$个比他小。&lt;br /&gt;
那么假设$i$的子节点$u$要求小于$i$&lt;br /&gt;
那么以$u$为根的子树中有可能有$[0, k - 1]$ 个数比$u$小&lt;br /&gt;
那么在考虑小于他的数的合并顺序，
由插板法得$C_{j}^{k}$&lt;br /&gt;
同理小于它的为$C_{size[i] + size[u] - j - 1}^{size[u] - k}$
综上转移方程为&lt;br /&gt;
$$f[i][j + k] = f[i][j] * \sum_{c=0}^{k-1}{f[u][c]} * C_{j + k}^{j} * C_{size[u] + size[i] - k - j - 1}^{size[u] - k}$$
大于与此类似&lt;/p&gt;
&lt;p&gt;不知道为什么数组越界过来&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
const int MAXN = 1005;
const int MOD = 1000000007;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;){if(ch==&apos;-&apos;)f=-1;ch=getchar();}
    while(ch&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;){x=x*10+ch-&apos;0&apos;;ch=getchar();}
    return x*f;
}
struct edge
{
    int END, next, v;
}v[MAXN &amp;lt;&amp;lt; 1];
int first[MAXN], p;
void add(int a, int b, int c)
{
    v[p].END = b;
    v[p].next = first[a];
    v[p].v = c;
    first[a] = p++;
}
long long f[MAXN][MAXN];
long long g[MAXN];
long long Sum[MAXN][MAXN];
long long C[MAXN][MAXN];
int size[MAXN];
void dfs(int rt, int fa)
{
    size[rt] = f[rt][0] = 1;
    for (int i = first[rt]; i != -1; i = v[i].next)
    {
        if (v[i].END == fa) continue;
        dfs(v[i].END, rt);
        for (int j = 0; j &amp;lt; size[rt] + size[v[i].END]; j++) g[j] = 0;
        if (v[i].v == 1)
            for (int j = 0; j &amp;lt; size[rt]; j++)
                for (int k = 0; k &amp;lt;= size[v[i].END]; k++)
                {
                    long long tmp = f[rt][j] * Sum[v[i].END][k - 1] % MOD;
                    long long rmp = C[j + k][j] * C[size[rt] + size[v[i].END] - k - j - 1][size[v[i].END] - k] % MOD;
                    (g[j + k] += tmp * rmp % MOD) %= MOD;
                }
        else
            for (int j = 0; j &amp;lt; size[rt]; j++)
                for (int k = 0; k &amp;lt;= size[v[i].END]; k++)
                {
                    long long tmp = f[rt][size[rt] - j - 1] * (Sum[v[i].END][size[v[i].END] - 1] - Sum[v[i].END][size[v[i].END] - k - 1] + MOD) % MOD;
                    long long rmp = C[j + k][j] % MOD * C[size[v[i].END] + size[rt] - k - j - 1][size[v[i].END] - k] % MOD;
                    (g[size[rt] + size[v[i].END] - j - k - 1] += tmp * rmp % MOD) %= MOD;
                }
        size[rt] += size[v[i].END];
        for (int j = 0; j &amp;lt; size[rt]; j++) f[rt][j] = g[j];
    }
    Sum[rt][0] = f[rt][0];
    for (int i = 1; i &amp;lt; size[rt]; i++)
        Sum[rt][i] = (Sum[rt][i - 1] + f[rt][i]) % MOD;
}
int main()
{
    int t = read();
    C[0][0] = 1;    
    for (int i = 1; i &amp;lt;= 1000; i++)
    {
        C[i][0] = 1;
        for (int j = 1; j &amp;lt;= i; j++)
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
    }
    while (t--)
    {
        memset (size, 0, sizeof (size));
        memset (Sum, 0, sizeof (Sum));
        memset (f, 0, sizeof (f));
        memset (first, -1, sizeof (first));
        p = 0;
        int n = read(), a, b;
        char c[3];
        for (int i = 1; i &amp;lt; n; i++)
        {
            scanf (&quot;%d%s%d&quot;, &amp;amp;a, c, &amp;amp;b);
            a++, b++;
            if (c[0] == &apos;&amp;gt;&apos;) add(a, b, 1), add(b, a, -1);
            else add(a, b, -1), add(b, a, 1);
        }
        dfs(1, 0);
        printf (&quot;%lld\n&quot;, Sum[1][n - 1]);
    }
    // while (1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 3262 陌上花开 CDQ</title><link>https://www.nekomio.com/posts/116/</link><guid isPermaLink="true">https://www.nekomio.com/posts/116/</guid><pubDate>Wed, 25 Oct 2017 21:29:20 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;有n朵花，每朵花有三个属性：花形(s)、颜色(c)、气味(m)，又三个整数表示。现要对每朵花评级，一朵花的级别是它拥有的美丽能超过的花的数量。定义一朵花A比另一朵花B要美丽，当且仅当Sa&amp;gt;=Sb,Ca&amp;gt;=Cb,Ma&amp;gt;=Mb。显然，两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。&lt;/p&gt;
&lt;h3&gt;输入格式&lt;/h3&gt;
&lt;p&gt;第一行为N,K (1 &amp;lt;= N &amp;lt;= 100,000, 1 &amp;lt;= K &amp;lt;= 200,000), 分别表示花的数量和最大属性值。
以下N行，每行三个整数si, ci, mi (1 &amp;lt;= si, ci, mi &amp;lt;= K)，表示第i朵花的属性&lt;/p&gt;
&lt;h3&gt;输出格式&lt;/h3&gt;
&lt;p&gt;包含N行，分别表示评级为0...N-1的每级花的数量。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;10 3
3 3 3
2 3 3 
2 3 1 
3 1 1 
3 1 2 
1 3 1 
1 1 2 
1 2 2 
1 3 2 
1 2 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;3
1
3
0
1
0
1
0
0
1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;提示&lt;/h3&gt;
&lt;p&gt;1 &amp;lt;= N &amp;lt;= 100,000, 1 &amp;lt;= K &amp;lt;= 200,000&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;三维偏序&lt;br /&gt;
将一个维度作为时间。&lt;/p&gt;
&lt;p&gt;比如我令 &lt;strong&gt;颜色(c)&lt;/strong&gt; 为时间维。&lt;/p&gt;
&lt;p&gt;那么第一步将除时间(颜色)以外的一个维度排序，&lt;br /&gt;
比如说我这里将 &lt;strong&gt;花形(s)&lt;/strong&gt; 排序&lt;/p&gt;
&lt;p&gt;那么我们要保证这一维(花形) 时刻有序。&lt;/p&gt;
&lt;p&gt;然后我们分治时间(颜色);&lt;/p&gt;
&lt;p&gt;我选择的方法是暴力&lt;code&gt;sort&lt;/code&gt;， 先递归。&lt;/p&gt;
&lt;p&gt;那么在分治后左边的花型一定是小于右边的。&lt;/p&gt;
&lt;p&gt;所以只要将左右分别按时间排序， 对于每一个右边的值， 将左边时间比他小的更新到树状数组中。 然后查询第三维小于他的个数就可以更新答案了。&lt;/p&gt;
&lt;p&gt;一些具体的细节可以看代码实现&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
const int N = 100005;
const int M = 200005;
struct data
{
    int s, c, m, pos, num, ans;
    bool operator &amp;lt; (const data &amp;amp;a) const
    {
        if (s == a.s &amp;amp;&amp;amp; c == a.c) return m &amp;lt; a.m;
        if (s == a.s) return c &amp;lt; a.c;
        return s &amp;lt; a.s; 
    }
}a[N], b[N];
const bool cmp(const data &amp;amp;a, const data &amp;amp;b)
{
    if (a.c == b.c) a.m &amp;lt; b.m;
    return a.c &amp;lt; b.c;
}
int Sum[M], cnt, Color[M], C;
#define lowbit(_) ((_) &amp;amp; (-_))
void add(int x, int c)
{
    for (int i = x; i &amp;lt;= M; i += lowbit(i))
    {
        if (Color[i] != C) Sum[i] = 0;
        Color[i] = C;
        Sum[i] += c;
    }
}
int Query(int x)
{
    int ans = 0;
    for (int i = x; i &amp;gt; 0; i -= lowbit(i))
    {
        if (Color[i] == C)
            ans += Sum[i];
    }
    return ans;
}
void CDQ(int l, int r)
{
    if (l == r) return;
    int mid = l + r &amp;gt;&amp;gt; 1;
    CDQ(l, mid), CDQ(mid + 1, r);
    sort(b + l, b + mid + 1, cmp);
    sort(b + mid + 1, b + r + 1, cmp);
    C++;
    for (int j = mid + 1, i = l; j &amp;lt;= r; j++)
    {
        for (; b[i].c &amp;lt;= b[j].c &amp;amp;&amp;amp; i &amp;lt;= mid; i++)
            add(b[i].m, b[i].num);
        b[j].ans += Query(b[j].m);
    }
}
int main()
{
    int n, k;
    scanf (&quot;%d%d&quot;, &amp;amp;n, &amp;amp;k);
    for (int i = 1; i &amp;lt;= n; i++){
        scanf (&quot;%d%d%d&quot;, &amp;amp;a[i].s, &amp;amp;a[i].c, &amp;amp;a[i].m);
        a[i].pos = i;
    }
    sort(a + 1, a + n + 1);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        if (a[i].c == a[i - 1].c &amp;amp;&amp;amp; a[i].s == a[i - 1].s &amp;amp;&amp;amp; a[i].m == a[i - 1].m)
            b[cnt].num++;
        else
            b[++cnt] = a[i], b[cnt].num = 1;
    }
    // for (int i = 1; i &amp;lt;= cnt; i++) printf (&quot;%d%c&quot;, b[i].pos, &quot; \n&quot;[i == cnt]);
    CDQ(1, cnt);
    // for (int i = 1; i &amp;lt;= cnt; i++) printf (&quot;%d%c&quot;, b[i].ans, &quot; \n&quot;[i == cnt]);
    // while(1);
    static int Ans[N];
    for (int i = 1; i &amp;lt;= cnt; i++) Ans[b[i].ans + b[i].num - 1] += b[i].num;
    for (int i = 0; i &amp;lt; n; i++) printf (&quot;%d\n&quot;, Ans[i]);
    // while (1);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 1176 [Balkan2007]Mokia CDQ</title><link>https://www.nekomio.com/posts/115/</link><guid isPermaLink="true">https://www.nekomio.com/posts/115/</guid><pubDate>Sat, 21 Oct 2017 11:46:59 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;维护一个W*W的矩阵，初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M&amp;lt;=160000,询问数Q&amp;lt;=10000,W&amp;lt;=2000000.&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小&lt;/p&gt;
&lt;p&gt;接下来每行为一下三种输入之一(不包含引号):
&quot;1 x y a&quot;
&quot;2 x1 y1 x2 y2&quot;
&quot;3&quot;
输入1:你需要把(x,y)(第x行第y列)的格子权值增加a
输入2:你需要求出以左下角为(x1,y1),右上角为(x2,y2)的矩阵内所有格子的权值和,并输出
输入3:表示输入结束&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;对于每个输入2,输出一行,即输入2的答案&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;3
5
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Code&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
const int MAXN = 800005;
struct Query
{
    int x, y, op, val, id, pos;
    bool operator &amp;lt; (const Query &amp;amp;a) const
    {
        return x == a.x ? op &amp;lt; a.op : x &amp;lt; a.x;
    }
} Ask[MAXN], tmp[MAXN];
int n, m, Ans[MAXN];
#define lowbit(_) ((_)&amp;amp;(-_))
struct BIT
{
    int Sum[2000005];
    void add(int x, int c)
    {
        for (int i = x; i &amp;lt;= n; i += lowbit(i))
            Sum[i] += c;
    }
    int Query(int x)
    {
        int ans = 0;
        for (int i = x; i &amp;gt; 0; i -= lowbit(i))
            ans += Sum[i];
        return ans;
    }
}bit;
void add()
{
    int x1, y1, x2, y2;
    scanf (&quot;%d%d%d%d&quot;, &amp;amp;x1, &amp;amp;y1, &amp;amp;x2, &amp;amp;y2);
    ++Ans[0];
    Ask[++m].pos = Ans[0], Ask[m].x = x1 - 1, Ask[m].y = y1 - 1, Ask[m].val = 1, Ask[m].op = 1;
    Ask[++m].pos = Ans[0], Ask[m].x = x2    , Ask[m].y = y2    , Ask[m].val = 1, Ask[m].op = 1;
    Ask[++m].pos = Ans[0], Ask[m].x = x1 - 1, Ask[m].y = y2    , Ask[m].val =-1, Ask[m].op = 1;
    Ask[++m].pos = Ans[0], Ask[m].x = x2    , Ask[m].y = y1 - 1, Ask[m].val =-1, Ask[m].op = 1;
}
void CDQ(int l, int r)
{
    if (l == r)
        return;
    int mid = l + r &amp;gt;&amp;gt; 1, l1 = l, l2 = mid + 1;
    for (int i = l; i &amp;lt;= r; i++)
    {
        if (Ask[i].id &amp;lt;= mid &amp;amp;&amp;amp; !Ask[i].op)
            bit.add(Ask[i].y, Ask[i].val);
        if (Ask[i].id &amp;gt; mid &amp;amp;&amp;amp; Ask[i].op)
            Ans[Ask[i].pos] += Ask[i].val * bit.Query(Ask[i].y);
    }
    for (int i = l; i &amp;lt;= r; i++)
        if (Ask[i].id &amp;lt;= mid &amp;amp;&amp;amp; !Ask[i].op)
            bit.add(Ask[i].y, -Ask[i].val);
    for (int i = l; i &amp;lt;= r; i++)
    {
        if (Ask[i].id &amp;lt;= mid)
            tmp[l1++] = Ask[i];
        else tmp[l2++] = Ask[i];
    }
    for (int i = l; i &amp;lt;= r; i++)
        Ask[i] = tmp[i];
    CDQ(l, mid);
    CDQ(mid + 1, r);
    return;
}
int main()
{
    freopen(&quot;mokia.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;mokia.out&quot;, &quot;w&quot;, stdout);
    int op;
    scanf (&quot;%d%d&quot;, &amp;amp;op, &amp;amp;n);
    while (1)
    {
        scanf (&quot;%d&quot;, &amp;amp;op);
        if (op == 1)
        {
            m++;
            scanf (&quot;%d%d%d&quot;, &amp;amp;Ask[m].x, &amp;amp;Ask[m].y, &amp;amp;Ask[m].val);
        }
        else if (op == 2)
            add();
        else break;
    }
    for (int i = 1; i &amp;lt;= m; i++)
        Ask[i].id = i;
    sort(Ask + 1, Ask + m + 1);
    CDQ(1 ,m);
    for (int i = 1; i &amp;lt;= Ans[0]; i++)
        printf (&quot;%d\n&quot;, Ans[i]);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 2064 分裂 状压DP</title><link>https://www.nekomio.com/posts/114/</link><guid isPermaLink="true">https://www.nekomio.com/posts/114/</guid><pubDate>Sat, 21 Oct 2017 08:23:31 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;背景： 和久必分，分久必和。。。 题目描述： 中国历史上上分分和和次数非常多。。通读中国历史的WJMZBMR表示毫无压力。 同时经常搞OI的他把这个变成了一个数学模型。 假设中国的国土总和是不变的。 每个国家都可以用他的国土面积代替， 又两种可能，一种是两个国家合并为1个，那么新国家的面积为两者之和。 一种是一个国家分裂为2个，那么2个新国家的面积之和为原国家的面积。 WJMZBMR现在知道了很遥远的过去中国的状态，又知道了中国现在的状态，想知道至少要几次操作（分裂和合并各算一次操作），能让中国从当时状态到达现在的状态。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行一个数n1，表示当时的块数，接下来n1个数分别表示各块的面积。 第二行一个数n2，表示现在的块，接下来n2个数分别表示各块的面积。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;一行一个数表示最小次数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;1 6
3 1 2 3
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;数据范围：&lt;/h3&gt;
&lt;p&gt;对于100%的数据，n1,n2&amp;lt;=10，每个数&amp;lt;=50&lt;br /&gt;
对于30%的数据，n1,n2&amp;lt;=6，&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;状压DP
首先可以知道用$n+m-2$次一定可以实现&lt;br /&gt;
所以我们考虑减少次数。&lt;br /&gt;
如果原集合能分出来一块与新集合中的一块大小相同。&lt;br /&gt;
那么这是一个子问题, 他的答案也是$n+m-2$&lt;br /&gt;
同样剩下的集合也是如此。 这样我们就把答案减小了2。&lt;br /&gt;
然后可以看出我们需要尽可能多的将集合分为几部分。 每部分对应相等。&lt;br /&gt;
这可以用状压DP来解决。&lt;br /&gt;
可以将新集合中所有值设为相反数， 这样就可以求和为0就可以了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
int a[100];
int S[(1 &amp;lt;&amp;lt; 20) + 1], f[(1 &amp;lt;&amp;lt; 20) + 1];
int main()
{
    int n, m;
    int cnt = 0;
    scanf (&quot;%d&quot;, &amp;amp;n);
    for (cnt = 1; cnt &amp;lt;= n; cnt++)
        scanf (&quot;%d&quot;, &amp;amp;a[cnt]);
    scanf (&quot;%d&quot;, &amp;amp;m);
    n += m;
    for (; cnt &amp;lt;= n; cnt++)
        scanf (&quot;%d&quot;, &amp;amp;a[cnt]), a[cnt] = -a[cnt];
    int N = (1 &amp;lt;&amp;lt; n) - 1;
    for (int i = 1; i &amp;lt;= N; i++)
    {
        int j = 0;
        for (j = 1; j &amp;lt;= n; j++)
            if (i &amp;amp; (1 &amp;lt;&amp;lt; (j - 1)))
                break;
        S[i] = S[i ^ (1 &amp;lt;&amp;lt; (j - 1))] + a[j];
        for (j = 1; j &amp;lt;= n; j++)
            if (i &amp;amp; (1 &amp;lt;&amp;lt; (j - 1)))
                f[i] = max(f[i], f[i ^ (1 &amp;lt;&amp;lt; (j - 1))] + (!S[i]));
    }
    printf (&quot;%d&quot;, n - f[N] * 2);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 1972 [Sdoi2010]猪国杀</title><link>https://www.nekomio.com/posts/113/</link><guid isPermaLink="true">https://www.nekomio.com/posts/113/</guid><pubDate>Tue, 10 Oct 2017 21:41:16 GMT</pubDate><content:encoded>&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;概述&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;《猪国杀》是一种多猪牌类回合制游戏，一共有三种角色：主猪，忠猪，反猪。&lt;/li&gt;
&lt;li&gt;每局游戏主猪有且只有一只，忠猪和反猪可以有多只，每只猪扮演一种角色。
&amp;lt;!--more--&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;游戏目的&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主猪（MP）：自己存活的情况下消灭所有的反猪。&lt;/li&gt;
&lt;li&gt;忠猪（ZP）：不惜一切保护主猪，胜利条件与主猪相同。&lt;/li&gt;
&lt;li&gt;反猪（FP）：杀死主猪。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;游戏过程&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;游戏开始时候，每个玩家手里都会有 4 张牌，且体力上限和初始体力都是 4 。&lt;/li&gt;
&lt;li&gt;开始游戏时，从主猪开始，按照逆时针方向（数据中就是按照编号从 1, 2, 3...n, 1... 的顺序）依次行动。&lt;/li&gt;
&lt;li&gt;每个玩家自己的回合可以分为 4 个阶段
&lt;ul&gt;
&lt;li&gt;摸牌阶段
&lt;ul&gt;
&lt;li&gt;从牌堆顶部摸两张牌，依次放到手牌的最右边。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;出牌阶段
&lt;ul&gt;
&lt;li&gt;你可以使用 0 张到任意张牌，每次使用牌的时候都使用最靠左的能够使用的牌。&lt;/li&gt;
&lt;li&gt;当然，要满足如下规则
&lt;ul&gt;
&lt;li&gt;如果没有猪哥连弩，每个出牌阶段只能使用一次“杀”来攻击。&lt;/li&gt;
&lt;li&gt;任何牌被使用后被弃置（武器是装备上）。&lt;/li&gt;
&lt;li&gt;被弃置的牌以后都不能再用，即与游戏无关。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;各种牌介绍&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每张手牌用一个字母表示，字母代表牌的种类。&lt;/li&gt;
&lt;li&gt;基本牌
&lt;ul&gt;
&lt;li&gt;『桃(P)』
&lt;ul&gt;
&lt;li&gt;在自己的回合内，如果自己的体力值不等于体力上限，那么使用一个桃可以为自己补充一点体力；否则不能使用桃。
桃只能对自己使用。&lt;/li&gt;
&lt;li&gt;在自己的回合外，如果自己的血变为 0 或者更低，那么也可以使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;『杀(K)』
&lt;ul&gt;
&lt;li&gt;在自己的回合内，对攻击范围内除自己以外的一名角色使用。&lt;/li&gt;
&lt;li&gt;如果没有被『闪』抵消，则造成 1 点伤害。&lt;/li&gt;
&lt;li&gt;无论有无武器，杀的攻击范围都是 1。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;『闪(D)』
&lt;ul&gt;
&lt;li&gt;当你受到杀的攻击时，可以弃置一张闪来抵消杀的效果。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;锦囊牌
&lt;ul&gt;
&lt;li&gt;『决斗(F)』
&lt;ul&gt;
&lt;li&gt;出牌阶段，对除自己以外任意一名角色使用，由目标角色先开始，自己和目标角色轮流弃置一张杀，首先没有杀可弃的一方受到1点伤害，另一方视为此伤害的来源。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;『南猪入侵(N)』
&lt;ul&gt;
&lt;li&gt;出牌阶段，对除你以外所有角色使用，按逆时针顺序从使用者下家开始依次结算，除非弃置一张杀，否则受到1点伤害。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;『万箭齐发(W)』
&lt;ul&gt;
&lt;li&gt;和南猪入侵类似，不过要弃置的不是杀而是闪。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;『无懈可击(J)』
&lt;ul&gt;
&lt;li&gt;在目标锦囊生效前抵消其效果。&lt;/li&gt;
&lt;li&gt;每次有一张锦囊即将生效时，从使用这张锦囊的猪开始，按照逆时针顺序，依次得到使用无懈可击的机会。&lt;/li&gt;
&lt;li&gt;效果
&lt;ul&gt;
&lt;li&gt;用于决斗时，决斗无效并弃置。&lt;/li&gt;
&lt;li&gt;用于南猪入侵或万箭齐发时，当结算到某个角色时才能使用，当前角色不需弃置牌并且不会受到伤害（仅对一个角色产生效果）。&lt;/li&gt;
&lt;li&gt;用于无懈可击时，成为目标的无懈可击被无效。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;装备牌
&lt;ul&gt;
&lt;li&gt;『猪哥连弩(Z)』
&lt;ul&gt;
&lt;li&gt;武器，攻击范围 1，出牌阶段你可以使用任意张杀。
同一时刻最多只能装一个武器。&lt;/li&gt;
&lt;li&gt;如果先前已经有了一把武器，那么之后再装武器的话，会弃置以前的武器来装现在的武器。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;特殊事件及概念解释&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;伤害来源
&lt;ul&gt;
&lt;li&gt;杀、南猪入侵、万箭齐发的伤害来源均是使用该牌的猪。&lt;/li&gt;
&lt;li&gt;决斗的伤害来源如上。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;距离
&lt;ul&gt;
&lt;li&gt;两只猪的距离定义为沿着逆时针方向间隔的猪数 +1。即初始时 1 和 2 的距离为 1 ，但是 2 和 1 的距离就是 n - 1 。&lt;/li&gt;
&lt;li&gt;注意一个角色的死亡会导致一些猪距离的改变。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;玩家死亡
&lt;ul&gt;
&lt;li&gt;如果该玩家的体力降到 0 或者更低，并且自己手中没有足够的桃使得自己的体力值回到 1，那么就死亡了，死亡后所有的牌（装备区，手牌区）被弃置、&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;奖励与惩罚
&lt;ul&gt;
&lt;li&gt;反猪死亡时，最后一个伤害来源处（即使是反猪）立即摸三张牌。&lt;/li&gt;
&lt;li&gt;忠猪死亡时，如果最后一个伤害来源是主猪，那么主猪所有装备牌、手牌被弃置。&lt;/li&gt;
&lt;li&gt;注意，一旦达成胜利条件，游戏立刻结束，因此即使会摸 3 张牌或者还有牌可以用也不用执行了。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;现在，我们已经知道每只猪的角色、手牌，还有牌堆初始情况，并且假设每个角色会按照如下的行为准则进行游戏，你需要做的就是告诉小猪 iPig 最后的结果。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;几种行为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;献殷勤
&lt;ul&gt;
&lt;li&gt;使用无懈可击挡下南猪入侵、万箭齐发、决斗。&lt;/li&gt;
&lt;li&gt;使用无懈可击抵消表敌意。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;表敌意
&lt;ul&gt;
&lt;li&gt;对某个角色使用杀、决斗。&lt;/li&gt;
&lt;li&gt;使用无懈可击抵消献殷勤。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;跳忠
&lt;ul&gt;
&lt;li&gt;即通过行动表示自己是忠猪。&lt;/li&gt;
&lt;li&gt;跳忠行动就是对主猪或对某只已经跳忠的猪献殷勤，或者对某只已经跳反的猪表敌意。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;跳反
&lt;ul&gt;
&lt;li&gt;即通过行动表示自己是反猪。&lt;/li&gt;
&lt;li&gt;跳反行动就是对主猪或对某只已经跳忠的猪表敌意，或者对某只已经跳反的猪献殷勤。&lt;/li&gt;
&lt;li&gt;忠猪不会跳反，反猪也不会跳忠。&lt;/li&gt;
&lt;li&gt;不管是忠猪还是反猪，能够跳必然跳。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;行动准则&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;共性
&lt;ul&gt;
&lt;li&gt;每个角色如果手里有桃且生命值未满，那么必然吃掉。&lt;/li&gt;
&lt;li&gt;有南猪入侵、万箭齐发、必然使用。&lt;/li&gt;
&lt;li&gt;有装备必然装上。&lt;/li&gt;
&lt;li&gt;受到杀时，有闪必然弃置。&lt;/li&gt;
&lt;li&gt;响应南猪入侵或者万箭齐发时候，有杀/闪必然弃置。&lt;/li&gt;
&lt;li&gt;不会对未表明身份的猪献殷勤（包括自己）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;特性
&lt;ul&gt;
&lt;li&gt;主猪
&lt;ul&gt;
&lt;li&gt;主猪会认为没有跳身份，且用南猪入侵/万箭齐发对自己造成伤害的猪是“类反猪”（没伤害到不算，注意“类反猪”并没有表明身份），如果之后跳了，那么主猪会重新认识这只猪。
对于每种表敌意的方式，对逆时针方向能够执行到的第一只“类反猪”或者已跳反猪表；如果没有，那么就不表敌意。
决斗时会不遗余力弃置杀。&lt;/li&gt;
&lt;li&gt;如果能对已经跳忠的猪或自己献殷勤，那么一定献。&lt;/li&gt;
&lt;li&gt;如果能够对已经跳反的猪表敌意，那么一定表。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;忠猪
&lt;ul&gt;
&lt;li&gt;对于每种表敌意的方式，对逆时针方向能够执行到的第一只已经跳反的猪表；如果没有，那么就不表敌意。&lt;/li&gt;
&lt;li&gt;决斗时，如果对方是主猪，那么不会弃置杀，否则，会不遗余力弃置杀。&lt;/li&gt;
&lt;li&gt;如果有机会对主猪或者已经跳忠的猪献殷勤，那么一定献。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;反猪
&lt;ul&gt;
&lt;li&gt;对于每种表敌意的方式，如果有机会则对主猪表，否则，对逆时针方向能够执行到的第一只已经跳忠的猪表；如果没有，那么就不表敌意。&lt;/li&gt;
&lt;li&gt;决斗时会不遗余力弃置杀。&lt;/li&gt;
&lt;li&gt;如果有机会对已经跳反的猪献殷勤，那么一定献。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;限于 iPig 只会用 P++ 语言写 A + B，他请你用 Pigcal(Pascal)、P(C) 或 P++(C++) 语言来帮他预测最后的结果。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;输入&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一行包含两个正整数n(2 &amp;lt;= n &amp;lt;= 10) 和m( m &amp;lt;= 2000)，分别代表玩家数和牌堆中牌的数量。&lt;/li&gt;
&lt;li&gt;接下来n行，每行5个字符串，依次表示对第i只猪的角色和初始4张手牌描述。&lt;/li&gt;
&lt;li&gt;编号为1的肯定是主猪。&lt;/li&gt;
&lt;li&gt;再接下来一行，一共m个字符串，按照从牌堆顶部到牌堆底部的顺序描述每张牌&lt;/li&gt;
&lt;li&gt;所有的相邻的两个字符串都严格用1个空格隔开，行尾没有多余空格。​&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;输出&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;输出数据第一行包含一个字符串代表游戏结果。
&lt;ul&gt;
&lt;li&gt;如果是主猪胜利
&lt;ul&gt;
&lt;li&gt;那么输出“MP”&lt;/li&gt;
&lt;li&gt;否则输出“FP”。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;接下来n行，第i行是对第i只猪的手牌描述
&lt;ul&gt;
&lt;li&gt;按照手牌从左往右的顺序输出&lt;/li&gt;
&lt;li&gt;相邻两张牌用一个空格隔开，行末尾没有多余空格&lt;/li&gt;
&lt;li&gt;如果这只猪已阵亡，那么只要输出“DEAD”即可。&lt;/li&gt;
&lt;li&gt;注意如果要输出手牌而没有手牌的话，那么只需输出一个空行。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;样例输入&lt;/p&gt;
&lt;p&gt;3 10&lt;br /&gt;
MP D D F F&lt;br /&gt;
ZP N N N D&lt;br /&gt;
FP J J J J&lt;br /&gt;
F F D D J J F F K D&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;样例输出&lt;/p&gt;
&lt;p&gt;FP&lt;br /&gt;
DEAD&lt;br /&gt;
DEAD&lt;br /&gt;
J J J J J D&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;题解&lt;/h3&gt;
&lt;p&gt;题目就是题解&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;list&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
int n, m, T, D_F, Z_D_to_M;
char C[2005];
// #define Log 1
namespace Pig
{
    bool Died[11];
    struct Pig_data
    {
        /*
        Id :
            1: 主猪
            2: 忠猪
            3: 反猪
        */
        std::list&amp;lt;char&amp;gt; Card;
        std::list&amp;lt;char&amp;gt;::iterator it, it2;
        int Identity, Strength;
        bool Equipped, Jump, Similar;
        void init(int Id, char *s)
        {
            Strength = 4, Similar = 0;
            Identity = Id;
            if (Id == 1) Jump = 1;
            for (int i = 1; i &amp;lt;= 4; i++)
                Card.push_back(s[i]);
        }
        void Print(int i)
        {
            it2 = Card.end();
            if (it2 == Card.begin()) 
            {
                if(i != n)
                    printf(&quot;\n&quot;);
                return;
            }
            it2--;
            for (it = Card.begin(); it != it2; it++)
                printf(&quot;%c &quot;, *it);
            printf(&quot;%c&quot;, *it2);
            if(i != n) printf (&quot;\n&quot;);
        }
    }Pig[11];

}
namespace Card
{
    struct Card_Heap_data
    {
        char Card_Heap[2005];
        int h, t;
        void init(char *s, int Num)
        {
            t = Num;
            h = 0;
            for (int i = 1; i &amp;lt;= Num; i++)
                Card_Heap[i] = s[i];
        }
        char Get_Card()
        {
            if (h == t)
                return Card_Heap[h];
            else
                return Card_Heap[++h];
        }
    }Card;
}
namespace Main
{
void Read_init()
{
    #ifdef Log
        printf(&quot;===========================================\n Read Start\n=================================\n&quot;);
    #endif
    scanf(&quot;%d%d&quot;, &amp;amp;::n ,&amp;amp;::m);
    char s[5], ID[4];
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf (&quot;%s&quot;, ID);
        for (int j = 1; j &amp;lt;= 4; j++)
            std::cin &amp;gt;&amp;gt; s[j];
        if (ID[0] == &apos;M&apos;)
            Pig::Pig[i].init(1, s);
        else if (ID[0] == &apos;Z&apos;)
            Pig::Pig[i].init(2, s);
        else
            Pig::Pig[i].init(3, s), T++;
    }
#ifdef Log
    printf(&quot;===========================================\n Read Pig Succeed\n=================================\n&quot;);
#endif
    memset(Pig::Died, 0, sizeof(Pig::Died));
    for (int i = 1; i &amp;lt;= m; i++)
        std::cin &amp;gt;&amp;gt; C[i];
    #ifdef Log
        printf(&quot;===========================================\n Read Card Succeed\n=================================\n&quot;);
    #endif
    Card::Card.init(C, m);
#ifdef Log
    printf(&quot;===========================================\nCard Init Succeed\n=================================\n&quot;);
#endif
}
void Get_Card(int x, int t)
{
#ifdef Log
    printf(&quot;Pig %d Get %d Card\n&quot;, x, t);
#endif
    while (t--)
    {
        Pig::Pig[x].Card.push_back(Card::Card.Get_Card());
    }
}
int nxt[11];
int next(int x)
{
    if (nxt[x] != 0) return nxt[x];
    for (int i = x + 1; ; i++)
    {
        if (i == n + 1) i = 1;
        if (!Pig::Died[i]) 
            return nxt[x] = i;
    }
}
std::list&amp;lt;char&amp;gt;::iterator it, it2, searchit, eraseit;
bool Over(int &amp;amp;W)
{
    bool No_Fan = 1;
    int now = 0;
    if (Pig::Died[1]) return W = 1, 1;
    else now = 1;
    int Next_Pig = now;
    do
    {
        if (Pig::Pig[Next_Pig].Identity == 3) No_Fan = 0;
        Next_Pig = next(Next_Pig);
    }while (Next_Pig != now);
    if (No_Fan)
        return W = 0, 1;
    else
        return 0;
}
bool Judge(int x, char c, int K_Num, int &amp;amp;t)
{
    if (c == &apos;P&apos;) 
    {
        if (Pig::Pig[x].Strength != 4)
            return t = x, 1;
        else return 0;
    }
    else if (c == &apos;K&apos;)
    {
        if (K_Num &amp;amp;&amp;amp; !Pig::Pig[x].Equipped) return 0;
        if (Pig::Pig[x].Identity == 1)
        {
            if (Pig::Pig[next(x)].Similar) return t = next(x), 1;
            if (Pig::Pig[next(x)].Identity == 3 &amp;amp;&amp;amp; Pig::Pig[next(x)].Jump)
                return t = next(x), 1;
            else return 0;
        }
        else if (Pig::Pig[x].Identity == 2)
        {
            if (Pig::Pig[next(x)].Identity == 3 &amp;amp;&amp;amp; Pig::Pig[next(x)].Jump)
                return t = next(x), 1;
            else return 0;
        }
        else if (Pig::Pig[x].Identity == 3)
        {
            if ((Pig::Pig[next(x)].Identity == 1 || Pig::Pig[next(x)].Identity == 2) &amp;amp;&amp;amp; Pig::Pig[next(x)].Jump)
                return t = next(x), 1;
            else return 0;
        }
        else
        {
            printf (&quot;ERROR No Identity\n&quot;);
        }
    } 
    else if (c == &apos;D&apos;) return 0;
    else if (c == &apos;F&apos;)
    {
        bool flag = 0;
        int Next_Pig = next(x);
        while (Next_Pig != x)
        {
            if (Pig::Pig[x].Identity == 1)
            {
                if (Pig::Pig[Next_Pig].Similar) return t = Next_Pig, 1;
                if (Pig::Pig[Next_Pig].Identity == 3 &amp;amp;&amp;amp; Pig::Pig[Next_Pig].Jump)
                    return t = Next_Pig, 1;
                else goto Restart;
            }
            else if (Pig::Pig[x].Identity == 2)
            {
                if (Pig::Pig[Next_Pig].Identity == 3 &amp;amp;&amp;amp; Pig::Pig[Next_Pig].Jump)
                    return t = Next_Pig, 1;
                else goto Restart;
            }
            else if (Pig::Pig[x].Identity == 3)
            {
                if (Pig::Pig[Next_Pig].Identity == 1)
                    return t = Next_Pig, 1;
                else if (Pig::Pig[Next_Pig].Identity == 2 &amp;amp;&amp;amp; Pig::Pig[Next_Pig].Jump) 
                {
                    if (!flag) flag = 1, t = Next_Pig;
                    goto Restart;
                }
                else goto Restart;
            }
            else
            {
                printf (&quot;ERROR No Identity\n&quot;);
            }
            Restart: Next_Pig = next(Next_Pig);
        }
        if (Pig::Pig[x].Identity == 3 &amp;amp;&amp;amp; flag) return 1;
        else return 0;
    }
    else if (c == &apos;N&apos; || c == &apos;W&apos;)
    {
        return t = -1, 1;
    }
    else if (c == &apos;J&apos;)
        return 0;
    else if (c == &apos;Z&apos;)
        return t = x, 1;
    else
    {
        printf (&quot;ERROR in Card ID\n&quot;);
        exit(0);
        return 0;
    }
    return 0;
}
bool Have(char c, int t)// and erase
{
    #ifdef Log
        printf(&quot;It&apos;s %d to return He have &quot;, t);
        Pig::Pig[t].Print();
    #endif
    for (searchit = Pig::Pig[t].Card.begin(); searchit != Pig::Pig[t].Card.end(); searchit++)
        if (*searchit == c)
        {
            #ifdef Log
                printf(&quot;Pig %d Used %c\n&quot;, t, c);
            #endif
            return Pig::Pig[t].Card.erase(searchit), 1;
        }
    return 0;
}
bool Need_Wuxie(int x)
{
    if (!Have(&apos;J&apos;, x)) return 0;
    Pig::Pig[x].Jump = 1;
    Pig::Pig[x].Similar = 0;
    return 1;
}
bool Wuxie(int x, bool op)
{
    int Next_Pig = x;
    do
    {
        if ((op == 0 &amp;amp;&amp;amp; Pig::Pig[Next_Pig].Identity == 3) || (op == 1 &amp;amp;&amp;amp; Pig::Pig[Next_Pig].Identity != 3))
        {
            if (!Need_Wuxie(Next_Pig)) goto again;
            if (!Wuxie(Next_Pig, op ^ 1)) return 1;
            return 0;
        }
        again: Next_Pig = next(Next_Pig);
    }while (Next_Pig != x);
    return 0;
}
bool Okforwuxie(int x, int t)
{
    if (!Pig::Pig[t].Jump) return 0;
    if (Pig::Pig[t].Identity == 3) return Wuxie(x, 0);
    else return Wuxie(x, 1);
}
void UseM(int x, char c, int t)
{
    if (c == &apos;K&apos;)
    {
        #ifdef Log
            printf(&quot;Pig %d use %c to %d\n&quot;, x, c, t);
        #endif
        if (Pig::Pig[t].Jump) Pig::Pig[x].Jump = 1;
        if (!Have(&apos;D&apos;, t))
        {
            #ifdef Log
                printf(&quot;Pig %d not have %c\n&quot;, t, &apos;D&apos;);
            #endif // Log
            Pig::Pig[t].Strength--;
            #ifdef Log
            printf(&quot;Pig %d HP = %d\n&quot;, t, Pig::Pig[t].Strength);
            #endif // Log
            if (Pig::Pig[t].Strength == 0)
            {
                if (!Have(&apos;P&apos;, t))
                {
                    #ifdef Log
                    printf(&quot;Pig %d Died\n&quot;, t);
                    #endif // Log
                    Pig::Died[t] = 1;
                    memset(nxt, 0, sizeof (nxt));
                    if (Pig::Died[1] == 1) return;
                    if (Pig::Pig[t].Identity == 2 &amp;amp;&amp;amp; Pig::Pig[x].Identity == 1) 
                    {
                        Pig::Pig[x].Card.clear(), Pig::Pig[x].Equipped = 0;
                        Z_D_to_M = 1;
                    }
                    if (Pig::Pig[t].Identity == 3) 
                    {
                        D_F++;
                        if (D_F == T) return;
                        Get_Card(x, 3);
                    }
                }
                else
                    Pig::Pig[t].Strength = 1;
            }
        }
        return;
    }
    else if (c == &apos;P&apos;)
        return Pig::Pig[x].Strength++, void(0);
    else if (c == &apos;F&apos;)
    {
        #ifdef Log
            printf(&quot;Pig %d use %c to %d\n&quot;, x, c, t);
        #endif
        Pig::Pig[x].Jump = 1, Pig::Pig[x].Similar = 0;
        if (Pig::Pig[x].Identity == 1 &amp;amp;&amp;amp; Pig::Pig[t].Identity == 2) 
        {
            Pig::Pig[t].Strength--;
            #ifdef Log
            printf(&quot;Pig %d HP = %d\n&quot;, t, Pig::Pig[t].Strength);
            #endif // Log
            if (Pig::Pig[t].Strength == 0)
            {
                if (!Have(&apos;P&apos;, t))
                {
                    #ifdef Log
                    printf(&quot;Pig %d Died\n&quot;, t);
                    #endif // Log
                    Pig::Died[t] = 1;
                    memset(nxt, 0, sizeof (nxt));
                    if (Pig::Died[1] == 1) return;
                    if (Pig::Pig[t].Identity == 2 &amp;amp;&amp;amp; Pig::Pig[x].Identity == 1) 
                    {
                        Pig::Pig[x].Card.clear(), Pig::Pig[x].Equipped = 0;
                        Z_D_to_M = 1;
                    }
                    if (Pig::Pig[t].Identity == 3) 
                    {
                        D_F++;
                        if (D_F == T) return;
                        Get_Card(t, 3);
                    }
                }
                else
                    Pig::Pig[t].Strength = 1;
            }
            return;
        }
        if (Okforwuxie(x, t)) return void(0);
        while (1)
        {
            if (!Have(&apos;K&apos;, t)) 
            {
                Pig::Pig[t].Strength--;
                #ifdef Log
                printf(&quot;Pig %d HP = %d\n&quot;, t, Pig::Pig[t].Strength);
                #endif // Log
                if (Pig::Pig[t].Strength == 0)
                {
                    if (!Have(&apos;P&apos;, t))
                    {
                        #ifdef Log
                        printf(&quot;Pig %d Died\n&quot;, t);
                        #endif // Log
                        Pig::Died[t] = 1;
                        memset (nxt, 0, sizeof (nxt));
                        if (Pig::Died[1] == 1) return;
                        if (Pig::Pig[t].Identity == 2 &amp;amp;&amp;amp; Pig::Pig[x].Identity == 1) 
                        {
                            Pig::Pig[x].Card.clear(), Pig::Pig[x].Equipped = 0;
                            Z_D_to_M = 1;
                        }
                        if (Pig::Pig[t].Identity == 3) 
                        {
                            D_F++;
                            if (D_F == T) return;
                            Get_Card(x, 3);
                        }
                    }
                    else
                        Pig::Pig[t].Strength = 1;
                }
                return;
            }
            if (!Have(&apos;K&apos;, x))
            {
                Pig::Pig[x].Strength--;
                #ifdef Log
                printf(&quot;Pig %d HP = %d\n&quot;, x, Pig::Pig[x].Strength);
                #endif // Log
                if (Pig::Pig[x].Strength == 0)
                {
                    if (!Have(&apos;P&apos;, x))
                    {
                        #ifdef Log
                        printf(&quot;Pig %d Died\n&quot;, x);
                        #endif // Log
                        Pig::Died[x] = 1;
                        memset (nxt, 0, sizeof (nxt));
                        if (Pig::Died[1] == 1) return;
                        if (Pig::Pig[x].Identity == 2 &amp;amp;&amp;amp; Pig::Pig[t].Identity == 1) 
                        {
                            Pig::Pig[t].Card.clear(), Pig::Pig[t].Equipped = 0;
                            Z_D_to_M = 1;
                        }
                        if (Pig::Pig[x].Identity == 3) 
                        {
                            D_F++;
                            if (D_F == T) return;
                            Get_Card(t, 3);
                            return;
                        }
                    }
                    else
                        Pig::Pig[x].Strength = 1;
                }
                return;
            }
        }
    }
    else if (c == &apos;N&apos;)
    {
        #ifdef Log
        printf(&quot;Pig %d use %c to %d\n&quot;, x, c, t);
        #endif
        int Next_Pig = next(x);
        do
        {
            if (Okforwuxie(x, Next_Pig)) goto END1;
            if (!Have(&apos;K&apos;, Next_Pig))
            {
                Pig::Pig[Next_Pig].Strength--;
                #ifdef Log
                printf(&quot;Pig %d HP = %d\n&quot;, Next_Pig, Pig::Pig[Next_Pig].Strength);
                #endif // Log
                if (Pig::Pig[Next_Pig].Strength == 0)
                {
                    if (!Have(&apos;P&apos;, Next_Pig))
                    {
                        #ifdef Log
                        printf(&quot;Pig %d Died\n&quot;, Next_Pig);
                        #endif // Log
                        memset (nxt, 0, sizeof (nxt));
                        Pig::Died[Next_Pig] = 1;
                        if (Pig::Died[1] == 1) return;
                        if (Pig::Pig[Next_Pig].Identity == 2 &amp;amp;&amp;amp; Pig::Pig[x].Identity == 1) 
                        {
                            Pig::Pig[x].Card.clear(), Pig::Pig[x].Equipped = 0;
                            Z_D_to_M = 1;
                        }
                        if (Pig::Pig[Next_Pig].Identity == 3) 
                        {
                            D_F++;
                            if (D_F == T) return;
                            Get_Card(x, 3);
                        }
                    }
                    else
                        Pig::Pig[Next_Pig].Strength = 1;
                }
                if (Pig::Pig[Next_Pig].Identity == 1 &amp;amp;&amp;amp; Pig::Pig[x].Jump == 0) Pig::Pig[x].Similar = 1;
            }
            END1:Next_Pig = next(Next_Pig);
        }while (Next_Pig != x);
        return;
    }
    else if (c == &apos;W&apos;)
    {
        #ifdef Log
        printf(&quot;Pig %d use %c to %d\n&quot;, x, c, t);
        #endif
        int Next_Pig = next(x);
        do
        {
            if (Okforwuxie(x, Next_Pig)) goto END2;
            if (!Have(&apos;D&apos;, Next_Pig))
            {
                Pig::Pig[Next_Pig].Strength--;
                #ifdef Log
                printf(&quot;Pig %d HP = %d\n&quot;, Next_Pig, Pig::Pig[Next_Pig].Strength);
                #endif // Log
                if (Pig::Pig[Next_Pig].Strength == 0)
                {
                    if (!Have(&apos;P&apos;, Next_Pig))
                    {
                        #ifdef Log
                        printf(&quot;Pig %d Died\n&quot;, Next_Pig);
                        #endif // Log
                        Pig::Died[Next_Pig] = 1;
                        memset (nxt, 0, sizeof (nxt));
                        if (Pig::Died[1] == 1) return;
                        if (Pig::Pig[Next_Pig].Identity == 2 &amp;amp;&amp;amp; Pig::Pig[x].Identity == 1) 
                        {
                            Pig::Pig[x].Card.clear(), Pig::Pig[x].Equipped = 0;
                            Z_D_to_M = 1;
                        }
                        if (Pig::Pig[Next_Pig].Identity == 3) 
                        {
                            D_F++;
                            if (D_F == T) return;
                            Get_Card(x, 3);
                        }
                    }
                    else
                        Pig::Pig[Next_Pig].Strength = 1;
                }
                if (Pig::Pig[Next_Pig].Identity == 1 &amp;amp;&amp;amp; Pig::Pig[x].Jump == 0) Pig::Pig[x].Similar = 1;
            }
            END2:Next_Pig = next(Next_Pig);
        }while (Next_Pig != x);
        return;
    }
    else if (c == &apos;Z&apos;)
        return Pig::Pig[x].Equipped = 1, void(0);
}
void Use(int x, char c, int t)
{
    UseM(x, c, t);
    // printf(&quot;ERROR in Use at Identity, There is no Id in the Pig\n&quot;);
}
void Play(int x)
{
    it = Pig::Pig[x].Card.begin();
    int K_Num = 0;
    int Y = D_F;
    for (; it != Pig::Pig[x].Card.end(); it = it2)
    {
        int t = 0;
        if (Judge(x, *it, K_Num, t))
        {
            #ifdef Log
                printf(&quot;Pig %d Used %c to %d\n&quot;, x, *it, t);
            #endif
            Use(x, *it, t);
            if (Z_D_to_M) return;
            if (*it == &apos;K&apos;) K_Num++;
            Pig::Pig[x].Card.erase(it);
            it2 = Pig::Pig[x].Card.begin();
            if (Pig::Died[1] == 1 || Pig::Died[x] == 1 || D_F == T) return;
        }
        else
        {
            it2 = it;
            it2++;
        }
    }
}
void Run()
{
    int now = 1, W = 0;
    while (!Over(W))
    {
    #ifdef Log
        printf(&quot;It is %d Paly, It&apos;s Identity is %d &quot;, now, Pig::Pig[now].Identity);
        if (Pig::Pig[now].Jump == 1)
            printf(&quot;He Jumped\n&quot;);
        else
            printf(&quot;He not Jumped\n&quot;);
    #endif // Log
        Get_Card(now, 2);
    #ifdef Log
        printf(&quot;He has &quot;);
        Pig::Pig[now].Print();
    #endif
        Play(now);
        Z_D_to_M = 0;
        now = next(now);
    }
    if (W == 0)
    {
        printf (&quot;MP\n&quot;);
        for (int i = 1; i &amp;lt;= n; i++)
        {
            if (Pig::Died[i])
                printf(&quot;DEAD\n&quot;);
            else
                Pig::Pig[i].Print(i);
        }
    }
    else
    {
        printf (&quot;FP\n&quot;);
        for (int i = 1; i &amp;lt;= n; i++)
        {
            if (Pig::Died[i])
                printf(&quot;DEAD\n&quot;);
            else
                Pig::Pig[i].Print(i);
        }
    }
}
}
int main()
{
    // freopen(&quot;kopk10.in&quot;, &quot;r&quot;, stdin);
    // freopen(&quot;1.out&quot;, &quot;w&quot;, stdout);
#ifdef Log
    printf(&quot;======================================\n Start\n======================================\n&quot;);
#endif
    Main::Read_init();
#ifdef Log
    printf(&quot;Read Success\n\n&quot;);
    printf(&quot;======================================\nGame Start\n\n&quot;);
#endif
    Main::Run();
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>集训小记</title><link>https://www.nekomio.com/posts/112/</link><guid isPermaLink="true">https://www.nekomio.com/posts/112/</guid><pubDate>Sun, 01 Oct 2017 15:44:21 GMT</pubDate><content:encoded>&lt;h3&gt;2017 - 10 - 1 Day1&lt;/h3&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;
开坑&lt;br /&gt;
今天是集训的第一天， 上午就考了一场考试；&lt;br /&gt;
心中满怀希望，但又充满忐忑&lt;br /&gt;
我不知未来如何， 但希望过好今天&lt;/p&gt;
&lt;p&gt;今天的考试T1很明显是一道找规律的题目，但是因为一些问题，我好久才找到正确的公式。&lt;br /&gt;
这道题让我意识到基础的重要性， 因为本题用到了高精度， 也就是说， 如果没有高精度的基础， 做本题就无从谈起。&lt;br /&gt;
如果打一个高精度调上半天， 那考试就没得考了。&lt;/p&gt;
&lt;p&gt;然后T2是一道好题， 真的好， 这道题当场我并没有什么思路。 连暴力都没有想出来。  就骗了一点分完了。&lt;br /&gt;
然后考完试 听说输出m就有40。 真是个悲哀的故事。&lt;br /&gt;
正解是分类讨论， 情况很多。&lt;/p&gt;
&lt;p&gt;最后T3也是一道思路好题；
看到n的范围， 一下子想到了状压， 但是在仔细一看题， 发现状压好像压不下。&lt;br /&gt;
想了想也没有办法， 正解是按深度状压 + dfs 来减少状态数。 真的没有见过这么压的， 学习了。&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 2 Day2&lt;/h3&gt;
&lt;p&gt;集训的第二天了， 早上跟着物理奥赛的跑了个操。&lt;br /&gt;
发现信息奥赛的好像只有我来了， 一脸尴尬。。。&lt;br /&gt;
发现高三的竟然还起上课啊， 为他们默哀。&lt;br /&gt;
突然感觉自己不孤单了&lt;/p&gt;
&lt;p&gt;今天上午的考试
T1一开始没看出来， 先做到T2， 做完之后想了想T1，发现如果把店转换成线段的话就很好解决了。&lt;/p&gt;
&lt;p&gt;T2是一个裸的线段树。感觉复杂度不大对， 但是还是过了。&lt;/p&gt;
&lt;p&gt;T3是到好题， 反正我考场上没做出来， 全场平均分1分。&lt;br /&gt;
考完后看题解。 觉得应该先找规律， 在去想怎么打。&lt;br /&gt;
其实规律就是一个杨辉三角， 累加就可以。 二分左右边界。&lt;/p&gt;
&lt;p&gt;今天是死在第三题上了， 还是思路不够开阔， 还有就是A了前两道题之后不太想想第三题了。&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 3 Day3&lt;/h3&gt;
&lt;p&gt;早上逃了个操&lt;br /&gt;
反正下雨也没跑&lt;/p&gt;
&lt;p&gt;昨天晚上考了个试都不是什么难题&lt;br /&gt;
T1 直接结论 第一个为m第二个为m - 1, 之后就是m - 2的n - 2 次方
前面的小数特判一下就过了&lt;/p&gt;
&lt;p&gt;T2 是一个简单的树DP 和概率充电器那题很想， 上下分别考虑。&lt;/p&gt;
&lt;p&gt;T3 读错题了。 其他的都没想错。 用平衡树维护翻转。然后并查集搞就好了&lt;/p&gt;
&lt;p&gt;听说昨天晚上有人浪被逮了。。&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 4 Day4&lt;/h3&gt;
&lt;p&gt;上午考了个试， AK了&lt;br /&gt;
做完后还有一个多小时， 好无聊的， 什么也干不了。&lt;br /&gt;
然后Rank1， 讲了题， 然后就放假了， 开心。&lt;br /&gt;
然后就办域名修好了。 蜜汁不能实名认证。&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 5 Day5&lt;/h3&gt;
&lt;p&gt;放假在家
下午就返校了&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 6 Day6&lt;/h3&gt;
&lt;p&gt;该了昨天的题， 每一道是简单的。
T1 是一道线段树的题， 没想出来， 其实正解很暴力。 26次修改即可&lt;/p&gt;
&lt;p&gt;T2 很神的一个DP 状态的定义和处理方法很巧， 先计算出结果，再让结果是正确的， 修正。&lt;/p&gt;
&lt;p&gt;T3 一个Trie树上的题需要转化模型。 然后是一个DP 。 不是很难。&lt;/p&gt;
&lt;p&gt;下午又考试。&lt;/p&gt;
&lt;p&gt;看到标题&lt;img src=&quot;https://images-1254442371.image.myqcloud.com/Blog/2017-10-7-1.JPG&quot; alt=&quot;&quot; /&gt; 有点害怕。&lt;/p&gt;
&lt;p&gt;但第一题是个水题， 打打就过了。&lt;/p&gt;
&lt;p&gt;T2 杜教筛
额。。 不会啊。。&lt;br /&gt;
学习了一下，这道题还是不难的&lt;/p&gt;
&lt;p&gt;T3 用线段树维护Treap 上的LCA， 又是迷一波&lt;br /&gt;
最长上升子序列。&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 7 Day7&lt;/h3&gt;
&lt;p&gt;把昨天的题改完了。
下午考试
又是一个恐怖的标题 HEOI2016 Day0 试题 好怕&lt;br /&gt;
结果T1 是个水题&lt;/p&gt;
&lt;p&gt;T2
读完题？什么玩意。
先打个暴力， 想了想DP 想到了60分的DP
结果打挂了， 好伤心。&lt;br /&gt;
正解
$ dp[i][j][k] $表示前i个字符，最长同色长度&amp;lt;=j,最后一个字符是k。
$ s[i][j]=\sum_{k=1}^{m}dp[i][j][k] $
$ dp[i][j][k]=s[i-1][j]*g[i][i][k]-(s[i-j-1][j]-dp[i-j-1][j][k])*g[i-j][i][k] $
然后就可以DP了&lt;/p&gt;
&lt;p&gt;T3
将集合分为重集合和轻集合。 轻集合暴力修改， 重集合打标记。&lt;br /&gt;
然后预处理搞一搞就出来了&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 8 Day8&lt;/h3&gt;
&lt;p&gt;上午考试， 第三题被很多人水过了&lt;br /&gt;
正解好难啊啊啊啊啊啊啊啊啊啊。。。。&lt;/p&gt;
&lt;p&gt;T1 直接二分即可。 set&lt;/p&gt;
&lt;p&gt;T2 线段树， 和前几天做的一道题类似。 结果也没想出来。&lt;br /&gt;
不过不是很难， 改一会就改完了&lt;/p&gt;
&lt;p&gt;T3 真是恶心。。。
&lt;a href=&quot;https://github.com/HZoi-WildRage/OIcode/blob/master/Codes/HZOI/2017-10-8/Drink.cpp&quot;&gt;代码(github)&lt;/a&gt;&lt;br /&gt;
改了好久&lt;br /&gt;
&lt;a href=&quot;https://mubu.com/doc/1xT0WAONRA&quot;&gt;思路&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这雨下了一天。。&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 9 Day9&lt;/h3&gt;
&lt;p&gt;没考好啊。。&lt;br /&gt;
T1 是个容斥原理， 几乎用了我全部的时间， 结果也没推出来。。&lt;/p&gt;
&lt;p&gt;T2 是个水题。。。 结果都没怎么做。 Tarjan 缩点 + DFS&lt;/p&gt;
&lt;p&gt;T3 没人改出来&lt;br /&gt;
打了一天的 猪国杀&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 10 Day10&lt;/h3&gt;
&lt;p&gt;那群被开回家的回来了&lt;br /&gt;
T1 将 m 用类似离散的方法搞一搞能出来&lt;/p&gt;
&lt;p&gt;T2 裸DP&lt;/p&gt;
&lt;p&gt;T3 将后面的几位单独考虑转移就可以了。。&lt;/p&gt;
&lt;p&gt;猪国杀 终于过了&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 11 Day11&lt;/h3&gt;
&lt;p&gt;T1, T2 都是水题
T3 改了好久&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 12 Day12&lt;/h3&gt;
&lt;p&gt;两场啊啊啊&lt;br /&gt;
上午的题不可做， 不可改。 说是noi水平&lt;br /&gt;
下午的题到是不难&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 13 Day13&lt;/h3&gt;
&lt;p&gt;又是两场。。&lt;br /&gt;
上午也是不难， 第三题没找到规律&lt;br /&gt;
下午全场AK&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 14 Day14&lt;/h3&gt;
&lt;h3&gt;2017 - 10 - 15 Day15&lt;/h3&gt;
&lt;h3&gt;2017 - 10 - 16 Day16&lt;/h3&gt;
&lt;h3&gt;2017 - 10 - 17 Day17&lt;/h3&gt;
&lt;h3&gt;2017 - 10 - 18 Day18&lt;/h3&gt;
&lt;p&gt;跳了好几天， 不太想更了
今天复习了一下 Tarjan
开始学2-SAT 有点懵&lt;/p&gt;
&lt;h3&gt;2017 - 10 - 25 Day25&lt;/h3&gt;
&lt;p&gt;又是好几天。。&lt;br /&gt;
总结一下这几天的情况&lt;br /&gt;
这几天脑子有点乱， 刷题也刷不动的样子。&lt;br /&gt;
考试的题一改改一天。&lt;br /&gt;
虽然也有好点的时候，但是心里还是苦啊。&lt;br /&gt;
CDQ好懵啊。。&lt;br /&gt;
感觉自己少学了好多东西。心累。&lt;/p&gt;
&lt;h6&gt;未完待续。。。&lt;/h6&gt;
</content:encoded></item><item><title>后缀数组</title><link>https://www.nekomio.com/posts/111/</link><guid isPermaLink="true">https://www.nekomio.com/posts/111/</guid><pubDate>Tue, 26 Sep 2017 19:43:34 GMT</pubDate><content:encoded>&lt;h2&gt;后缀数组&lt;/h2&gt;
&lt;p&gt;详解 请参见 IOI2009 国家集训队论文
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h4&gt;例3：不可重叠最长重复子串（pku1743）&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;http://poj.org/problem?id=1743&quot;&gt;题目链接&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;先二分答案，判断是否存在两个长度为 k 的子串是相同的，且不重叠。&lt;br /&gt;
对于每组后缀，判断后缀的sa值的最大值和最小值之差是否不小于k&lt;/p&gt;
&lt;p&gt;Code&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
const int MAXN = 20010;
int buc[MAXN], wa[MAXN], wb[MAXN], n;
int r[MAXN], sa[MAXN], Rank[MAXN], height[MAXN];
void getheight(int n)
{
    int i, j, k = 0;
    for (i = 0; i &amp;lt; n; i++)
        Rank[sa[i]] = i;
    for (i = 0; i &amp;lt; n; height[Rank[i++]] = k)
        for (k ? k-- : 0, j = sa[Rank[i] - 1]; r[i + k] == r[j + k]; k++)
            ;
    return;
}
bool cmp(int *c, int a, int b, int d)
{
    return c[a] == c[b] &amp;amp;&amp;amp; c[a + d] == c[b + d];
}
void da(int n, int m = 320)
{
    // for(int i=0;i&amp;lt;n;i++)printf(&quot;%d  %d\n&quot;,i,r[i]);
    int i, j, p, *x = wa, *y = wb, *t;
    for (i = 0; i &amp;lt; m; i++)
        buc[i] = 0;
    for (i = 0; i &amp;lt; n; i++)
        buc[x[i] = r[i]]++;
    for (i = 1; i &amp;lt; m; i++)
        buc[i] += buc[i - 1];
    for (i = n - 1; ~i; i--)
        sa[--buc[x[i]]] = i;
    for (j = 1, p = 1; p &amp;lt; n; j *= 2, m = p)
    {
        for (i = n - j, p = 0; i &amp;lt; n; i++)
            y[p++] = i;
        for (i = 0; i &amp;lt; n; i++)
            if (sa[i] &amp;gt;= j)
                y[p++] = sa[i] - j;
        for (i = 0; i &amp;lt; m; i++)
            buc[i] = 0;
        for (i = 0; i &amp;lt; n; i++)
            buc[x[y[i]]]++;
        for (i = 1; i &amp;lt; m; i++)
            buc[i] += buc[i - 1];
        for (i = n - 1; ~i; i--)
            sa[--buc[x[y[i]]]] = y[i];
        for (t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i &amp;lt; n; i++)
            x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
    }
    // for(int i=0;i&amp;lt;n;i++)
    //     printf(&quot;%d  %d\n&quot;,i,sa[i]);
    getheight(n);
    return;
}
bool Judge(int mid)
{
    int Min = 0x3f3f3f3f, Max = -0x3f3f3f3f;
    for (int i = 2; i &amp;lt;= n; i++)
    {
        if (height[i] &amp;lt; mid)
            Min = 0x3f3f3f3f, Max = -0x3f3f3f3f;
        else
        {
            Min = min(Min, min(sa[i - 1], sa[i]));
            Max = max(Max, max(sa[i - 1], sa[i]));
            if (Max - Min &amp;gt; mid)
                return 1;
        }
    }
    return 0;
}
int a[MAXN];
int main()
{
    while (~scanf(&quot;%d&quot;, &amp;amp;n) &amp;amp;&amp;amp; n)
    {
        for (int i = 0; i &amp;lt; n; i++)
            scanf(&quot;%d&quot;, &amp;amp;a[i]);
        n--;
        for (int i = 0; i &amp;lt; n; i++)
            r[i] = a[i + 1] - a[i] + 88;
        r[n] = 0;
        da(n + 1);
        int l = 0, r = (n &amp;gt;&amp;gt; 1) + 1, ans = 0;
        while (l &amp;lt; r)
        {
            int m = l + r &amp;gt;&amp;gt; 1;
            if(Judge(m))
                ans = m, l = m + 1;
            else
                r = m;
        }
        if (ans &amp;gt;= 4) printf(&quot;%d\n&quot;, ans + 1);
        else printf(&quot;0\n&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;例4：可重叠的 k 次最长重复子串（pku3261）&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;http://www.lydsy.com/JudgeOnline/problem.php?id=1717&quot;&gt;题目链接&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;先二分答案，然后将后缀分成若干组。判断有没有一个组的后缀个数不小于k。&lt;/p&gt;
&lt;p&gt;Code&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
const int MAXN = 2000005;
int buc[MAXN], wa[MAXN], wb[MAXN], n, K;
int r[MAXN], sa[MAXN], Rank[MAXN], height[MAXN];
void GetHeight(int n)
{
    int i, j, k = 0;
    for (i = 0; i &amp;lt; n; i++)
        Rank[sa[i]] = i;
    for (i = 0; i &amp;lt; n; height[Rank[i++]] = k)
        for (k ? k-- : 0, j = sa[Rank[i] - 1]; r[i + k] == r[j + k]; k++)
            ;
    return;
}
bool cmp(int *c, int a, int b, int d)
{
    return c[a] == c[b] &amp;amp;&amp;amp; c[a + d] == c[b + d];
}
void da(int n, int m = 1000000)
{
    int i, j, p, *x = wa, *y = wb, *t;
    for (i = 0; i &amp;lt; m; i++)
        buc[i] = 0;
    for (i = 0; i &amp;lt; n; i++)
        buc[x[i] = r[i]]++;
    for (i = 1; i &amp;lt; m; i++)
        buc[i] += buc[i - 1];
    for (i = n - 1; ~i; i--)
        sa[--buc[x[i]]] = i;
    for (j = 1, p = 1; p &amp;lt; n; j *= 2, m = p)
    {
        for (i = n - j, p = 0; i &amp;lt; n; i++)
            y[p++] = i;
        for (i = 0; i &amp;lt; n; i++)
            if (sa[i] &amp;gt;= j)
                y[p++] = sa[i] - j;
        for (i = 0; i &amp;lt; m; i++)
            buc[i] = 0;
        for (i = 0; i &amp;lt; n; i++)
            buc[x[y[i]]]++;
        for (i = 1; i &amp;lt; m; i++)
            buc[i] += buc[i - 1];
        for (i = n - 1; ~i; i--)
            sa[--buc[x[y[i]]]] = y[i];
        for (t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i &amp;lt; n; i++)
            x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
    }
    GetHeight(n);
    return;
}
bool Judge(int mid)
{
    int l = 0;
    for (int i = 2; i &amp;lt;= n; i++)
    {
        if (height[i] &amp;lt; mid)
            l = 0;
        else
        {
            l++;
            if(l + 1 &amp;gt;= K) return 1;
        }
    }
    return 0;
}
int main()
{
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;K);
    for (int i = 0; i &amp;lt; n; i++)
        scanf(&quot;%d&quot;, &amp;amp;r[i]);
    da(n + 1);
    int l = 0, r = (n &amp;gt;&amp;gt; 1) + 1, ans = 0;
    while (l &amp;lt; r)
    {
        int mid = l + r &amp;gt;&amp;gt; 1;
        if (Judge(mid))
            ans = mid, l = mid + 1;
        else
            r = mid;
    }
    printf(&quot;%d&quot;, ans);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h6&gt;未完待续。。。&lt;/h6&gt;
</content:encoded></item><item><title>BZOJ 2827 千山鸟飞绝 Treap</title><link>https://www.nekomio.com/posts/110/</link><guid isPermaLink="true">https://www.nekomio.com/posts/110/</guid><pubDate>Sun, 24 Sep 2017 18:27:12 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;话说有一天doyouloveme和vfleaking到山里玩。谁知doyouloveme刚刚进山，所有的鸟儿竟被他的神犇气场给惊得全部飞走了。vfleaking顿时膜拜不已。&lt;br /&gt;
这时鸟王用鸟语说道：“!@#$%……?”安抚了一下众鸟的情绪。鸟王生性好斗，作出了一个决定——要排鸟布阵把刚才吓到它们的人类赶出山去。&lt;br /&gt;
&amp;lt;!--more--&amp;gt;
每只鸟都有一个编号，都有一个威武值。每秒钟鸟王都会发一个命令，编号为v的鸟飞到(x,y)去（坐标系原点是山顶，坐标单位为鸟爪）。鸟飞得很快，一秒之内就飞到了，可以看作是瞬间移动。如果编号为v的鸟和编号为u的鸟某一时刻处在同一位置，它们就会互相鼓励，增加各自的士气值和团结值。一只鸟的士气值等于此刻与它处在同一位置的鸟中的威武值的最大值，团结值等于此刻与它处在同一位置的鸟的只数。如果每一时刻都没有鸟与它处在同一位置，则士气值和团结值都为0。要注意自己不能鼓励自己，计算士气值和团结值时不能算上自己。
t秒钟后，doyouloveme目测出了现在每只鸟的战斗力，于是感叹了一句：“不妙，我们得走了。”&lt;br /&gt;
正所谓团结的鸟儿一个顶俩，所以doyouloveme这样描述战斗力：一只鸟战斗力值等于它在0到t秒中士气值的最大值与团结值的最大值的乘积。注意不是乘积的最大值，而是最大值的乘积。&lt;br /&gt;
vfleaking很想知道现在每只鸟的战斗力，但是他当然不会啦，于是他把这个任务交给了你来完成。&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第一行一个数n，代表鸟的只数。（鸟王那家伙你可以完全忽视掉）&lt;br /&gt;
接下来n行，每行三个整数w,x,y描述每只鸟的威武值和初始坐标。第i+1行描述编号为i的鸟。&lt;br /&gt;
接下来一行有一个数t，代表经过时间ts。&lt;br /&gt;
接下来t行，每行三个整数v,x,y描述鸟王每秒的命令。&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;一共n行，每行一个数，代表每只鸟的战斗力。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;5
1 1 1
3 1 2
4 4 4
2 0 1
2 2 3
5
1 1 2
2 4 4
2 4 3
3 0 1
5 0 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;3
4
6
8
8
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;提示&lt;/h3&gt;
&lt;p&gt;对于样例的解释：
首先5只鸟的位置为(1,1),(1,2),(4,4),(0,1),(2,3)，士气和团结值都是0。&lt;br /&gt;
鸟1飞到了(1,2)，于是鸟1和鸟2互相鼓励，鸟1士气变为3，鸟2士气变为1。鸟1鸟2的团结值变为1。&lt;br /&gt;
然后鸟2飞到(4,4)，与鸟3互相鼓励，鸟2士气变为4，鸟3士气变为3。鸟2与鸟3的团结值变为1。&lt;br /&gt;
鸟2然后飞到了(4,3)，一个没有鸟的地方。于是士气和团结值都变为了0。&lt;br /&gt;
接下来鸟3和鸟5都飞到了鸟4的位置，于是三只鸟互相鼓励，鸟4、鸟5士气变为4，鸟3士气仍为3。鸟3、鸟4、鸟5的团结值都变为2。&lt;br /&gt;
于是大家的战斗力：&lt;br /&gt;
鸟1：3 * 1 = 3&lt;br /&gt;
鸟2：4 * 1 = 4&lt;br /&gt;
鸟3：3 * 2 = 6&lt;br /&gt;
鸟4：4 * 2 = 8&lt;br /&gt;
鸟5：4 * 2 = 8&lt;br /&gt;
1≤n≤30000   0≤t≤300000&lt;br /&gt;
坐标范围为整数，且不超过INT_MIN~INT_MAX&lt;br /&gt;
威武值为不超过INT_MAX的非负整数。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;哈希加Treap&lt;/p&gt;
&lt;p&gt;把每一个点Hash对应的一棵Treap上&lt;br /&gt;
在插入和删除的时候不断的打标记跟新&lt;br /&gt;
注意不要漏情况&lt;br /&gt;
在最后的时候要把所有的标记都推下去&lt;br /&gt;
然后就出来了&lt;br /&gt;
细节很多调了好久&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
int Max_Morale[30005], Max_Solidarity[30005];
struct Point
{
    int x, y;
    Point(int a = 0, int b = 0)
    {
        x = a, y = b;
    }
    bool operator==(const Point &amp;amp;a) const
    {
        return x == a.x &amp;amp;&amp;amp; y == a.y;
    }
};
struct data
{
    int x, ID;
    data(int a = 0, int b = 0)
    {
        x = a, ID = b;
    }
    bool operator&amp;gt;(const data &amp;amp;a) const
    {
        return x == a.x ? ID &amp;gt; a.ID : x &amp;gt; a.x;
    }
    bool operator&amp;lt;=(const data &amp;amp;a) const
    {
        return !(*this &amp;gt; a);
    }
};
struct Treap
{
    struct Node
    {
        int s, key, Max_Num, Max_Size;
        data x;
        Node *ch[2];
        Node(data sa)
        {
            ch[0] = ch[1] = NULL;
            s = 1, x = sa, key = rand();
            Max_Num = Max_Size = 0;
        }
#define size(_) ((_) ? (_)-&amp;gt;s : 0)
        void Pushup()
        {
            s = size(ch[0]) + size(ch[1]) + 1;
        }
        void Pushdown()
        {
            if (ch[0])
            {
                ch[0]-&amp;gt;Max_Num = max(ch[0]-&amp;gt;Max_Num, Max_Num);
                ch[0]-&amp;gt;Max_Size = max(ch[0]-&amp;gt;Max_Size, Max_Size);
                Max_Morale[ch[0]-&amp;gt;x.ID] = max(Max_Morale[ch[0]-&amp;gt;x.ID], ch[0]-&amp;gt;Max_Num);
                Max_Solidarity[ch[0]-&amp;gt;x.ID] = max(Max_Solidarity[ch[0]-&amp;gt;x.ID], ch[0]-&amp;gt;Max_Size);
            }
            if (ch[1])
            {
                ch[1]-&amp;gt;Max_Num = max(ch[1]-&amp;gt;Max_Num, Max_Num);
                ch[1]-&amp;gt;Max_Size = max(ch[1]-&amp;gt;Max_Size, Max_Size);
                Max_Morale[ch[1]-&amp;gt;x.ID] = max(Max_Morale[ch[1]-&amp;gt;x.ID], ch[1]-&amp;gt;Max_Num);
                Max_Solidarity[ch[1]-&amp;gt;x.ID] = max(Max_Solidarity[ch[1]-&amp;gt;x.ID], ch[1]-&amp;gt;Max_Size);
            }
            Max_Num = Max_Size = 0;
        }
    } * root;
    Treap()
    {
        root = NULL;
    }
    Node *Merge(Node *A, Node *B)
    {
        if (!A)
            return B;
        if (!B)
            return A;
        if (A-&amp;gt;key &amp;lt; B-&amp;gt;key)
        {
            A-&amp;gt;Pushdown();
            A-&amp;gt;ch[1] = Merge(A-&amp;gt;ch[1], B);
            A-&amp;gt;Pushup();
            return A;
        }
        else
        {
            B-&amp;gt;Pushdown();
            B-&amp;gt;ch[0] = Merge(A, B-&amp;gt;ch[0]);
            B-&amp;gt;Pushup();
            return B;
        }
    }
    typedef pair&amp;lt;Node *, Node *&amp;gt; DNode;
    DNode Split(Node *rt, int k)
    {
        if (!rt)
            return DNode(NULL, NULL);
        DNode o;
        rt-&amp;gt;Pushdown();
        if (size(rt-&amp;gt;ch[0]) &amp;gt;= k)
        {
            o = Split(rt-&amp;gt;ch[0], k);
            rt-&amp;gt;ch[0] = o.second;
            rt-&amp;gt;Pushup();
            o.second = rt;
        }
        else
        {
            o = Split(rt-&amp;gt;ch[1], k - size(rt-&amp;gt;ch[0]) - 1);
            rt-&amp;gt;ch[1] = o.first;
            rt-&amp;gt;Pushup();
            o.first = rt;
        }
        return o;
    }
    Node *kth(int k)
    {
        DNode x = Split(root, k - 1);
        DNode y = Split(x.second, 1);
        Node *ans = y.first;
        root = Merge(Merge(x.first, ans), y.second);
        return ans;
    }
    int Rank(Node *rt, data x)
    {
        if (!rt)
            return 0;
        return x &amp;lt;= rt-&amp;gt;x ? Rank(rt-&amp;gt;ch[0], x) : Rank(rt-&amp;gt;ch[1], x) + size(rt-&amp;gt;ch[0]) + 1;
    }
    void Insert(data x)
    {
        int k = Rank(root, x);
        if (root)
        {
            root-&amp;gt;Max_Size = max(root-&amp;gt;Max_Size, size(root));
            root-&amp;gt;Max_Num = max(root-&amp;gt;Max_Num, x.x);
            Max_Morale[root-&amp;gt;x.ID] = max(root-&amp;gt;Max_Num, Max_Morale[root-&amp;gt;x.ID]);
            Max_Solidarity[root-&amp;gt;x.ID] = max(root-&amp;gt;Max_Size, Max_Solidarity[root-&amp;gt;x.ID]);
        }
        DNode y = Split(root, k);
        Node *n = new Node(x);
        root = Merge(Merge(y.first, n), y.second);
    }
    void remove(data x)
    {
        int k = Rank(root, x);
        DNode a = Split(root, k);
        DNode b = Split(a.second, 1);
        delete b.first;
        root = Merge(a.first, b.second);
    }
};
#define Hash_MOD 76543
#define Hash_MOD_x 9991
#define Hash_MOD_y 7307
int p = 0;
struct Hash_Table
{
    int first[76545];
    struct Link
    {
        Treap *rt;
        Point t;
        int next;
    } v[400000];
    Hash_Table()
    {
        memset(first, -1, sizeof(first));
    }
    void Push(int u, Point now, Treap *x)
    {
        v[p].rt = x;
        v[p].t = now;
        v[p].next = first[u];
        first[u] = p++;
    }
    Treap *&amp;amp;operator[](Point x)
    {
        int Hash = (((x.x % Hash_MOD_x) + Hash_MOD_x) % Hash_MOD_x) * (((x.y % Hash_MOD_y) + Hash_MOD_y) % Hash_MOD_y) % Hash_MOD;
        for (int i = first[Hash]; i != -1; i = v[i].next)
            if (v[i].t == x)
                return v[i].rt;
        Push(Hash, x, new Treap);
        return v[first[Hash]].rt;
    }
} Hash;
#define X(_) ((_) ? (_)-&amp;gt;x : 0)

Point bird[30005];
int Num[30005];
int main()
{
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    int a, b, c;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d%d%d&quot;, &amp;amp;a, &amp;amp;b, &amp;amp;c);
        Max_Morale[i] = max(Max_Morale[i], X(Hash[Point(b, c)]-&amp;gt;kth(size(Hash[Point(b, c)]-&amp;gt;root))).x);
        Max_Solidarity[i] = max(Max_Solidarity[i], size(Hash[Point(b, c)]-&amp;gt;root));
        Hash[Point(b, c)]-&amp;gt;Insert(data(a, i));
        bird[i] = Point(b, c);
        Num[i] = a;
    }
    int m;
    scanf(&quot;%d&quot;, &amp;amp;m);
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d%d%d&quot;, &amp;amp;a, &amp;amp;b, &amp;amp;c);
        Hash[bird[a]]-&amp;gt;remove(data(Num[a], a));
        Max_Morale[a] = max(Max_Morale[a], X(Hash[Point(b, c)]-&amp;gt;kth(size(Hash[Point(b, c)]-&amp;gt;root))).x);
        Max_Solidarity[a] = max(Max_Solidarity[a], size(Hash[Point(b, c)]-&amp;gt;root));
        Hash[Point(b, c)]-&amp;gt;Insert(data(Num[a], a));
        bird[a] = Point(b, c);
    }
    for (int i = 1; i &amp;lt;= n; i++)
        Hash[bird[i]]-&amp;gt;remove(data(Num[i],i));
    for (int i = 1; i &amp;lt;= n; i++)
        printf(&quot;%lld\n&quot;, (long long)Max_Morale[i] * Max_Solidarity[i]);
    // while(1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 3211 花神游历各国</title><link>https://www.nekomio.com/posts/109/</link><guid isPermaLink="true">https://www.nekomio.com/posts/109/</guid><pubDate>Tue, 19 Sep 2017 19:09:52 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/09/19/59c0fb3aab2fe.jpg&quot; alt=&quot;1(16).jpg&quot; /&gt;&lt;br /&gt;
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/09/19/59c0fb305a23a.jpg&quot; alt=&quot;2(5).jpg&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;每次x=1时，每行一个整数，表示这次旅行的开心度&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;101
11
11
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;本题和&lt;a href=&quot;/2017/07/13/34/&quot;&gt;上帝造题的七分钟&lt;/a&gt;是一样的&lt;/p&gt;
&lt;p&gt;但我的程序没有过啊&lt;br /&gt;
打的比较傻&lt;/p&gt;
&lt;p&gt;其实只要维护一个值就可以了&lt;/p&gt;
&lt;p&gt;用一个flag标记是否不变&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
using namespace std;
#ifndef LL
#define LL long long
#endif
#define lch l, m, rt &amp;lt;&amp;lt; 1
#define rch m + 1, r, rt &amp;lt;&amp;lt; 1 | 1
const int N = 100005;
LL Sum[N &amp;lt;&amp;lt; 2];
bool flag[N &amp;lt;&amp;lt; 2];
void PushUp(int rt)
{
	Sum[rt] = Sum[rt &amp;lt;&amp;lt; 1] + Sum[rt &amp;lt;&amp;lt; 1 | 1];
	flag[rt] = flag[rt &amp;lt;&amp;lt; 1] &amp;amp; flag[rt &amp;lt;&amp;lt; 1 | 1];
}
void buildtree(int l, int r, int rt)
{
	if(l == r)
	{
		scanf(&quot;%lld&quot;, &amp;amp;Sum[rt]);
		if(Sum[rt] &amp;lt;= 1)
			flag[rt] = 1;
		return;
	}
	int m = l + r &amp;gt;&amp;gt; 1;
	buildtree(lch);
	buildtree(rch);
	PushUp(rt);
}
void Update(int L, int R, int l, int r, int rt)
{
	if(flag[rt])
		return;
	if(l == r)
	{
		Sum[rt] = sqrt(Sum[rt]);
		if(Sum[rt] &amp;lt;= 1)
			flag[rt] = 1;
		return;
	}
	int m = l + r &amp;gt;&amp;gt; 1;
	if (L &amp;lt;= m) Update(L, R, lch);
	if (R &amp;gt; m) Update(L, R, rch);
	PushUp(rt);
}
LL Query(int L, int R, int l, int r, int rt)
{
	if(L &amp;lt;= l &amp;amp;&amp;amp; R &amp;gt;= r)
		return Sum[rt];
	int m = l + r &amp;gt;&amp;gt; 1;
	LL ans = 0;
	if (L &amp;lt;= m) ans += Query(L, R, lch);
	if (R &amp;gt; m) ans += Query(L, R, rch);
	return ans;
}
int main()
{
	int n;
	scanf(&quot;%d&quot;, &amp;amp;n);
	buildtree(1, n, 1);
	int m;
	scanf(&quot;%d&quot;, &amp;amp;m);
	while (m--)
	{
		int op, l, r;
		scanf(&quot;%d%d%d&quot;, &amp;amp;op, &amp;amp;l, &amp;amp;r);
		if(l &amp;gt; r)
			swap(l, r);
		if (op == 1)
		{
			printf(&quot;%lld\n&quot;, Query(l, r, 1, n, 1));
		}
		else
			Update(l, r, 1, n, 1);
	}
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 1770 [Usaco2009 Nov]lights 燈 折半搜索</title><link>https://www.nekomio.com/posts/108/</link><guid isPermaLink="true">https://www.nekomio.com/posts/108/</guid><pubDate>Sun, 17 Sep 2017 21:09:37 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;贝希和她的闺密们在她们的牛棚中玩游戏。但是天不从人愿，突然，牛棚的电源跳闸了，所有的灯都被关闭了。贝希是一个很胆小的女生，在伸手不见拇指的无尽的黑暗中，她感到惊恐，痛苦与绝望。她希望您能够帮帮她，把所有的灯都给重新开起来！她才能继续快乐地跟她的闺密们继续玩游戏！
&amp;lt;!--more--&amp;gt;
牛棚中一共有N（1 &amp;lt;= N &amp;lt;= 35）盏灯，编号为1到N。这些灯被置于一个非常复杂的网络之中。有M（1 &amp;lt;= M &amp;lt;= 595）条很神奇的无向边，每条边连接两盏灯。每盏灯上面都带有一个开关。当按下某一盏灯的开关的时候，这盏灯本身，还有所有有边连向这盏灯的灯的状态都会被改变。状态改变指的是：当一盏灯是开着的时候，这盏灯被关掉；当一盏灯是关着的时候，这盏灯被打开。问最少要按下多少个开关，才能把所有的灯都给重新打开。数据保证至少有一种按开关的方案，使得所有的灯都被重新打开。&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;＊第一行：两个空格隔开的整数：N和M。&lt;/p&gt;
&lt;p&gt;＊第二到第M+1行：每一行有两个由空格隔开的整数，表示两盏灯被一条无向边连接在一起。没有一条边会出现两次。&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;第一行：一个单独的整数，表示要把所有的灯都打开时，最少需要按下的开关的数目。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;5 6
1 2
1 3
4 2
3 4
2 5
5 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;輸入細節：&lt;/p&gt;
&lt;p&gt;一共有五盞燈。燈1、燈4和燈5都連接著燈2和燈3。&lt;/p&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;輸出細節：&lt;/p&gt;
&lt;p&gt;按下在燈1、燈4和燈5上面的開關。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;【折半搜索】&lt;br /&gt;
将需要搜索的元素分为不关联的两个部分，分别搜索&lt;/p&gt;
&lt;p&gt;在本题中
N的范围有35如果直接搜的话$2^35$会T的很惨&lt;br /&gt;
所以我们将N分为前后两部分&lt;br /&gt;
现将前mid个搜出来，记录每个状态集合的最小的答案&lt;br /&gt;
之后出来后mid + 1到n搜完后加上他的补集跟新答案&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;map&amp;gt;
using namespace std;
long long A[36], full, bin[37];
int Min = 0x3f, n, m;
map&amp;lt;long long, int&amp;gt; Mp;
void dfs1(int x, long long now, int k)
{
	if(x == m + 1)
	{
		if(now == full)
			Min = min(k, Min);
		int t = Mp[now];
		if(!t || t &amp;gt; k)
			Mp[now] = k;
		return;
	}
	dfs1(x + 1, now, k);
	dfs1(x + 1, now^A[x], k + 1);
}
void dfs2(int x, long long now, int k)
{
	if(x == n + 1)
	{
		if(now == full)
			Min = min(k, Min);
		int t = Mp[full - now];
		if(!t)
			return;
		Min = min(t + k, Min);
		return;
	}
	dfs2(x + 1, now, k);
	dfs2(x + 1, now^A[x], k + 1);
}
int main()
{
	// freopen(&quot;lights.in&quot;,&quot;r&quot;,stdin);
	// freopen(&quot;lights.out&quot;,&quot;w&quot;,stdout);
	int c;
	scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;c);
	bin[1] = 1;
	for (int i = 2; i &amp;lt; 37; i++)
		bin[i] = bin[i - 1] &amp;lt;&amp;lt; 1;
	int a, b;
	for (int i = 1; i &amp;lt;= c; i++)
	{
		scanf(&quot;%d%d&quot;, &amp;amp;a, &amp;amp;b);
		A[a] += bin[b];
		A[b] += bin[a];
	}
	for (int i = 1; i &amp;lt;= n; i++)
		A[i] += bin[i];
	full = bin[n + 1] - 1;
	m = n &amp;gt;&amp;gt; 1;
	dfs1(1, 0, 0);
	dfs2(m + 1, 0, 0);
	printf(&quot;%d&quot;, Min);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[NOIP2004] 虫食算</title><link>https://www.nekomio.com/posts/107/</link><guid isPermaLink="true">https://www.nekomio.com/posts/107/</guid><pubDate>Sun, 17 Sep 2017 16:42:37 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;所谓虫食算，就是原先的算式中有一部分被虫子啃掉了，需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子：
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;43#98650#45
+ 8468#6633
44445506978
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中#号代表被虫子啃掉的数字。根据算式，我们很容易判断：第一行的两个数字分别是5和3，第二行的数字是5。
现在，我们对问题做两个限制：
首先，我们只考虑加法的虫食算。这里的加法是N进制加法，算式中三个数都有N位，允许有前导的0。
其次，虫子把所有的数都啃光了，我们只知道哪些数字是相同的。我们将相同的数字用相同的字母表示，不同的数字用不同的字母表示。如果这个算式是N进制的，我们就取英文字母表中的前N个大写字母来表示这个算式中的0到N-1这N个不同的数字（但是这N个字母并不一定顺序地代表0到N-1）。输入数据保证N个字母分别至少出现一次。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BADC
+ CBDA
DCCC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面的算式是一个4进制的算式。很显然，我们只要让ABCD分别代表0123，便可以让这个式子成立了。你的任务是，对于给定的N进制加法算式，求出N个不同的字母分别代表的数字，使得该加法算式成立。输入数据保证有且仅有一组解。&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;包含4行。第一行有一个正整数N（N &amp;lt;= 26），后面的3行每行有一个由大写字母组成的字符串，分别代表两个加数以及和。这3个字符串左右两端都没有空格，从高位到低位，并且恰好有N位。&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;包含一行。在这一行中，应当包含唯一的那组解。解是这样表示的：输出N个数字，分别表示A，B，C……所代表的数字，相邻的两个数字用一个空格隔开，不能有多余的空格。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;5
ABCED
BDACE
EBBAA
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;1 0 3 4 2
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;从后向前从大到小倒着搜&lt;br /&gt;
分8种情况讨论&lt;br /&gt;
打的是真爽&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
using namespace std;
char a[30], b[30], c[30];
bool mark[30];
int map[300], n, ans;
void dfs(int pos, int y)
{
    ans++;
    //printf(&quot;%d\n&quot;, ans);
    if(pos == 0)
    {
        for (int i = &apos;A&apos;; i &amp;lt; &apos;A&apos; + n; i++)
            printf(&quot;%d &quot;,map[i]);
        exit(0);
    }
    if(map[a[pos]] != -1 &amp;amp;&amp;amp; map[b[pos]] != -1 &amp;amp;&amp;amp; map[c[pos]] != -1)
    {
        if((map[a[pos]] + map[b[pos]] + y) % n != map[c[pos]])
            return;
        else
            dfs(pos - 1, (map[a[pos]] + map[b[pos]] + y) / n);
    }
    else if (map[a[pos]] != -1 &amp;amp;&amp;amp; map[b[pos]] != -1)
    {
        if(mark[(map[a[pos]] + map[b[pos]] + y) % n])
            return;
        else
        {
            map[c[pos]] = (map[a[pos]] + map[b[pos]] + y) % n;
            mark[(map[a[pos]] + map[b[pos]] + y) % n] = 1;
            dfs(pos - 1, (map[a[pos]] + map[b[pos]] + y) / n);
            mark[(map[a[pos]] + map[b[pos]] + y) % n] = 0;
            map[c[pos]] = -1;
        }
    }
    else if (map[a[pos]] != -1 &amp;amp;&amp;amp; map[c[pos]] != -1)
    {
        int now = map[c[pos]] + n - y - map[a[pos]];
        if(mark[now % n])
            return;
        map[b[pos]] = now % n;
        mark[now % n] = 1;
        dfs(pos - 1, (now % n) == now ? 1 : 0);
        map[b[pos]] = -1;
        mark[now % n] = 0;
    }
    else if (map[b[pos]] != -1 &amp;amp;&amp;amp; map[c[pos]] != -1)
    {
        int now = map[c[pos]] + n - y - map[b[pos]];
        if(mark[now % n])
            return;
        map[a[pos]] = now % n;
        mark[now % n] = 1;
        dfs(pos - 1, (now % n) == now ? 1 : 0);
        map[a[pos]] = -1;
        mark[now % n] = 0;
    }
    else if(map[a[pos]] != -1)
    {
        for (int i = 0; i &amp;lt; n; i++)
            if(!mark[i] &amp;amp;&amp;amp; !mark[(map[a[pos]] + i + y) % n])
            {
                map[b[pos]] = i;
                map[c[pos]] = (map[a[pos]] + i + y) % n;
                mark[i] = 1;
                mark[(map[a[pos]] + i + y) % n] = 1;
                dfs(pos - 1, (map[a[pos]] + i + y) / n);
                map[b[pos]] = -1;
                map[c[pos]] = -1;
                mark[i] = 0;
                mark[(map[a[pos]] + i + y) % n] = 0;
            }
    }
    else if(map[b[pos]] != -1)
    {
        for (int i = 0; i &amp;lt; n; i++)
            if(!mark[i] &amp;amp;&amp;amp; !mark[(map[b[pos]] + i + y) % n])
            {
                map[a[pos]] = i;
                map[c[pos]] = (map[b[pos]] + i + y) % n;
                mark[i] = 1;
                mark[(map[b[pos]] + i + y) % n] = 1;
                dfs(pos - 1, (map[b[pos]] + i + y) / n);
                map[a[pos]] = -1;
                map[c[pos]] = -1;
                mark[i] = 0;
                mark[(map[b[pos]] + i + y) % n] = 0;
            }
    }
    else if(map[c[pos]] != -1)
    {
        for (int i = 0; i &amp;lt; n; i++)
        {
            if(!mark[i] &amp;amp;&amp;amp; !mark[(map[c[pos]] + n - i - y) % n])
            {
                map[a[pos]] = i;
                map[b[pos]] = (map[c[pos]] + n - i - y) % n;
                mark[i] = 1;
                mark[(map[c[pos]] + n - i - y) % n] = 1;
                dfs(pos - 1, ((map[c[pos]] + n - i - y) % n == (map[c[pos]] + n - i - y)));
                map[a[pos]] = -1;
                map[b[pos]] = -1;
                mark[i] = 0;
                mark[(map[c[pos]] + n - i - y) % n] = 0;
            }
        }
    }
    else
    {
        // printf(&quot;\\\\\n&quot;);
        for (int i = n - 1; i &amp;gt;= 0; i--)
        {
            if(mark[i]) continue;
            mark[i] = 1;
            map[a[pos]] = i;
            // printf(&quot;------__\n&quot;);
            for (int j = n - 1; j &amp;gt;= 0; j--)
            {
                if(!mark[j] &amp;amp;&amp;amp; !mark[(i + j + y) % n])
                {
                    // printf(&quot;===\n&quot;);
                    mark[j] = mark[(i + j + y) % n] = 1;
                    map[b[pos]] = j;
                    map[c[pos]] = (i + j + y) % n;
                    dfs(pos - 1, (i + j + y) / n);
                    mark[j] = mark[(i + j + y) % n] = 0;
                    map[b[pos]] = -1;
                    map[c[pos]] = -1;
                }
                else if (mark[j] &amp;amp;&amp;amp; mark[(i + j + y) % n] &amp;amp;&amp;amp; (j == map[b[pos]]) &amp;amp;&amp;amp; ((i + j + y) % n == map[c[pos]]))
                {
                    dfs(pos - 1, (i + j + y) / n);
                }
                else if (mark[j] &amp;amp;&amp;amp; (j == map[b[pos]]) &amp;amp;&amp;amp; !mark[(i + j + y) % n])
                {
                    // printf(&quot;----\n&quot;);
                    mark[(i + j + y) % n] = 1;
                    map[c[pos]] = (i + j + y) % n;
                    dfs(pos - 1, (i + j + y) / n);
                    map[c[pos]] = -1;
                    mark[(i + j + y) % n] = 0;
                }
            }
            map[a[pos]] = -1;
            mark[i] = 0;
        }
    }
}
int main()
{
    // freopen(&quot;alpha.in&quot;,&quot;r&quot;,stdin);
    // freopen(&quot;alpha.out&quot;,&quot;w&quot;,stdout);
    scanf(&quot;%d&quot;, &amp;amp;n);
    scanf(&quot;%s%s%s&quot;, a + 1, b + 1, c + 1);
    for (int i = &apos;A&apos;; i &amp;lt; &apos;A&apos; + n; i++)
        map[i] = -1;
    dfs(n, 0);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>NOIP模拟 超级树</title><link>https://www.nekomio.com/posts/106/</link><guid isPermaLink="true">https://www.nekomio.com/posts/106/</guid><pubDate>Fri, 15 Sep 2017 19:18:35 GMT</pubDate><content:encoded>&lt;h3&gt;3.1 描述&lt;/h3&gt;
&lt;p&gt;一棵k-超级树可按如下方法得到：取一棵深度为k的满二叉树，对每个节
点，向它的所有祖先连边（如果这条边不存在的话）。例如，下图是一个4-超
级树的例子：
&amp;lt;!--more--&amp;gt;
&lt;img src=&quot;https://i.loli.net/2017/09/15/59bbb7efc36c1.gif&quot; alt=&quot;tree.gif&quot; /&gt;
现在你的任务是统计一棵k-超级树中有多少条每个节点最多经过一次的不
同有向路径。两条路径被认为不同，当且仅当它们经过的节点的集合不同，或
经过的节点的顺序不同。由于答案可能很大，请输出总路径数对mod取模后的
结果。&lt;/p&gt;
&lt;h3&gt;3.2 输入&lt;/h3&gt;
&lt;p&gt;一行两个整数k、mod，意义见上。&lt;/p&gt;
&lt;h3&gt;3.3 输出&lt;/h3&gt;
&lt;p&gt;一行一个整数，代表答案&lt;/p&gt;
&lt;h3&gt;样例&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;输入&lt;/th&gt;
&lt;th&gt;输出&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2 100&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3 1000&lt;/td&gt;
&lt;td&gt;245&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20 998244353&lt;/td&gt;
&lt;td&gt;450500168&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;样例解释：对第一组样例，将节点如图编号，共有9条不同的路径：1, 2, 3, 1−
2, 2 − 1, 1 − 3, 3 − 1, 2 − 1 − 3, 3 − 1 − 2。
&lt;img src=&quot;https://i.loli.net/2017/09/15/59bbb8a0e55bc.png&quot; alt=&quot;tree1.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;限制与约定&lt;/h3&gt;
&lt;p&gt;对于10%的数据，k ≤ 4。
对于40%的数据，k ≤ 10。
对于60%的数据，k ≤ 100。
另有10%的数据，mod = 998244353。
对于所有数据，1 ≤ k ≤ 300，1 ≤ mod ≤ 109。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;考虑dp[i][j]表示一棵i-超级树，有j条点不重复的路径的方案数。
对于第二维表示有j条路径他们不相交的方案数
这记num=dp[i][l]*dp[i][r]&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dp[i+1][l+r]+=num  
dp[i+1][l+r+1]+=num  
dp[i+1][l+r]+=2*num*(l+r)  
dp[i+1][l+r-1]+=2*num*l*r  
dp[i+1][l+r-1]+=num*(l*(l-1)+r*(r-1))  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;dp[1][0]=dp[1][1]=1&lt;br /&gt;
答案为dp[k][1]&lt;/p&gt;
&lt;p&gt;因为我们发现每次转移的时候j最多会减1&lt;br /&gt;
所以我们只需要前k-i+1个状态&lt;br /&gt;
只DP这些状态就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
long long f[305][305];
int MOD;
int main()
{
	int k;
	scanf(&quot;%d%d&quot;, &amp;amp;k, &amp;amp;MOD);
	f[1][0] = f[1][1] = 1 % MOD;
	for (int i = 1; i &amp;lt; k; i++)
	{
		for (int l = 0; l &amp;lt;= k - i + 1; l++)
			for (int r = 0; r &amp;lt;= k - i + 1; r++)
			{
				long long num = f[i][l] * f[i][r] % MOD;
				if (r + l &amp;lt;= k - i)
				{
					f[i + 1][r + l] = (f[i + 1][r + l] + num) % MOD;
					f[i + 1][r + l] = (f[i + 1][r + l] + 2 * num * (l + r) % MOD) % MOD;
				}
				if (r + l + 1 &amp;lt;= k - i)
					f[i + 1][r + l + 1] = (f[i + 1][r + l + 1] + num) % MOD;
				if (r + l - 1 &amp;lt;= k - i)
				{
					f[i + 1][r + l - 1] = (f[i + 1][r + l - 1] + 2 * num * l * r % MOD) % MOD;
					f[i + 1][r + l - 1] = (f[i + 1][r + l - 1] + num * (l * (l - 1) + r * (r - 1)) % MOD) % MOD;
				}
			}
	}
	printf(&quot;%lld&quot;, f[k][1]);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[ZJOI2007]矩阵游戏</title><link>https://www.nekomio.com/posts/105/</link><guid isPermaLink="true">https://www.nekomio.com/posts/105/</guid><pubDate>Tue, 22 Aug 2017 17:12:21 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;小Q是一个非常聪明的孩子，除了国际象棋，他还很喜欢玩一个电脑益智游戏——矩阵游戏。矩阵游戏在一个N
*N黑白方阵进行（如同国际象棋一般，只是颜色是随意的）。每次可以对该矩阵进行两种操作：行交换操作：选择
矩阵的任意两行，交换这两行（即交换对应格子的颜色）列交换操作：选择矩阵的任意行列，交换这两列（即交换
对应格子的颜色）
&amp;lt;!--more--&amp;gt;
游戏的目标，即通过若干次操作，使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑
色。对于某些关卡，小Q百思不得其解，以致他开始怀疑这些关卡是不是根本就是无解的！！于是小Q决定写一个程
序来判断这些关卡是否有解。&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第一行包含一个整数T，表示数据的组数。接下来包含T组数据，每组数据第一行为一个整数N，表示方阵的大
小；接下来N行为一个N*N的01矩阵（0表示白色，1表示黑色）。&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输出文件应包含T行。对于每一组数据，如果该关卡有解，输出一行Yes；否则输出一行No。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;br /&gt;
2&lt;br /&gt;
0 0&lt;br /&gt;
0 1&lt;br /&gt;
3&lt;br /&gt;
0 0 1&lt;br /&gt;
0 1 0&lt;br /&gt;
1 0 0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;No&lt;br /&gt;
Yes&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【数据规模】&lt;/h3&gt;
&lt;p&gt;对于100%的数据，N ≤ 200&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;我们发现在同一行或同一列的一直在同一行或同一列。&lt;br /&gt;
所以这道题就是要求是否能找到不同行列的一个匹配覆盖n个点&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
struct edge
{
    int END, next;
}v[40005];
int first[205],p;
void add(int a,int b)
{
    v[p].END = b;
    v[p].next = first[a];
    first[a] = p++;
}
int link[205];
bool vis[205];
int find(int x)
{
    for (int i = first[x]; i != -1; i = v[i].next)
    {
        if(!vis[v[i].END])
        {
            vis[v[i].END] = 1;
            if(link[v[i].END]==-1||find(link[v[i].END]))
            {
                link[v[i].END] = x;
                return 1; 
            }
        }
    }
    return 0;
}
int main()
{
    int T, a;
    scanf(&quot;%d&quot;, &amp;amp;T);
    while (T--)
    {
        memset(first, -1, sizeof(first));
        p = 0;
        memset(link, -1, sizeof(link));
        int n;
        scanf(&quot;%d&quot;, &amp;amp;n);
        for (int i = 1; i &amp;lt;= n; i++)
            for (int j = 1; j &amp;lt;= n; j++)
            {
                scanf(&quot;%d&quot;, &amp;amp;a);
                if (a)
                    add(i, j);
            }
        int ans = 0;
        for (int i = 1; i &amp;lt;= n; i++)
        {
            memset(vis, 0, sizeof(vis));
            if (find(i))
                ans++;
        }
        if(ans == n)
            printf(&quot;Yes\n&quot;);
        else
            printf(&quot;No\n&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[HNOI2012]矿场搭建</title><link>https://www.nekomio.com/posts/104/</link><guid isPermaLink="true">https://www.nekomio.com/posts/104/</guid><pubDate>Tue, 22 Aug 2017 17:08:30 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见，希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口，使得无论哪一个挖煤点坍塌之后，其他挖煤点的工人都有一条道路通向救援出口。请写一个程序，用来计算至少需要设置几个救援出口，以及不同最少救援出口的设置方案总数。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;
输入
输入文件有若干组数据，每组数据的第一行是一个正整数 N（N≤500），表示工地的隧道数，接下来的 N 行每行是用空格隔开的两个整数 S 和 T，表示挖S 与挖煤点 T 由隧道直接连接。输入数据以 0 结尾。&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输入文件中有多少组数据，输出文件 output.txt 中就有多少行。每行对应一组输入数据的 结果。其中第 i 行以 Case i: 开始（注意大小写，Case 与 i 之间有空格，i 与:之间无空格，: 之后有空格），其后是用空格隔开的两个正整数，第一个正整数表示对于第 i 组输入数据至少需 要设置几个救援出口，第二个正整数表示对于第 i 组输入数据不同最少救援出口的设置方案总 数。输入数据保证答案小于 2^64。输出格式参照以下输入输出样例。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;9&lt;br /&gt;
1  3&lt;br /&gt;
4  1&lt;br /&gt;
3  5&lt;br /&gt;
1  2&lt;br /&gt;
2  6&lt;br /&gt;
1  5&lt;br /&gt;
6  3&lt;br /&gt;
1  6&lt;br /&gt;
3  2&lt;br /&gt;
6&lt;br /&gt;
1  2&lt;br /&gt;
1  3&lt;br /&gt;
2  4&lt;br /&gt;
2  5&lt;br /&gt;
3  6&lt;br /&gt;
3  7&lt;br /&gt;
0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Case 1: 2 4&lt;br /&gt;
Case 2: 4 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;可也看出如果塌在割点才有影响&lt;br /&gt;
所以先跑出所以割点，然后删去割点跑联通块&lt;br /&gt;
如果一个块有两个割点那么无所谓。
否则建一个方案为点数&lt;/p&gt;
&lt;p&gt;最后如果只要一个联通块，那么就要两个点。方案数为n*（n-1）/2&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
struct edge
{
    int END, next;
} v[10005];
int first[500], p;
void add(int a, int b)
{
    v[p].END = b;
    v[p].next = first[a];
    first[a] = p++;
}
int dfn[500], low[500], Index;
bool iscut[500];
void Tarjan(int x, int fa)
{
    low[x] = dfn[x] = ++Index;
    int S = 0;
    for (int i = first[x]; i != -1; i = v[i].next)
    {
        if (!dfn[v[i].END])
        {
            S++;
            Tarjan(v[i].END, x);
            low[x] = min(low[v[i].END], low[x]);
            if (low[v[i].END] &amp;gt;= dfn[x])
                iscut[x] = 1;
        }
        else
            low[x] = min(low[x], dfn[v[i].END]);
    }
    if (fa &amp;lt; 0 &amp;amp;&amp;amp; S == 1)
        iscut[x] = 0;
}
bool vis[500];
int T, size, num;
int color[500];
void dfs(int x)
{
    vis[x] = 1;
    size++;
    for (int i = first[x]; i != -1; i = v[i].next)
    {
        if (!vis[v[i].END])
        {
            if (!iscut[v[i].END])
                dfs(v[i].END);
            else
            {
                if (color[v[i].END] != T)
                    color[v[i].END] = T, num++;
            }
        }
    }
}
int main()
{
    //freopen(&quot;bzoj_2730.in&quot;,&quot;r&quot;,stdin);
    //freopen(&quot;bzoj_2730.out&quot;,&quot;w&quot;,stdout);
    int P1 = 0;
    while (1)
    {
        memset(vis, 0, sizeof(vis));
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(iscut, 0, sizeof(iscut));
        memset(first, -1, sizeof(first));
        memset(color, 0, sizeof(color));
        p = 0;
        Index = 0;
        P1++;
        int n = 0, a, b, m;
        scanf(&quot;%d&quot;, &amp;amp;m);
        if (m == 0)
            break;
        for (int i = 1; i &amp;lt;= m; i++)
        {
            scanf(&quot;%d%d&quot;, &amp;amp;a, &amp;amp;b);
            n = max(a, n);
            n = max(b, n);
            add(a, b);
            add(b, a);
        }
        for (int i = 1; i &amp;lt;= n; i++)
            if (!dfn[i])
                Tarjan(i, -1);
        int ans1 = 0;
        long long ans2 = 1;
        T = 0;
        for (int i = 1; i &amp;lt;= n; i++)
        {
            if (!vis[i] &amp;amp;&amp;amp; !iscut[i])
            {
                T++, size = 0, num = 0;
                dfs(i);
                if (num == 1)
                    ans1++, ans2 *= size;
            }
        }
        if (T == 1)
            ans1 = 2, ans2 = n * (n - 1) / 2;
        printf(&quot;Case %d: %d %lld\n&quot;, P1, ans1, ans2);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[NOI2014]魔法森林</title><link>https://www.nekomio.com/posts/103/</link><guid isPermaLink="true">https://www.nekomio.com/posts/103/</guid><pubDate>Tue, 22 Aug 2017 16:59:12 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;为了得到书法大家的真传，小E同学下定决心去拜访住在魔法森林中的隐士。魔法森林可以被看成一个包含个N节点M条边的无向图，节点标号为1..N，边标号为1..M。初始时小E同学在号节点1，隐士则住在号节点N。小E需要通过这一片魔法森林，才能够拜访到隐士。
&amp;lt;!--more--&amp;gt;
魔法森林中居住了一些妖怪。每当有人经过一条边的时候，这条边上的妖怪就会对其发起攻击。幸运的是，在号节点住着两种守护精灵：A型守护精灵与B型守护精灵。小E可以借助它们的力量，达到自己的目的。&lt;/p&gt;
&lt;p&gt;只要小E带上足够多的守护精灵，妖怪们就不会发起攻击了。具体来说，无向图中的每一条边Ei包含两个权值Ai与Bi。若身上携带的A型守护精灵个数不少于Ai，且B型守护精灵个数不少于Bi，这条边上的妖怪就不会对通过这条边的人发起攻击。当且仅当通过这片魔法森林的过程中没有任意一条边的妖怪向小E发起攻击，他才能成功找到隐士。&lt;/p&gt;
&lt;p&gt;由于携带守护精灵是一件非常麻烦的事，小E想要知道，要能够成功拜访到隐士，最少需要携带守护精灵的总个数。守护精灵的总个数为A型守护精灵的个数与B型守护精灵的个数之和。&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第1行包含两个整数N,M，表示无向图共有N个节点，M条边。 接下来M行，第行包含4个正整数Xi,Yi,Ai,Bi，描述第i条无向边。其中Xi与Yi为该边两个端点的标号，Ai与Bi的含义如题所述。 注意数据中可能包含重边与自环。&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输出一行一个整数：如果小E可以成功拜访到隐士，输出小E最少需要携带的守护精灵的总个数；如果无论如何小E都无法拜访到隐士，输出“-1”（不含引号）。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;【输入样例1】&lt;br /&gt;
4 5&lt;br /&gt;
1 2 19 1&lt;br /&gt;
2 3 8 12&lt;br /&gt;
2 4 12 15&lt;br /&gt;
1 3 17 8&lt;br /&gt;
3 4 1 17&lt;br /&gt;
【输入样例2】&lt;br /&gt;
3 1&lt;br /&gt;
1 2 1 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;【输出样例1】&lt;br /&gt;
32&lt;br /&gt;
【样例说明1】&lt;br /&gt;
如果小E走路径1→2→4，需要携带19+15=34个守护精灵；&lt;br /&gt;
如果小E走路径1→3→4，需要携带17+17=34个守护精灵；&lt;br /&gt;
如果小E走路径1→2→3→4，需要携带19+17=36个守护精灵；&lt;br /&gt;
如果小E走路径1→3→2→4，需要携带17+15=32个守护精灵。&lt;br /&gt;
综上所述，小E最少需要携带32个守护精灵。&lt;br /&gt;
【输出样例2】&lt;br /&gt;
-1&lt;br /&gt;
【样例说明2】&lt;br /&gt;
小E无法从1号节点到达3号节点，故输出-1。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;对一个权值排序&lt;br /&gt;
从小到大逐渐加边维护答案&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;queue&amp;gt;
using namespace std;
struct data
{
    int s, e, a, b;
    bool operator&amp;lt;(const data &amp;amp;c) const
    {
        return a &amp;lt; c.a;
    }
} a[100005];
struct edge
{
    int END, v, next;
} v[200005];
int first[50005], p;
void add(int s, int e, int c)
{
    v[p].END = e;
    v[p].v = c;
    v[p].next = first[s];
    first[s] = p++;
}
bool flag[50005];
queue&amp;lt;int&amp;gt; Q;
int dis[50005];
void spfa()
{
    while (!Q.empty())
    {
        int k = Q.front();
        Q.pop();
        flag[k] = 0;
        for (int i = first[k]; i != -1; i = v[i].next)
        {
            if (dis[v[i].END] &amp;gt; max(dis[k], v[i].v))
            {
                dis[v[i].END] = max(dis[k], v[i].v);
                if (!flag[v[i].END])
                {
                    flag[v[i].END] = 1;
                    Q.push(v[i].END);
                }
            }
        }
    }
}
int main()
{
    memset(first, -1, sizeof(first));
    int n, m;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d%d%d%d&quot;, &amp;amp;a[i].s, &amp;amp;a[i].e, &amp;amp;a[i].a, &amp;amp;a[i].b);
    }
    sort(a + 1, a + m + 1);
    memset(dis, 0x3f, sizeof(dis));
    dis[1] = 0;
    int ans = 0x3f3f3f3f;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        add(a[i].s, a[i].e, a[i].b);
        add(a[i].e, a[i].s, a[i].b);
        if (!flag[a[i].s])
        {
            Q.push(a[i].s);
            flag[a[i].s] = 1;
        }
        if (!flag[a[i].e])
        {
            Q.push(a[i].e);
            flag[a[i].e] = 1;
        }
        if (a[i + 1].a != a[i].a)
            spfa();
        ans = min(ans, a[i].a + dis[n]);
    }
    if (ans == 0x3f3f3f3f)
        puts(&quot;-1&quot;);
    else
        printf(&quot;%d\n&quot;,ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>生日有感</title><link>https://www.nekomio.com/posts/102/</link><guid isPermaLink="true">https://www.nekomio.com/posts/102/</guid><pubDate>Mon, 21 Aug 2017 15:44:30 GMT</pubDate><content:encoded>&lt;h2&gt;生日有感&lt;/h2&gt;
&lt;p&gt;其实这是我在这个学校过的第二个生日了，
只有两句祝福，但也让我很是高兴。&lt;/p&gt;
&lt;p&gt;心中略有一丝伤感但更多的是希望，&lt;br /&gt;
我只希望：&lt;br /&gt;
下一次，就下一次，我的生日，能在家过。&lt;/p&gt;
&lt;p&gt;感谢亲爱的爸爸妈妈 和 关心我的同学们。&lt;/p&gt;
</content:encoded></item><item><title>约会</title><link>https://www.nekomio.com/posts/99/</link><guid isPermaLink="true">https://www.nekomio.com/posts/99/</guid><pubDate>Tue, 15 Aug 2017 20:41:52 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/15/5992ec3e4b26c.jpg&quot; alt=&quot;20170813082855_58428.jpg&quot; /&gt;
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入输出&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/15/5992ec6af30e1.jpg&quot; alt=&quot;20170813082918_26068.jpg&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;4&lt;br /&gt;
1 2&lt;br /&gt;
1 3&lt;br /&gt;
2 4&lt;br /&gt;
1&lt;br /&gt;
2 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;提示&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/15/5992ec9ab7a7d.jpg&quot; alt=&quot;20170813083005_18558.jpg&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;先建出树来，顺便求出每个节点所在子树的size&lt;/p&gt;
&lt;p&gt;然后对于每一个询问我们先跑LCA&lt;br /&gt;
然后通过树上倍增求出他们的中点&lt;br /&gt;
如果他是LCA那么ans = n - size(有起点的儿子) - size(有终点的儿子)&lt;br /&gt;
否则 ans = size（mid） - size（有起点的儿子） - size（有终点的儿子）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
struct edge
{
    int END, next;
} v[200005];
int first[100005], p, n;
void add(int a, int b)
{
    v[p].END = b;
    v[p].next = first[a];
    first[a] = p++;
}
int size[100005];
int f[100005][30];
int dep[100005];
void dfs(int rt, int fa, int dp)
{
    dep[rt] = dp;
    f[rt][0] = fa;
    for (int i = 1; i &amp;lt;= 20; i++)
        f[rt][i] = f[f[rt][i - 1]][i - 1];
    size[rt] = 1;
    for (int i = first[rt]; i != -1; i = v[i].next)
        if (v[i].END != fa)
        {
            dfs(v[i].END, rt, dp + 1);
            size[rt] += size[v[i].END];
        }
}
int LCA(int a, int b)
{
    if (dep[a] &amp;lt; dep[b])
        swap(a, b);
    int t = dep[a] - dep[b];
    for (int i = 20; i &amp;gt;= 0; i--)
        if (t &amp;amp; (1 &amp;lt;&amp;lt; i))
            a = f[a][i];
    if (a == b)
        return a;
    for (int i = 20; i &amp;gt;= 0; i--)
        if (f[a][i] != f[b][i])
            a = f[a][i], b = f[b][i];
    return f[a][0];
}
int Query(int a, int b)
{
    if (a == b)
        return n;
    if (dep[a] &amp;lt; dep[b])
        swap(a, b);
    int Lca = LCA(a, b);
    int l = dep[a] - dep[Lca];
    int r = dep[b] - dep[Lca];
    if ((l + r) &amp;amp; 1)
        return 0;
    int mid = l + r &amp;gt;&amp;gt; 1;
    int k = a;
    for (int i = 20; i &amp;gt;= 0; i--)
        if (mid &amp;amp; (1 &amp;lt;&amp;lt; i))
            k = f[k][i];
    if (k == Lca)
    {
        int t = dep[a] - dep[Lca] - 1;
        for (int i = 20; i &amp;gt;= 0; i--)
            if (t &amp;amp; (1 &amp;lt;&amp;lt; i))
                a = f[a][i], b = f[b][i];
        return n - size[a] - size[b];
    }
    else
    {
        int t = dep[a] - dep[k] - 1;
        for (int i = 20; i &amp;gt;= 0; i--)
            if (t &amp;amp; (1 &amp;lt;&amp;lt; i))
                a = f[a][i];
        return size[k] - size[a];
    }
}
int main(int argc, char const *argv[])
{
    memset(first,-1,sizeof(first));
    int a, b;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt; n; i++)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;a, &amp;amp;b);
        add(a, b);
        add(b, a);
    }
    dfs(1, 0, 0);
    int m;
    scanf(&quot;%d&quot;,&amp;amp;m);
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;a, &amp;amp;b);
        printf(&quot;%d\n&quot;, Query(a, b));
    }
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>中值滤波</title><link>https://www.nekomio.com/posts/98/</link><guid isPermaLink="true">https://www.nekomio.com/posts/98/</guid><pubDate>Tue, 15 Aug 2017 20:35:36 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/15/5992eafa9664e.jpg&quot; alt=&quot;20170813082609_40094.jpg&quot; /&gt;
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入输出&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/15/5992eb25abd31.jpg&quot; alt=&quot;20170813082630_74802.jpg&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;br /&gt;
0 1 0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1&lt;br /&gt;
0 0 0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;提示&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/15/5992eb7e84c7e.jpg&quot; alt=&quot;20170813082722_12263.jpg&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;先打表&lt;/p&gt;
&lt;p&gt;会发现规律然后我们按照规律模拟就可以了&lt;/p&gt;
&lt;p&gt;具体的可以看代码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
int a[500005], b[500005];
int main()
{
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++)
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
    a[n+1]=a[n];
    int i = 1, l, r;
    int ans = 0;
    while (i &amp;lt;= n)
    {
        while (i &amp;lt;= n &amp;amp;&amp;amp; a[i] == a[i + 1])
        {
            b[i] = a[i];
            i++;
        }
        l = i;
        while (i &amp;lt;= n &amp;amp;&amp;amp; a[i] != a[i + 1])
            i++;
        r = i;
        int len = (r - l + 1);
        if (len &amp;amp; 1)
            for (int j = l; j &amp;lt;= r; j++)
                b[j] = a[l];
        else
            for (int j = 1; j * 2 &amp;lt;= len; j++)
                b[l + j - 1] = a[l], b[r - j + 1] = a[r];
        ans = max(ans, (len - 1) / 2);
    }
    printf(&quot;%d\n&quot;, ans);
    for (int i = 1; i &amp;lt;= n; i++)
        printf(&quot;%d &quot;, b[i]);
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>最长上升子串</title><link>https://www.nekomio.com/posts/97/</link><guid isPermaLink="true">https://www.nekomio.com/posts/97/</guid><pubDate>Tue, 15 Aug 2017 20:31:52 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/15/5992e9d597a7f.jpg&quot; alt=&quot;20170813082258_37990.jpg&quot; /&gt;
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;6&lt;br /&gt;
7 2 3 1 5 6&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/15/5992e9d596d0d.jpg&quot; alt=&quot;20170813082405_16233.jpg&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;直接DP就可以了&lt;br /&gt;
很水了&lt;br /&gt;
打的有点傻&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
int f[300005][2][2], a[300005];
bool change[300005];
int main()
{
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++)
        scanf(&quot;%d&quot;, a + i);
    a[0] = -1;
    int ans = 0;
    f[1][0][0] = 1;
    f[1][0][1] = 0;
    f[1][1][1] = 1;
    f[1][1][0] = 0;
    for (int i = 2; i &amp;lt;= n; i++)
    {
        f[i][0][0] = 1;
        f[i][0][1] = 1;
        f[i][1][1] = 1;
        f[i][1][0] = 0;
        if (a[i] &amp;gt; a[i - 1])
        {
            f[i][0][0] = f[i - 1][0][0] + 1;
            f[i][0][1] = f[i - 1][0][1] + 1;
        }
        if (f[i - 1][1][1] == f[i - 2][0][0] + 1)
        {
            if(a[i] &amp;gt; a[i - 2] + 1)
            {
                f[i][0][1] = max(f[i][0][1], f[i - 1][1][1] + 1);
            }
        }
        else
        {
            f[i][0][1] = max(f[i][0][1], f[i - 1][1][1]);
        }
        f[i][1][1] = max(f[i][1][1], f[i - 1][0][0] + 1);
        ans = max(ans,max(f[i][0][0],max(f[i][0][1],f[i][1][1])));
    }
    printf(&quot;%d&quot;,ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>便</title><link>https://www.nekomio.com/posts/101/</link><guid isPermaLink="true">https://www.nekomio.com/posts/101/</guid><pubDate>Tue, 15 Aug 2017 20:15:35 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;给出一个R*C的棋盘.共有R行C列,R*C个格子.现要在每个格子都填一个非负整数.使得任意一个2*2的正方形区域都满足这样的性质:左上角的数字+右下角的数字=左下角的数字+右上角的数字.有些格子已经确定,你不能更改其中的数字.其他格子的数字由你决定.
这是一个符合要求的3*3的棋盘:
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;不难验证每个2*2的区域都是符合要求的.
Orbitingflea想要知道一个可行的填充棋盘的方案.但是这个方案可能很大.所以你只需对给定的棋盘判定是否存在至少一种可行的填充棋盘的方案.&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第一行输入一个T，表示数据组数。接下来T组数据。&lt;/p&gt;
&lt;p&gt;每组数据的第1行2个整数R,C表示棋盘的大小.&lt;/p&gt;
&lt;p&gt;第2行1个整数n表示已经被填好数字的格子的数目.&lt;/p&gt;
&lt;p&gt;接下来n行每行3个整数ri,ci,ai,表示第ri行ci列的格子被填上了数字ai.&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;T行.第i行是第i组数据的答案.有合法方案时输出一行Yes,没有时输出一行No.&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;6&lt;br /&gt;
2 2 3&lt;br /&gt;
1 1 0&lt;br /&gt;
1 2 10&lt;br /&gt;
2 1 20&lt;br /&gt;
2 3 5&lt;br /&gt;
1 1 0&lt;br /&gt;
1 2 10&lt;br /&gt;
1 3 20&lt;br /&gt;
2 1 30&lt;br /&gt;
2 3 40&lt;br /&gt;
2 2 3&lt;br /&gt;
1 1 20&lt;br /&gt;
1 2 10&lt;br /&gt;
2 1 0&lt;br /&gt;
3 3 4&lt;br /&gt;
1 1 0&lt;br /&gt;
1 3 10&lt;br /&gt;
3 1 10&lt;br /&gt;
3 3 20&lt;br /&gt;
2 2 4&lt;br /&gt;
1 1 0&lt;br /&gt;
1 2 10&lt;br /&gt;
2 1 30&lt;br /&gt;
2 2 20&lt;br /&gt;
1 1 1&lt;br /&gt;
1 1 -1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Yes&lt;br /&gt;
No&lt;br /&gt;
No&lt;br /&gt;
Yes&lt;br /&gt;
No&lt;br /&gt;
No&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;每一列差分后得到的结果相同.每一行差分后的
结果也相同.于是我们对行列分别用带权并查集维护行之间,列之间的差分关系.如果差分关系出现矛盾(两行之间的差
值可以推导出两种可能)则无解.如果差分关系没有矛盾,则需要求出整个矩阵中能推导出的最小值判断是否小于0.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
int fa1[1000005], fa2[1000005];
long long w1[1000005], w2[1000005];
long long Min1[1000005], Min2[1000005];
struct Point
{
    int x, y, v;
} a[1000005];
bool cmpx(const Point &amp;amp;A, const Point &amp;amp;B)
{
    return A.x &amp;lt; B.x;
}
bool cmpy(const Point &amp;amp;A, const Point &amp;amp;B)
{
    return A.y &amp;lt; B.y;
}
int find1(int x)
{
    if (x == fa1[x])
        return x;
    int rt = find1(fa1[x]);
    w1[x] += w1[fa1[x]];
    return fa1[x] = rt;
}
int find2(int x)
{
    if (x == fa2[x])
        return x;
    int rt = find2(fa2[x]);
    w2[x] += w2[fa2[x]];
    return fa2[x] = rt;
}
bool link1(int a, int b, int w)
{
    if (find1(a) != find1(b))
    {
        int fa = find1(a), fb = find1(b);
        fa1[fa] = fa1[fb];
        w1[fa] = w + w1[b] - w1[a];
        return 1;
    }
    else
        return w1[a] == w + w1[b];
}
bool link2(int a, int b, int w)
{
    if (find2(a) != find2(b))
    {
        int fa = find2(a), fb = find2(b);
        fa2[fa] = fa2[fb];
        w2[fa] = w + w2[b] - w2[a];
        return 1;
    }
    else
        return w2[a] == w + w2[b];
}
int main()
{
    int T;
    scanf(&quot;%d&quot;, &amp;amp;T);
    while (T--)
    {
        bool flag = 1;
        int R, C;
        scanf(&quot;%d%d&quot;, &amp;amp;R, &amp;amp;C);
        for (int i = 1; i &amp;lt;= R; i++)
        {
            fa1[i] = i;
            w1[i] = 0;
        }
        for (int i = 1; i &amp;lt;= C; i++)
        {
            fa2[i] = i;
            w2[i] = 0;
        }
        int n;
        scanf(&quot;%d&quot;, &amp;amp;n);
        for (int i = 1; i &amp;lt;= n; i++)
            scanf(&quot;%d%d%d&quot;, &amp;amp;a[i].x, &amp;amp;a[i].y, &amp;amp;a[i].v);
        for (int i = 1; i &amp;lt;= n; i++)
            if (a[i].v &amp;lt; 0)
                flag = 0;
        sort(a + 1, a + n + 1, cmpx);
        for (int i = 1; i &amp;lt; n; i++)
            if (a[i].x == a[i + 1].x)
                if (!link2(a[i].y, a[i + 1].y, a[i + 1].v - a[i].v))
                    flag = false;
 
        sort(a + 1, a + n + 1, cmpy);
        for (int i = 1; i &amp;lt; n; i++)
            if (a[i].y == a[i + 1].y)
                if (!link1(a[i].x, a[i + 1].x, a[i + 1].v - a[i].v))
                    flag = false;
 
        memset(Min1, 0x3f, sizeof(Min1));
        memset(Min2, 0x3f, sizeof(Min2));
        for (int i = 1; i &amp;lt;= n; i++)
        {
            int rt = find1(a[i].x);
            Min1[rt] = min(Min1[rt], a[i].v + w1[a[i].x]);
        }
        for (int i = 1; i &amp;lt;= R; i++)
        {
            int rt = find1(i);
            Min2[rt] = min(Min2[rt], -w1[i]);
        }
        for (int i = 1; i &amp;lt;= R; i++)
        {
            if (fa1[i] == i &amp;amp;&amp;amp; Min1[i] + Min2[i] &amp;lt; 0)
                flag = 0;
        }
        if(flag)
            puts(&quot;Yes&quot;);
        else
            puts(&quot;No&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[Haoi2016]字符合并</title><link>https://www.nekomio.com/posts/100/</link><guid isPermaLink="true">https://www.nekomio.com/posts/100/</guid><pubDate>Tue, 15 Aug 2017 20:14:12 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;有一个长度为 n 的 01 串，你可以每次将相邻的 k 个字符合并，得到一个新的字符并获得一定分数。得到的新字
符和分数由这 k 个字符确定。你需要求出你能获得的最大分数。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第一行两个整数n，k。接下来一行长度为n的01串，表示初始串。接下来2k行，每行一个字符ci和一个整数wi，ci
表示长度为k的01串连成二进制后按从小到大顺序得到的第i种合并方案得到的新字符,wi表示对应的第i种方案对应
获得的分数。1&amp;lt;=n&amp;lt;=300,0&amp;lt;=ci&amp;lt;=1,wi&amp;gt;=1,k&amp;lt;=8&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输出一个整数表示答案&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3 2&lt;br /&gt;
101&lt;br /&gt;
1 10&lt;br /&gt;
1 10&lt;br /&gt;
0 20&lt;br /&gt;
1 30&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;40&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;//第3行到第6行表示长度为2的4种01串合并方案。00-&amp;gt;1,得10分，01-&amp;gt;1得10分，10-&amp;gt;0得20分，11-&amp;gt;1得30分。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;令f[i][j][S]表示将i~j这一段消到S这个状态能获得的最大得分。&lt;br /&gt;
f[i][j][S&amp;lt;&amp;lt;1]=max(f[i][j][S&amp;lt;&amp;lt;1],f[i][m−1][S]+f[m][j][0])&lt;br /&gt;
f[i][j][S&amp;lt;&amp;lt;1|1]=max(f[i][j][S&amp;lt;&amp;lt;1|1],f[i][m−1][S]+f[m][j][1])&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;bitset&amp;gt;
using namespace std;
int a[400], c;
int s[1 &amp;lt;&amp;lt; 8];
long long w[1 &amp;lt;&amp;lt; 8], f[305][305][1 &amp;lt;&amp;lt; 8], INF, ans;
int main()
{
    // freopen(&quot;merge.in&quot;,&quot;r&quot;,stdin);
    // freopen(&quot;merge.out&quot;,&quot;w&quot;,stdout);
    int n, k;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;k);
    for (int i = 1; i &amp;lt;= n; i++)
        scanf(&quot;%1d&quot;, &amp;amp;a[i]);
    for (int i = 0; i &amp;lt; (1 &amp;lt;&amp;lt; k); i++)
        scanf(&quot;%d%lld&quot;, &amp;amp;s[i], &amp;amp;w[i]);
    memset(f, 0x80, sizeof(f));
    memset(&amp;amp;INF, 0x80, sizeof(INF));
    for (int i = 1; i &amp;lt;= n; i++)
        f[i][i][a[i]] = 0;
    for (int l = 2; l &amp;lt;= n; l++)
    {
        for (int i = 1; i &amp;lt;= n - l + 1; i++)
        {
            int j = i + l - 1;
            int len = j - i;
            while (len &amp;gt;= k)
                len -= k - 1;
            for (int m = j; m &amp;gt; i; m -= k - 1)
            {
                for (int S = 0; S &amp;lt; (1 &amp;lt;&amp;lt; len); S++)
                {
                    if (f[i][m - 1][S] != INF)
                    {
                        if (f[m][j][0] != INF)
                            f[i][j][S &amp;lt;&amp;lt; 1] = max(f[i][j][S &amp;lt;&amp;lt; 1], f[i][m - 1][S] + f[m][j][0]);
                        if (f[m][j][1] != INF)
                            f[i][j][S &amp;lt;&amp;lt; 1 | 1] = max(f[i][j][S &amp;lt;&amp;lt; 1 | 1], f[i][m - 1][S] + f[m][j][1]);
                    }
                }
            }
            if (len == k - 1)
            {
                long long g[2];
                g[0] = g[1] = INF;
                for (int S = 0; S &amp;lt; (1 &amp;lt;&amp;lt; k); S++)
                    if (f[i][j][S] != INF)
                        g[s[S]] = max(g[s[S]], f[i][j][S] + w[S]);
                f[i][j][0] = g[0];
                f[i][j][1] = g[1];
            }
        }
    }
    for (int i = 0; i &amp;lt; (1 &amp;lt;&amp;lt; k); i++)
        ans = max(ans, f[1][n][i]);
    printf(&quot;%lld\n&quot;, ans);
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>从N方到NlogN的转变——FFT</title><link>https://www.nekomio.com/posts/96/</link><guid isPermaLink="true">https://www.nekomio.com/posts/96/</guid><pubDate>Mon, 14 Aug 2017 21:24:58 GMT</pubDate><content:encoded>&lt;h2&gt;1.Why&lt;/h2&gt;
&lt;p&gt;为什么我们信息学竞赛要用到FFT&lt;br /&gt;
因为我们要优化卷积啊&lt;br /&gt;
将n边为log是一个非常大的优化啊&lt;br /&gt;
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;What&lt;/h2&gt;
&lt;p&gt;什么是FFT呢
在&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E5%BF%AB%E9%80%9F%E5%82%85%E9%87%8C%E5%8F%B6%E5%8F%98%E6%8D%A2&quot;&gt;wiki&lt;/a&gt;上是这么说的&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;快速傅里叶变换（英语：Fast Fourier Transform, FFT），是计算序列的离散傅里叶变换（DFT）或其逆变换的一种算法。傅里叶分析将信号从原始域（通常是时间或空间）转换到频域的表示或者逆过来转换。FFT会通过把DFT矩阵分解为稀疏（大多为零）因子之积来快速计算此类变换。[1] 因此，它能够将计算DFT的复杂度从只用DFT定义计算需要的 $O(n^{2})$，降低到 $O(n\log n)$，其中 n 为数据大小。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;啥你说啥我听不懂（黑人问号?）&lt;/p&gt;
&lt;p&gt;如果简单的说就是求两个多项式的乘积&lt;/p&gt;
&lt;h2&gt;How&lt;/h2&gt;
&lt;p&gt;其实关于FFT的具体理论很复杂，我一篇博客肯定不能接受清楚
所以请有兴趣的人移步Google 或 baidu&lt;/p&gt;
&lt;p&gt;如果简单来说FFT用的分制的方法&lt;br /&gt;
所以才能有log啊&lt;/p&gt;
&lt;p&gt;将一个多项式按奇偶分开&lt;br /&gt;
但如果我们直接找值去计算时间复杂度还是$O(n^2)$的&lt;/p&gt;
&lt;p&gt;所以出现了一个特殊的东西他叫做n次单位根&lt;/p&gt;
&lt;p&gt;然后利用他的性质就可以搞了&lt;/p&gt;
&lt;p&gt;先贴两个板子&lt;/p&gt;
&lt;p&gt;UOJ 34 多项式乘法&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
using namespace std;
const int maxn = 1 &amp;lt;&amp;lt; 18 | 5;
namespace FFT
{
const double pi = acos(-1.0);
struct Complex
{
    double x, y;
    Complex operator+(const Complex &amp;amp;a)
    {
        return (Complex){x + a.x, y + a.y};
    }
    Complex operator-(const Complex &amp;amp;a)
    {
        return (Complex){x - a.x, y - a.y};
    }
    Complex operator*(const Complex &amp;amp;a)
    {
        return (Complex){x * a.x - y * a.y, x * a.y + y * a.x};
    }
    Complex operator*(const double &amp;amp;a)
    {
        return (Complex){x * a, y * a};
    }
    Complex Get()
    {
        return (Complex){x, -y};
    }
} c[maxn], c1[maxn], V = (Complex){0.5, 0} * (Complex){0, -0.5};
int rev[maxn], N, FU;
double Inv;
void FFt(Complex *a, int op)
{
    Complex w, wn, t;
    for (int i = 0; i &amp;lt; N; i++)
        if (i &amp;lt; rev[i])
            swap(a[i], a[rev[i]]);
    for (int k = 2; k &amp;lt;= N; k &amp;lt;&amp;lt;= 1)
    {
        wn = (Complex){cos(op * 2 * pi / k), sin(op * 2 * pi / k)};
        for (int j = 0; j &amp;lt; N; j += k)
        {
            w = (Complex){1, 0};
            for (int i = 0; i &amp;lt; (k &amp;gt;&amp;gt; 1); i++, w = w * wn)
            {
                t = a[i + j + (k &amp;gt;&amp;gt; 1)] * w;
                a[i + j + (k &amp;gt;&amp;gt; 1)] = a[i + j] - t;
                a[i + j] = a[i + j] + t;
            }
        }
    }
    if (op == -1)
        for (int i = 0; i &amp;lt; N; i++)
            a[i] = a[i] * Inv;
}
void FFt(int *a, int *b, int *res, int n)
{
    int j;
    N = 1;
    while (N &amp;lt; n)
        N &amp;lt;&amp;lt;= 1;
    FU = N - 1;
    Inv = 1. / N;
    for (int i = 0; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    for (int i = 0; i &amp;lt; N; i++)
        c[i].x = a[i], c[i].y = b[i];
    FFt(c, 1);
    for (int i = 0; i &amp;lt; N; i++)
        j = (N - i) &amp;amp; FU, c1[i] = (c[i] + c[j].Get()) * (c[i] - c[j].Get()) * V;
    FFt(c1, -1);
    for (int i = 0; i &amp;lt; N; i++)
        res[i] = round(c1[i].x);
}
} // FFT

int main(int argc, char const *argv[])
{
    static int a[maxn],b[maxn];
    int n1, n2, m;
    scanf(&quot;%d%d&quot;, &amp;amp;n1, &amp;amp;n2);
    m = n1 + n2 + 1;
    for (int i = 0; i &amp;lt;= n1; i++)
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
    for (int i = 0; i &amp;lt;= n2; i++)
        scanf(&quot;%d&quot;, &amp;amp;b[i]);
    FFT::FFt(a, b, a, m);
    for (int i = 0; i &amp;lt; m; i++)
        printf(&quot;%d &quot;, a[i]);
    return 0;
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;COGS 1473. 很强的乘法问题&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
const double pi = acos(-1.);
struct Complex
{
    double x, y;
    Complex() { ; }
    Complex(double a, double b) : x(a), y(b) {}
    Complex operator+(const Complex &amp;amp;a) { return Complex(x + a.x, y + a.y); }
    Complex operator-(const Complex &amp;amp;a) { return Complex(x - a.x, y - a.y); }
    Complex operator*(const Complex &amp;amp;a) { return Complex(x * a.x - y * a.y, x * a.y + y * a.x); }
    Complex operator*(const double a) { return Complex(x * a, y * a); }
    Complex Get() { return Complex(x, -y); }
} A[150005 &amp;lt;&amp;lt; 3], B[150005 &amp;lt;&amp;lt; 3];
int rev[150005 &amp;lt;&amp;lt; 3], N, FU;
double INV;
void FFt(Complex *a, int op)
{
    Complex w, wn, t;
    for (int i = 0; i &amp;lt; N; i++)
        if (i &amp;lt; rev[i])
            std::swap(a[i], a[rev[i]]);
    for (int k = 2; k &amp;lt;= N; k &amp;lt;&amp;lt;= 1)
    {
        wn = Complex(cos(op * 2 * pi / k), sin(op * 2 * pi / k));
        for (int j = 0; j &amp;lt; N; j += k)
        {
            w = Complex(1, 0);
            for (int i = 0; i &amp;lt; (k &amp;gt;&amp;gt; 1); i++, w = w * wn)
            {
                t = a[i + j + (k &amp;gt;&amp;gt; 1)] * w;
                a[i + j + (k &amp;gt;&amp;gt; 1)] = a[i + j] - t;
                a[i + j] = a[i + j] + t;
            }
        }
    }
    if (op == -1)
        for (int i = 0; i &amp;lt; N; i++)
            a[i] = a[i] * INV;
}
void FFt(const int *a, const int *b, int *res, int n)
{
    N = 1;
    while (N &amp;lt; n)
        N &amp;lt;&amp;lt;= 1;
    INV = 1. / N;
    for (int i = 0; i &amp;lt; N; i++)
        if (i &amp;amp; 1)
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1) | (N &amp;gt;&amp;gt; 1);
        else
            rev[i] = (rev[i &amp;gt;&amp;gt; 1] &amp;gt;&amp;gt; 1);
    for (int i = 0; i &amp;lt; N; i++)
        A[i].x = a[i], B[i].x = b[i];
    FFt(A, 1), FFt(B, 1);
    for (int i = 0; i &amp;lt; N; i++)
        A[i] = A[i] * B[i];
    FFt(A, -1);
    for (int i = 0; i &amp;lt; N; i++)
        res[i] = round(A[i].x);
}
char s[150005 &amp;lt;&amp;lt; 2];
struct BigNum
{
    int len;
    int a[1000005];
    void read()
    {
        scanf(&quot;%s&quot;, s);
        len = strlen(s);
        for (int i = len - 1, j = 0; i &amp;gt;= 0; i--, j++)
            a[j] = s[i] - &apos;0&apos;;
    }
    BigNum operator*(const BigNum &amp;amp;b)
    {
        BigNum ans;
        ans.len = len + b.len - 1;
        FFt(a, b.a, ans.a, ans.len + 1);
        for (int i = 0; i &amp;lt;= ans.len + 2; i++)
        {
            if (ans.a[i] &amp;gt; 9)
            {
                ans.a[i + 1] += ans.a[i] / 10;
                ans.a[i] %= 10;
            }
        }
        while (ans.a[ans.len])
            ans.len++;
        return ans;
    }
    void print()
    {
        for (int i = len - 1; i &amp;gt;= 0; i--)
            printf(&quot;%d&quot;, a[i]);
        printf(&quot;\n&quot;);
    }
} a, b;
 
int main()
{
    freopen(&quot;bettermul.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;bettermul.out&quot;,&quot;w&quot;,stdout);
    a.read();
    b.read();
    (a * b).print();
    //while (1)
        ;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 3529 [Sdoi2014] 数表</title><link>https://www.nekomio.com/posts/95/</link><guid isPermaLink="true">https://www.nekomio.com/posts/95/</guid><pubDate>Mon, 14 Aug 2017 21:19:20 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;有一张N×m的数表，其第i行第j列（1 &amp;lt; =i &amp;lt; =N，1 &amp;lt; =j &amp;lt; =m）的数值为
能同时整除i和j的所有自然数之和。给定a，计算数表中不大于a的数之和。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;输入包含多组数据。
输入的第一行一个整数Q表示测试点内的数据组数，接下来Q行，每行三个整数n，m，a(|a| &amp;lt; =10^9)描述一组数据。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;对每组数据，输出一行一个整数，表示答案模2^31的值。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;br /&gt;
4 4 3&lt;br /&gt;
10 10 5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;20&lt;br /&gt;
148&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;1 &amp;lt; =N．m &amp;lt; =10^5 ，1 &amp;lt; =Q &amp;lt;=2×10^4&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;先推试子&lt;/p&gt;
&lt;p&gt;先不考虑a&lt;/p&gt;
&lt;p&gt;设$F(i)$为i的约数和&lt;br /&gt;
设$g(i)=\sum_{i|d}{\mu(\frac{d}{i})\lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d} \rfloor}$&lt;br /&gt;
可以轻松的得&lt;br /&gt;
$$ \sum_{i=1}^{n}{F(i)g(i)} = \sum_{d=1}^{n}{\lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d} \rfloor \sum_{i|d}{F(i)\mu(\frac{d}{i})}} $$&lt;/p&gt;
&lt;p&gt;对于$\sum_{i|d}{F(i)\mu(\frac{d}{i})}$想怎么求就怎么求&lt;/p&gt;
&lt;p&gt;而如果有a&lt;br /&gt;
那么我们可以离线，树状数组维护就可以&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#define LL long long
using namespace std;
unsigned int tmp1[100005], tmp2[100005], s[100005];
int prime[100005], tot;
int mu[100005];
bool isnprime[100005];
int a[100005];
int N = 100000;
int comp(const int &amp;amp;c, const int &amp;amp;b)
{
    return s[c] &amp;lt; s[b];
}
void Get_Fun()
{
    s[1] = mu[1] = 1;
    tmp1[1] = tmp2[1] = 0;
    for (int i = 2; i &amp;lt;= N; i++)
    {
        if (!isnprime[i])
        {
            prime[++tot] = i;
            mu[i] = -1;
            tmp1[i] = i + 1, tmp2[i] = i;
            s[i] = i + 1;
        }
        for (int j = 1; j &amp;lt;= tot; j++)
        {
            if (i * prime[j] &amp;gt; N)
                break;
            isnprime[i * prime[j]] = 1;
            if (i % prime[j] == 0)
            {
                mu[i * prime[j]] = 0;
                s[i * prime[j]] = s[i] / tmp1[i] * (tmp1[i] + tmp2[i] * prime[j]);
                tmp1[i * prime[j]] = tmp1[i] + tmp2[i] * prime[j];
                tmp2[i * prime[j]] = tmp2[i] * prime[j];
                break;
            }
            mu[i*prime[j]] = -mu[i];
            s[i * prime[j]] = s[i] * s[prime[j]];
            tmp1[i * prime[j]] = prime[j] + 1;
            tmp2[i * prime[j]] = prime[j];
        }
    }
    for (int i = 1; i &amp;lt;= N; i++)
        a[i] = i;
    sort(a + 1, a + N + 1, comp);
}
unsigned int Sum[100005];
#define lowbit(_) ((_) &amp;amp; (-_))
void add(int a, int b)
{
    for (int i = a; i &amp;lt;= N; i += lowbit(i))
        Sum[i] += b;
}
unsigned int Query(int a)
{
    unsigned int ans = 0;
    for (int i = a; i &amp;gt; 0; i -= lowbit(i))
        ans += Sum[i];
    return ans;
}
struct data
{
    int n, m, a, ID;
    bool operator&amp;lt;(const data &amp;amp;b) const
    {
        return a &amp;lt; b.a;
    }
} Q[20005];
unsigned int ans[20005];
unsigned int Query(data S)
{
    if (S.n &amp;gt; S.m)
        swap(S.n, S.m);
    unsigned int ans = 0,last;
    for (int i = 1; i &amp;lt;= S.n; i = last + 1)
    {
        last = min(S.n / (S.n / i), S.m / (S.m / i));
        ans += (Query(last) - Query(i - 1)) * (S.n / i) * (S.m / i);
    }
    return ans;
}
int main(int argc, char const *argv[])
{
    freopen(&quot;sdoi2014shb.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;sdoi2014shb.out&quot;,&quot;w&quot;,stdout);
    int T;
    Get_Fun();
    scanf(&quot;%d&quot;, &amp;amp;T);
    for (int i = 1; i &amp;lt;= T; i++)
        scanf(&quot;%d%d%d&quot;, &amp;amp;Q[i].n, &amp;amp;Q[i].m, &amp;amp;Q[i].a), Q[i].ID = i;
    sort(Q + 1, Q + T + 1);
    for (int i = 1, j = 1; i &amp;lt;= T; i++)
    {
        while (s[a[j]] &amp;lt;= Q[i].a &amp;amp;&amp;amp; j &amp;lt;= N)
        {
            for (int k = 1; k * a[j] &amp;lt;= N; k++)
                add(k * a[j], s[a[j]] * mu[k]);
            j++;
        }
        ans[Q[i].ID] = Query(Q[i]);
    }
    for (int i = 1; i &amp;lt;= T; i++)
    {
        printf(&quot;%d\n&quot;,((ans[i]&amp;lt;&amp;lt;1)&amp;gt;&amp;gt;1));
    }
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 4407 于神之怒加强版</title><link>https://www.nekomio.com/posts/93/</link><guid isPermaLink="true">https://www.nekomio.com/posts/93/</guid><pubDate>Sun, 13 Aug 2017 21:11:37 GMT</pubDate><content:encoded>&lt;h3&gt;【题目描述】&lt;/h3&gt;
&lt;p&gt;给定n,m,k,计算 $\sum_{i=1}^{n}{\sum_{j=1}^{m}{gcd(i,j)^k}}$ 对1000000007取模的结果
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;多组数据。
第一行是两个数T,K;
之后的T行，每行两个整数n，m；&lt;/p&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;K行，每行一个结果&lt;/p&gt;
&lt;h3&gt;【样例输入】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1 2&lt;br /&gt;
3 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【样例输出】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;20&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【提示】&lt;/h3&gt;
&lt;p&gt;T&amp;lt;=2000,1&amp;lt;=N,M,K&amp;lt;=5000000&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;第一步推式子&lt;/p&gt;
&lt;p&gt;$\sum_{i=1}^{n}{\sum_{j=1}^{m}{gcd(i,j)^k}}$&lt;br /&gt;
$=\sum_{d=1}^{n}{d^k\sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)==d]}}}$&lt;br /&gt;
$=\sum_{d=1}^{n}{d^k\sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}{\sum_{j=1}^{\lfloor \frac{m}{d} \rfloor}{[gcd(i,j)==1]}}}$&lt;br /&gt;
$=\sum_{d=1}^{n}{d^k\sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}{\sum_{j=1}^{\lfloor \frac{m}{d} \rfloor}{\sum_{c|i,c|j}{\mu{c}}}}}$&lt;br /&gt;
另$T = dc$&lt;br /&gt;
$=\sum_{T=1}^{n}{\sum_{d|T}{d^k \mu{\frac{T}{d}} \lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor}}$&lt;br /&gt;
$=\sum_{T=1}^{n}{\lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor \sum_{d|T}{d^k \mu{\frac{T}{d}}}}$&lt;/p&gt;
&lt;p&gt;然后我们需要线性筛出$\sum_{d|T}{d^k \mu{\frac{T}{d}}}$就可以了&lt;br /&gt;
设$g(T) = \sum_{d|T}{d^k \mu{\frac{T}{d}}}$&lt;br /&gt;
显然是积性函数
别问我怎么知道的&lt;br /&gt;
当互质时 $g(T&lt;em&gt;P) = g(T) * g(p)$&lt;br /&gt;
当不互质时
又要推狮子&lt;br /&gt;
根据$\mu$函数的定义&lt;br /&gt;
当且仅当不含平方因子时不为零&lt;br /&gt;
所以质因子只有选和不选两种状态，有用的状态数是不变的&lt;br /&gt;
每一个有用的$\mu$ 都乘了一个p^k;
所以$ g(T&lt;/em&gt;p) = g(T) * p^k $&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#define LL long long
 
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
int prime[500005], tot;
const int MOD = 1000000007;
bool isnprime[5000005];
LL g[5000005];
LL primeK[500005], n, k, m;
LL N = 5000000;
LL pow_mod(LL a, LL b)
{
    LL ans = 1;
    while (b)
    {
        if (b &amp;amp; 1)
            ans = ans * a % MOD;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % MOD;
    }
    return ans;
}
void Get_g()
{
    g[1] = 1;
    for (int i = 2; i &amp;lt;= N; i++)
    {
        if (!isnprime[i])
        {
            prime[++tot] = i;
            g[i] = (primeK[tot] = pow_mod(i, k)) - 1;
        }
        for (int j = 1; j &amp;lt;= tot; j++)
        {
            if (i * prime[j] &amp;gt; N)
                break;
            isnprime[i * prime[j]] = 1;
            if (i % prime[j] == 0)
            {
                g[i * prime[j]] = g[i] * primeK[j] % MOD;
                break;
            }
            g[i * prime[j]] = g[i] * g[prime[j]] % MOD;
        }
    }
    for (int i = 2; i &amp;lt;= N; i++)
        g[i] += g[i - 1], g[i] %= MOD;
}
int main()
{
    freopen(&quot;bzoj_4407.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;bzoj_4407.out&quot;,&quot;w&quot;,stdout);
    int t;
    scanf(&quot;%d%lld&quot;, &amp;amp;t, &amp;amp;k);
    Get_g();
    while (t--)
    {
        scanf(&quot;%lld%lld&quot;, &amp;amp;n, &amp;amp;m);
        int last;
        LL ret = 0;
        if (n &amp;gt; m)
            swap(n, m);
        for (int i = 1; i &amp;lt;= n; i = last + 1)
        {
            last = min(n / (n / i), m / (m / i));
            (ret += (n / i) * (m / i) % MOD * (g[last] - g[i - 1] + MOD) % MOD)%=MOD;
        }
        printf(&quot;%lld\n&quot;, ret);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 4173 数学</title><link>https://www.nekomio.com/posts/92/</link><guid isPermaLink="true">https://www.nekomio.com/posts/92/</guid><pubDate>Sun, 13 Aug 2017 06:13:24 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/13/598f8195c1e7e.jpg&quot; alt=&quot;ff.jpg&quot; /&gt;
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;输入文件的第一行输入两个正整数 。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;如题&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5 6&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;240&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;N,M&amp;lt;=10^15&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;简单来说就是找规律&lt;/p&gt;
&lt;p&gt;答案为a*b*phi(a)*phi(b)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cmath&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
const long long MOD = 998244353;
long long phi(long long x)
{
    double ans = x;
    int i = 2;
    int Sqrt = ceil(sqrt(x));
    while (x != 1)
    {
        if (i &amp;gt; Sqrt)
        {
            ans *= (1 - (double)1 / x);
            break;
        }
        if (x % i == 0)
        {
            ans *= (1 - (double)1 / i);
            while (x % i == 0)
                x /= i;
        }
        i++;
    }
    return (long long)ans;
}
int main()
{
    long long a,b;
    scanf(&quot;%lld%lld&quot;,&amp;amp;a,&amp;amp;b);
    printf(&quot;%lld&quot;,((((a%MOD)*(b%MOD)%MOD)*(phi(a)%MOD)%MOD)*(phi(b)%MOD))%MOD);
    //while(1);
}
﻿
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 3505 [Cqoi2014]数三角形</title><link>https://www.nekomio.com/posts/91/</link><guid isPermaLink="true">https://www.nekomio.com/posts/91/</guid><pubDate>Sat, 12 Aug 2017 21:28:54 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;给定一个nxm的网格，请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。
注意三角形的三点不能共线。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;输入一行，包含两个空格分隔的正整数m和n。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;输出一个正整数，为所求三角形数量。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2 2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;76&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;数据范围&lt;/h3&gt;
&lt;p&gt;1&amp;lt;=m,n&amp;lt;=1000&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;先用组合数算出所有的可能&lt;/p&gt;
&lt;p&gt;在 Gcd 去掉在一条线上的就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
long long c[1000005][4];
long long gcd(long long a, long long b)
{
    return b == 0 ? a : gcd(b, a % b);
}
int main()
{
    long long n, m;
    scanf(&quot;%lld%lld&quot;, &amp;amp;n, &amp;amp;m);
    n++, m++;
    c[0][0] = 1;
    for (long long i = 1; i &amp;lt;= n * m; i++)
    {
        c[i][0] = 1;
        for (long long j = 1; j &amp;lt;= 3; j++)
            c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
    }
    long long ans = c[n * m][3];
    ans -= c[n][3] * m;
    ans -= c[m][3] * n;
    for (long long i = 1; i &amp;lt; n; i++)
    {
        for (long long j = 1; j &amp;lt; m; j++)
        {
            long long Gcd = gcd(i, j);
            if (Gcd &amp;gt; 1)
                ans -= 2 * (Gcd - 1) * (n - i) * (m - j);
        }
    }
    printf(&quot;%lld&quot;, ans);
}
﻿
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>改造二叉树</title><link>https://www.nekomio.com/posts/90/</link><guid isPermaLink="true">https://www.nekomio.com/posts/90/</guid><pubDate>Sat, 12 Aug 2017 21:09:24 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/12/598efe05d2ae0.png&quot; alt=&quot;20170812080419_23272.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;br /&gt;
2 2 2&lt;br /&gt;
1 0&lt;br /&gt;
1 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/12/598f0119dabfa.png&quot; alt=&quot;20170812080428_12682.png&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;先中序遍历&lt;br /&gt;
然后按a[i] - i 跑 最长不降子序列&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
struct Tree
{
    int ch[2];
    int v;
} Node[100005];
int a[100005], Ind, val[100005], c[100005];
void dfs(int rt)
{
    if (rt)
    {
        dfs(Node[rt].ch[0]);
        a[++Ind] = Node[rt].v;
        dfs(Node[rt].ch[1]);
    }
}
int f[100005], Max[100005];
int tot;
inline int lowbit(int x) { return x &amp;amp; (-x); }
void Update(int x, int val)
{
    for (int i = x; i &amp;lt;= tot; i += lowbit(i))
        Max[i] = max(Max[i], val);
    return;
}
int Query(int x)
{
    int ans = 0;
    for (int i = x; i; i -= lowbit(i))
        ans = max(ans, Max[i]);
    return ans;
}
int main()
{
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;Node[i].v);
    }
    int fa, d;
    for (int i = 2; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;fa, &amp;amp;d);
        Node[fa].ch[d] = i;
    }
    dfs(1);
    //memset(f, 0x7f, sizeof(f));
    for (int i = 1; i &amp;lt;= n; i++)
    {
        a[i] = a[i] - i;
        c[i] = a[i];
    }
    int ans = 0;
    sort(a + 1, a + n + 1);
    tot = unique(a + 1, a + n + 1) - a - 1;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        int now = lower_bound(a + 1, a + tot + 1, c[i]) - a;
        f[i] = Query(now) + 1;
        Update(now, f[i]);
        ans = max(ans, f[i]);
    }
    printf(&quot;%d&quot;, n - ans);
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>序列</title><link>https://www.nekomio.com/posts/89/</link><guid isPermaLink="true">https://www.nekomio.com/posts/89/</guid><pubDate>Sat, 12 Aug 2017 20:38:23 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/12/598ef6e160efc.png&quot; alt=&quot;20170812080316_85064.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5 3&lt;br /&gt;
2 4 2 3 4&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;39&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/12/598ef7763147d.png&quot; alt=&quot;20170812080326_67661.png&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;从比他小的中找&lt;br /&gt;
组合数一搞就行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
#define LL long long
const LL P = 1e9 + 7;
LL F[100005];
void Init()
{
    F[0] = 1;
    for (int i = 1; i &amp;lt;= 100000; i++)
        F[i] = i * F[i - 1] % P;
}
LL pow_mod(LL a, int b)
{
    LL ans = 1;
    while (b)
    {
        if (b &amp;amp; 1)
            ans = ans * a % P;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % P;
    }
    return ans;
}
LL C(int n, int m)
{
    if (m &amp;gt; n || m &amp;lt; 0)
        return 0;
    return F[n] * pow_mod(F[m] * F[n - m] % P, P - 2) % P;
}
LL a[100005], Has[100005];
int Sum[100005], n;
 
#define lowbit(_) ((_) &amp;amp; (-_))
 
void add(int x, int c)
{
    for (int i = x; i &amp;lt;= n; i += lowbit(i))
        Sum[i] += c;
}
int Query(int x)
{
    int ans = 0;
    for (int i = x; i &amp;gt; 0; i -= lowbit(i))
        ans += Sum[i];
    return ans;
}
int fron[100005], nxt[100005];
int main()
{
    Init();
    int K;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;K);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%lld&quot;, &amp;amp;a[i]);
    }
    sort(a + 1, a + n + 1);
    LL ans = 0;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        ans = (ans + a[i] * C(i - 1, K - 1)) % P;
    }
    printf(&quot;%lld\n&quot;, ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>灌水</title><link>https://www.nekomio.com/posts/88/</link><guid isPermaLink="true">https://www.nekomio.com/posts/88/</guid><pubDate>Sat, 12 Aug 2017 20:19:27 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/12/598ef4efe3fdf.png&quot; alt=&quot;20170812080054_73383.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;样例输入1：&lt;br /&gt;
3 1&lt;br /&gt;
样例输出1：&lt;br /&gt;
3 1 2&lt;br /&gt;
样例输入2：&lt;br /&gt;
4 1&lt;br /&gt;
样例输出2：&lt;br /&gt;
4 3 1 2&lt;br /&gt;
样例输入3：&lt;br /&gt;
8 17&lt;br /&gt;
样例输出3：&lt;br /&gt;
6 2 3 1 8 4 5 7&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;提示&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.loli.net/2017/08/12/598ef5a148e72.png&quot; alt=&quot;20170812080119_26860.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;题解&lt;/h3&gt;
&lt;p&gt;先找规律然后瞎搞就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
#define LL long long
LL Sum[1000005];
LL x;
int ans[1000005];
int main()
{
    int n;
    scanf(&quot;%d%lld&quot;, &amp;amp;n, &amp;amp;x);
    for (int i = n - 2; i &amp;gt;= 0; i--)
        Sum[i] = Sum[i + 1] + i;
    if (Sum[0] &amp;lt; x)
    {
        puts(&quot;-1&quot;);
        return 0;
    }
    int k, i, j;
    for (k = 1; k &amp;lt;= n - 2; k++)
        if (x &amp;gt; Sum[k])
            break;
    x = x - Sum[k];
    for (i = n - k, j = 1; i &amp;lt;= n - 1; i++, j++)
        ans[j] = i;
    for (i = 1; i &amp;lt;= n - k - 1; i++, j++)
        ans[j] = i;
    ans[n] = n;
    i = 1;
    while (x--)
    {
        swap(ans[i], ans[i + 1]);
        i++;
    }
    for (i = 1; i &amp;lt; n; i++)
        printf(&quot;%d &quot;, ans[i]);
    printf(&quot;%d\n&quot;, ans[n]);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[JLOI2011]飞行路线</title><link>https://www.nekomio.com/posts/87/</link><guid isPermaLink="true">https://www.nekomio.com/posts/87/</guid><pubDate>Thu, 10 Aug 2017 21:17:13 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;Alice和Bob现在要乘飞机旅行，他们选择了一家相对便宜的航空公司。该航空公司一共在n个城市设有业务，设这些城市分别标记为0到n-1，一共有m种航线，每种航线连接两个城市，并且航线有一定的价格。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;Alice和Bob现在要从一个城市沿着航线到达另一个城市，途中可以进行转机。航空公司对他们这次旅行也推出优惠，他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少？&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;数据的第一行有三个整数，n,m,k，分别表示城市数，航线数和免费乘坐次数。
第二行有两个整数，s,t，分别表示他们出行的起点城市编号和终点城市编号。(0&amp;lt;=s,t&amp;lt;n)
接下来有m行，每行三个整数，a,b,c，表示存在一种航线，能从城市a到达城市b，或从城市b到达城市a，价格为c。(0&amp;lt;=a,b&amp;lt;n,a与b不相等，0&amp;lt;=c&amp;lt;=1000)&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;只有一行，包含一个整数，为最少花费。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5 6 1&lt;br /&gt;
0 4&lt;br /&gt;
0 1 5&lt;br /&gt;
1 2 5&lt;br /&gt;
2 3 5&lt;br /&gt;
3 4 5&lt;br /&gt;
2 3 3&lt;br /&gt;
0 2 100&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;8&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;提示&lt;/h3&gt;
&lt;p&gt;对于30%的数据,2&amp;lt;=n&amp;lt;=50,1&amp;lt;=m&amp;lt;=300,k=0;
对于50%的数据,2&amp;lt;=n&amp;lt;=600,1&amp;lt;=m&amp;lt;=6000,0&amp;lt;=k&amp;lt;=1;
对于100%的数据,2&amp;lt;=n&amp;lt;=10000,1&amp;lt;=m&amp;lt;=50000,0&amp;lt;=k&amp;lt;=10.&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;二维SPFA优化一下&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;queue&amp;gt;
using namespace std;
struct edge
{
    int END, next, v;
} v[100005];
int first[10005], p;
void add(int a, int b, int c)
{
    v[p].END = b;
    v[p].next = first[a];
    v[p].v = c;
    first[a] = p++;
}
 
int dis[10005][11];
bool flag[10005][11];
int Top;
struct data
{
    int k, tmp;
    bool operator&amp;lt;(const data &amp;amp;a) const
    {
        return dis[k][tmp] &amp;gt; dis[a.k][a.tmp];
    }
};
int Spfa(int S, int T)
{
    memset(dis, 0x3f, sizeof(dis));
    flag[S][0] = 1;
    priority_queue&amp;lt;data&amp;gt; Q;
    Q.push((data){S, 0});
    dis[S][0] = 0;
    while (!Q.empty())
    {
        int k = Q.top().k;
        int tmp = Q.top().tmp;
        flag[k][tmp] = 0;
        Q.pop();
        for (int i = first[k]; i != -1; i = v[i].next)
        {
            if (dis[v[i].END][tmp] &amp;gt; dis[k][tmp] + v[i].v)
            {
                dis[v[i].END][tmp] = dis[k][tmp] + v[i].v;
                if (!flag[v[i].END][tmp])
                {
                    flag[v[i].END][tmp] = 1;
                    Q.push((data){v[i].END, tmp});
                }
            }
            if (dis[v[i].END][tmp + 1] &amp;gt; dis[k][tmp] &amp;amp;&amp;amp; tmp + 1 &amp;lt;= Top)
            {
                dis[v[i].END][tmp + 1] = dis[k][tmp];
                if (!flag[v[i].END][tmp + 1])
                {
                    flag[v[i].END][tmp + 1] = 1;
                    Q.push((data){v[i].END, tmp + 1});
                }
            }
        }
    }
    int ans = 0x7fffffff;
    for (int i = 0; i &amp;lt;= Top; i++)
        ans = min(ans, dis[T][i]);
    return ans;
}
int main(int argc, char const *argv[])
{
    memset(first, -1, sizeof(first));
    int n, m;
    scanf(&quot;%d%d%d&quot;, &amp;amp;n, &amp;amp;m, &amp;amp;Top);
    int S, T;
    scanf(&quot;%d%d&quot;, &amp;amp;S, &amp;amp;T);
    S++, T++;
    int a, b, c;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d%d%d&quot;, &amp;amp;a, &amp;amp;b, &amp;amp;c);
        add(a + 1, b + 1, c);
        add(b + 1, a + 1, c);
    }
    printf(&quot;%d&quot;, Spfa(S, T));
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Function</title><link>https://www.nekomio.com/posts/86/</link><guid isPermaLink="true">https://www.nekomio.com/posts/86/</guid><pubDate>Thu, 10 Aug 2017 21:16:58 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/10/20170810100243_44388428d5.png&quot; alt=&quot;20170810100243_44388428d5.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;暴力搞就可以&lt;br /&gt;
先预处理出所有范围内的函数值&lt;br /&gt;
卡卡常&lt;a href=&quot;https://raw.githubusercontent.com/HZOI/Share/master/%E8%AF%BE%E4%BB%B6/wys-full.pdf&quot;&gt;-Owys&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;直接O(1) 查询就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
******************************************************************************
* @file Function
* @author   WildRage
* @version v 1.0
* @date 2017-8-10 10:57:28
* @brief 
******************************************************************************
*/
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
#define LL long long
LL a[1005], b[1005], c[1005];
LL Max[200005];
int fix = 100001;
int main()
{
    memset(Max, 0x80, sizeof(Max));
    int n, q;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;q);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%lld%lld%lld&quot;, &amp;amp;a[i], &amp;amp;b[i], &amp;amp;c[i]);
    }
    LL u;
    for (int i = -100000; i &amp;lt;= 100000; i++)
    {
        for (int j = 1; j &amp;lt;= n; j++)
        {
            Max[i + fix] = max(Max[i + fix], a[j] * i * i + b[j] * i + c[j]);
        }
    }
    while (q--)
    {
        scanf(&quot;%lld&quot;, &amp;amp;u);
        printf(&quot;%lld\n&quot;, Max[u + fix]);
    }
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>公主的朋友</title><link>https://www.nekomio.com/posts/85/</link><guid isPermaLink="true">https://www.nekomio.com/posts/85/</guid><pubDate>Thu, 10 Aug 2017 21:08:31 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;由于 Wulala 在上个问题中的精彩表现，公主认为 Wulala 是一个很棒的人，就把 Wulala 留在了 X 国。这时正好公主的一位传教士朋友来拜访公主，于是想找 wulala 帮忙X 国如同一条直线，其中有 n 个城市,从东向西分别编号为 1~n。而他的国家中有 m 种宗教，每个城市一定会有一种信仰的宗教。
&amp;lt;!--more--&amp;gt;
有时候有些城市为了获得更多的认可，会派出信仰本城市宗教的传教士前往其他国家。X 国
的传教士都十分厉害，只要是他途经的地方都会改信他所传播的宗教。
传教士们在路上碰到自己宗教的城市自然就不用传教了，可以停下来看看里番啥的，所以每
一个传教士在旅行前都会计算自己可以在多少城市停下来(不包括起始的城市)。
而传教士们都是文科僧，数学是很差的，所以他希望 Wulala 能帮他计算。可 Wulala 数学也不好，但他又不想在公主面前丢脸，你能帮帮他吗？&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第一行两个整数 n，m
第二行 n 个整数第 i 个整数代表第 i 各城市信仰的宗教
第三行一个整数 T 代表传教士的个数
接下来 T 行每行两个整数 x，y 代表 x 城向 y 城派遣了一个传教士(保证 x &amp;lt; y)&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输出 T 行，第 i 行代表第 i 个传教士询问的答案&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2 2&lt;br /&gt;
1 2&lt;br /&gt;
2&lt;br /&gt;
1 2&lt;br /&gt;
1 2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;0&lt;br /&gt;
1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;提示&lt;/h3&gt;
&lt;p&gt;对于 30%的数据 n &amp;lt;= 100000, m &amp;lt;= 10, T &amp;lt;= 100
对于 60%的数据 n &amp;lt;= 100000, m &amp;lt;= 10, T &amp;lt;= 100000
对于 100%的数据 n &amp;lt;= 100000, m &amp;lt;= 300, T &amp;lt;= 100000&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;分块直接维护就可以了&lt;br /&gt;
原来分块也可以是正解&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
******************************************************************************
* @file Wulala
* @author   WildRage
* @version v 0.9
* @date 2017-8-10 10:58:12
* @brief 
******************************************************************************
*/
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
const int N = 100001, M = 301;
int a[N], in[N], n, m;
int Sum[500][305], Change[500];
int block;
int lp[500], rp[500];
int Query(int l, int r)
{
    int L = in[l], R = in[r];
    int ans = 0;
    bool flag = 0;
    if (L == R)
    {
        if (Change[L])
            return r - l;
        for (int i = l + 1; i &amp;lt;= r; i++)
        {
            if (a[i] == a[l])
                ans++;
            a[i] = a[l];
        }
        for (int i = lp[L]; i &amp;lt; l; i++)
            if (a[i] != a[l])
            {
                flag = 1;
                break;
            }
        if (flag == 1)
            return ans;
        for (int i = r + 1; i &amp;lt;= rp[R]; i++)
        {
            if (a[i] != a[l])
            {
                flag = 1;
                break;
            }
        }
        if (flag == 0)
            Change[L] = a[l];
        return ans;
    }
    else
    {
        if (Change[L] == a[l])
            ans += (rp[L] - l);
        else
        {
            flag = 0;
            for (int i = l + 1; i &amp;lt;= rp[L]; i++)
            {
                if (a[i] == a[l])
                    ans++;
                a[i] = a[l];
            }
            for (int i = lp[L]; i &amp;lt; l; i++)
                if (a[i] != a[l])
                {
                    flag = 1;
                    break;
                }
            if (!flag)
                Change[L] = a[l];
        }
        if (Change[R])
        {
            if (Change[R] == a[l])
                ans += (r - lp[R] + 1);
            else
            {
                for (int i = lp[R]; i &amp;lt;= r; i++)
                    a[i] = a[l];
                Change[R] = 0;
            }
        }
        else
        {
            flag = 0;
            for (int i = lp[R]; i &amp;lt;= r; i++)
            {
                if (a[i] == a[l])
                    ans++;
                a[i] = a[l];
            }
            for (int i = r + 1; i &amp;lt;= rp[R]; i++)
                if (a[i] != a[l])
                {
                    flag = 1;
                    break;
                }
            if (!flag)
                Change[R] = a[l];
        }
        for (int i = L + 1; i &amp;lt; R; i++)
        {
            if (Change[i])
            {
                if (Change[i] == a[l])
                    ans += block;
                else
                {
                    for (int j = lp[i]; j &amp;lt;= rp[i]; j++)
                        a[j] = a[l];
                    Change[i] = a[l];
                }
            }
            else
            {
                for(int j = lp[i];j&amp;lt;=rp[i];j++)
                {
                    if(a[j]==a[l])
                        ans++;
                    a[j] = a[l];
                }
                Change[i] = a[l];
            }
        }
        return ans;
    }
}
int main()
{
    int c, b;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    block = 316;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
        in[i] = (i - 1) / block + 1;
        Sum[in[i]][a[i]]++;
    }
    for (int i = 1; i &amp;lt;= in[n]; i++)
        lp[i] = (i - 1) * block + 1, rp[i] = min(n, i * block);
    int T;
    scanf(&quot;%d&quot;, &amp;amp;T);
    while (T--)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;c, &amp;amp;b);
        int ans = Query(c, b);
        printf(&quot;%d\n&quot;, ans);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Evensgn 剪树枝</title><link>https://www.nekomio.com/posts/84/</link><guid isPermaLink="true">https://www.nekomio.com/posts/84/</guid><pubDate>Thu, 10 Aug 2017 21:04:03 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;繁华中学有一棵苹果树。苹果树有 n 个节点（也就是苹果），n − 1 条边（也就
是树枝）。调皮的 Evensgn 爬到苹果树上。他发现这棵苹果树上的苹果有两种：一
种是黑苹果，一种是红苹果。Evensgn 想要剪掉 k 条树枝，将整棵树分成 k + 1 个
部分。他想要保证每个部分里面有且仅有一个黑苹果。请问他一共有多少种剪树枝
的方案？
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第一行一个数字 n，表示苹果树的节点（苹果）个数。
第二行一共 n − 1 个数字 p0, p1, p2, p3, ..., pn−2，pi 表示第 i + 1 个节点和 pi 节
点之间有一条边。注意，点的编号是 0 到 n − 1。
第三行一共 n 个数字 x0, x1, x2, x3, ..., xn−1。如果 xi 是 1，表示 i 号节点是黑
苹果；如果 xi 是 0，表示 i 号节点是红苹果。&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输出一个数字，表示总方案数。答案对 109 + 7 取模。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;样例输入 1&lt;br /&gt;
3&lt;br /&gt;
0 0&lt;br /&gt;
0 1 1&lt;br /&gt;
样例输入 2&lt;br /&gt;
6&lt;br /&gt;
0 1 1 0 4&lt;br /&gt;
1 1 0 0 1 0&lt;br /&gt;
样例输入 3&lt;br /&gt;
10&lt;br /&gt;
0 1 2 1 4 4 4 0 8&lt;br /&gt;
0 0 0 1 0 1 1 0 0 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;样例输出 1&lt;br /&gt;
2&lt;br /&gt;
样例输出 2&lt;br /&gt;
1&lt;br /&gt;
样例输出 3&lt;br /&gt;
27&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;提示&lt;/h3&gt;
&lt;p&gt;数据范围
对于 30% 的数据，1 ≤ n ≤ 10。
对于 60% 的数据，1 ≤ n ≤ 100。
对于 80% 的数据，1 ≤ n ≤ 1000。
对于 100% 的数据，1 ≤ n ≤ 105。
对于所有数据点，都有 0 ≤ pi ≤ n − 1，xi = 0 或 xi = 1。
特别地，60% 中、80% 中、100% 中各有一个点，树的形态是一条链。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;题解链接&lt;a href=&quot;http://blog.csdn.net/ren_ivan/article/details/77053836&quot;&gt;Evensgn 剪树枝 树规 Ivan&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;f[x][0]表示与其父边相连的连通块内没有黑苹果的方案数，&lt;br /&gt;
f[x][1]则表示有黑苹果，&lt;br /&gt;
如果父边被切断，相当于没有黑苹果&lt;br /&gt;
初始化时，假设切掉父边，f[x][0]=1,f[x][1]=0;&lt;br /&gt;
递归回时转移,每递归回一个子树,f[x][1]=f[x][1]*f[v][0]+f[x][0]*f[v][1],f[x][0]=f[x][0]*f[v][0];&lt;br /&gt;
最后处理完每个子树时,若其为黑苹果f[x][1]=f[x][0],否则f[x][0]=f[x][0]+f[x][1]（可以切掉）&lt;/p&gt;
&lt;p&gt;Mycode&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
******************************************************************************
* @file Evensgn
* @author WildRage
* @version v 1.0
* @date  2017-5-10 10:55:23
* @brief 
******************************************************************************
*/
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;vector&amp;gt;
const int P = 1e9 + 7;
namespace Mine_WorkSpace
{
struct data
{
    struct edge
    {
        int END, next;
    } v[200005];
    int first[100005], p;
    data()
    {
        memset(first, -1, sizeof(first));
        p = 0;
    }
    void add(int a, int b)
    {
        v[p].END = b;
        v[p].next = first[a];
        first[a] = p++;
    }
} Edge;
bool color[100005];
long long f[100005][2];
void  DP(int rt, int fa)
{
    f[rt][0] = 1;
    f[rt][1] = 0;
    for (int i = Edge.first[rt]; i != -1; i = Edge.v[i].next)
    {
        if (fa != Edge.v[i].END)
        {
            DP(Edge.v[i].END, rt);
            f[rt][1] = (f[rt][1] * f[Edge.v[i].END][0]) % P;
            f[rt][1] = (f[rt][1] + f[Edge.v[i].END][1] * f[rt][0]) % P;
            f[rt][0] = (f[rt][0] * f[Edge.v[i].END][0]) % P;
        }
    }
    if (color[rt])
        f[rt][1] = f[rt][0];
    else
        f[rt][0] = (f[rt][1] + f[rt][0]) % P;
}
int Main()
{
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    int a, b;
    for (int i = 1; i &amp;lt; n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;b);
        Edge.add(i + 1, b + 1), Edge.add(b + 1, i + 1);
    }
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;a);
        if (a)
            color[i] = 1;
    }
    DP(1,0);
    printf(&quot;%lld\n&quot;, f[1][1]);
    // Print_tree(1);
    // while(1);
}
}
int main() { Mine_WorkSpace::Main(); }
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title> [NOI2017] 蚯蚓排队</title><link>https://www.nekomio.com/posts/82/</link><guid isPermaLink="true">https://www.nekomio.com/posts/82/</guid><pubDate>Wed, 09 Aug 2017 21:24:05 GMT</pubDate><content:encoded>&lt;p&gt;题目描述
蚯蚓幼儿园有nnn只蚯蚓。幼儿园园长神刀手为了管理方便，时常让这些蚯蚓们列队表演。
&amp;lt;!--more--&amp;gt;
所有蚯蚓用从 1 到 n 的连续正整数编号。每只蚯蚓的长度可以用一个正整数表示，根据入园要求，所有蚯蚓的长度都不超过 6 。神刀手希望这些蚯蚓排成若干个队伍，初始时，每只蚯蚓各自排成一个仅有一只蚯蚓的队伍，该蚯蚓既在队首，也在队尾。&lt;/p&gt;
&lt;p&gt;神刀手将会依次进行 m 次操作，每个操作都是以下三种操作中的一种：&lt;/p&gt;
&lt;p&gt;给出 i 和 j ，令 i 号蚯蚓与 j 号蚯蚓所在的两个队伍合并为一个队伍，具体来说，令 j 号蚯蚓紧挨在 i 号蚯蚓之后，其余蚯蚓保持队伍的前后关系不变。
给出 i ，令 i 号蚯蚓与紧挨其后的一只蚯蚓分离为两个队伍，具体来说，在分离之后， i 号蚯蚓在其中一个队伍的队尾，原本紧挨其后的那一只蚯蚓在另一个队伍的队首，其余蚯蚓保持队伍的前后关系不变。
给出一个正整数 k 和一个长度至少为 k 的数字串 s ，对于 s 的每个长度为 k 的连续子串 t （这样的子串共有 ∣s∣−k+1 个，其中 ∣s∣|s|∣s∣ 为 s 的长度），定义函数 f(t) ，询问所有这些f(t)的乘积对 998244353 取模后的结果。其中f(t)的定义如下：
对于当前的蚯蚓队伍，定义某个蚯蚓的向后 k 数字串为：从该蚯蚓出发，沿队伍的向后方向，寻找最近的 k 只蚯蚓（包括其自身），将这些蚯蚓的长度视作字符连接而成的数字串；如果这样找到的蚯蚓不足 k 只，则其没有向后k数字串。例如蚯蚓的队伍为 10 号蚯蚓在队首，其后是 22 号蚯蚓，其后是 3 号蚯蚓（为队尾），这些蚯蚓的长度分别为 4 、 5 、 6 ，则 10 号蚯蚓的向后 3 数字串为456， 22 号蚯蚓没有向后 3 数字串，但其向后 2 数字串为56，其向后 1 数字串为5。&lt;/p&gt;
&lt;p&gt;而 f(t) 表示所有蚯蚓中，向后 k 数字串恰好为 t 的蚯蚓只数。
输入格式
从标准输入读入数据。&lt;/p&gt;
&lt;p&gt;输入文件的第一行有两个正整数 n,m ，分别表示蚯蚓的只数与操作次数。&lt;/p&gt;
&lt;p&gt;第二行包含 n 个不超过 6 的正整数，依次表示编号为
1,2,…,n的蚯蚓的长度。&lt;/p&gt;
&lt;p&gt;!!!&lt;/p&gt;
&lt;h3&gt;不想粘题了&lt;/h3&gt;
&lt;p&gt;好气&lt;/p&gt;
&lt;p&gt;链接&lt;a href=&quot;https://loj.ac/problem/2303&quot;&gt;LOJ&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;哈希能过&lt;br /&gt;
但要注意一下&lt;/p&gt;
&lt;p&gt;每合并一次就相当于增加了50^2种情况&lt;br /&gt;
合并和拆分是一样的&lt;br /&gt;
然后查询的时候硬跑就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
#define LL unsigned long long
const int N = 300010, M = 15000010, L = 20000010;
const LL P = 23333333, p = 1000007, mod = 998244353;
int head[P], next[L], cnt[L], E, Next[N], Pre[N], a[N];
LL w[L], Pow[60];
int n, m;
char str[L];
void Insert(LL x, int y)
{
    LL now = x % P;
    bool flag = 0;
    for (int i = head[now]; i; i = next[i])
        if (w[i] == x)
        {
            cnt[i] += y;
            flag = 1;
            break;
        }
    if (!flag)
    {
        next[++E] = head[now];
        head[now] = E;
        cnt[E] = 1;
        w[E] = x;
    }
}
int Query(LL x)
{
    LL now = x % P;
    for (int i = head[now]; i; i = next[i])
        if (w[i] == x)
            return cnt[i];
    return 0;
}
void Change(int x, int y)
{
    int now = x;
    for (int k = 1; k &amp;lt;= 50; k++)
    {
        int ret = now;
        LL Hash = a[now];
        for (int j = 1; j &amp;lt;= k; j++)
        {
            ret = Next[ret];
            Hash = Hash * p + a[ret];
        }
        for (int l = k + 1; l &amp;lt;= 50; l++)
        {
            Insert(Hash, y);
            ret = Next[ret];
            if (!ret)
                break;
            Hash = Hash * p + a[ret];
        }
        now = Pre[now];
        if (!now)
            break;
    }
}
int main()
{
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
        Insert(a[i], 1);
    }
    Pow[0] = 1;
    for (int i = 1; i &amp;lt;= 50; i++)
    {
        Pow[i] = Pow[i - 1] * p;
    }
    int op;
    int x, y;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;op);
        if (op == 1)
        {
            scanf(&quot;%d%d&quot;, &amp;amp;x, &amp;amp;y);
            Next[x] = y;
            Pre[y] = x;
            Change(x, 1);
        }
        else if (op == 2)
        {
            scanf(&quot;%d&quot;, &amp;amp;x);
            Change(x, -1);
            Pre[Next[x]] = 0, Next[x] = 0;
        }
        else
        {
            scanf(&quot;%s&quot;, str + 1);
            scanf(&quot;%d&quot;, &amp;amp;x);
            LL ret = 0;
            for (int i = 1; i &amp;lt;= x; i++)
                ret = ret * p + str[i] - &apos;0&apos;;
            LL ans = Query(ret);
            LL len = strlen(str + 1);
            for (int i = x + 1; i &amp;lt;= len; i++)
            {
                ret = ret - (str[i - x] - &apos;0&apos;) * Pow[x - 1];
                ret = ret * p + (str[i] - &apos;0&apos;);
                ans = ans * Query(ret) % mod;
            }
            printf(&quot;%lld\n&quot;, ans);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 4299 Codechef FRBSUM</title><link>https://www.nekomio.com/posts/83/</link><guid isPermaLink="true">https://www.nekomio.com/posts/83/</guid><pubDate>Wed, 09 Aug 2017 21:24:05 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;数集S的ForbiddenSum定义为无法用S的某个子集（可以为空）的和表示的最小的非负整数。
例如，S={1,1,3,7}，则它的子集和中包含0(S’=∅)，1(S’={1})，2(S’={1,1})，3(S’={3})，4(S’={1,3})，5(S&apos; = {1, 1, 3})，但是它无法得到6。因此S的ForbiddenSum为6。
给定一个序列A，你的任务是回答该数列的一些子区间所形成的数集的ForbiddenSum是多少。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;输入数据的第一行包含一个整数N，表示序列的长度。
接下来一行包含N个数，表示给定的序列A（从1标号）。
接下来一行包含一个整数M，表示询问的组数。
接下来M行，每行一对整数，表示一组询问。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;对于每组询问，输出一行表示对应的答案。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5&lt;br /&gt;
1 2 4 9 10&lt;br /&gt;
5&lt;br /&gt;
1 1&lt;br /&gt;
1 2&lt;br /&gt;
1 3&lt;br /&gt;
1 4&lt;br /&gt;
1 5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;br /&gt;
4&lt;br /&gt;
8&lt;br /&gt;
8&lt;br /&gt;
8&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;对于100%的数据，1≤N,M≤100000,1≤A_i≤10^9，1≤A_1+A_2+…+A_N≤10^9。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;可以看出&lt;/p&gt;
&lt;p&gt;如果一个区间能组出1~n的数而且有一个数小于等于n+1&lt;br /&gt;
则这个区间一定能构造出 n+1&lt;/p&gt;
&lt;p&gt;然后就可以了&lt;/p&gt;
&lt;p&gt;用主席树维护一下就可以了&lt;/p&gt;
&lt;p&gt;复习一下主席树&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
const int INF = 1e9;
struct Seg_Node
{
    int l, r;
    Seg_Node *ch[2];
    int Sum;
} * root[100005], *null;
int a[100005];
Seg_Node *NewSeg_Node()
{
    Seg_Node *S = new Seg_Node();
    S-&amp;gt;ch[0] = S-&amp;gt;ch[1] = null;
    return S;
}
void copy(Seg_Node *&amp;amp;a, Seg_Node *b)
{
    if (b == null)
        a = null;
    else
        a = NewSeg_Node(), *a = *b;
}
void Update(int v, int l, int r, Seg_Node *&amp;amp;rt1, Seg_Node *rt2)
{
    copy(rt1, rt2);
    if(rt1==null)
        rt1=NewSeg_Node();
    rt1-&amp;gt;Sum += v;
    rt1-&amp;gt;l = l, rt1-&amp;gt;r = r;
    if (l == r)
        return;
    int m = l + r &amp;gt;&amp;gt; 1;
    if (v &amp;lt;= m)
    {
        Update(v, l, m, rt1-&amp;gt;ch[0], rt2-&amp;gt;ch[0]);
    }
    else
    {
        Update(v, m + 1, r, rt1-&amp;gt;ch[1], rt2-&amp;gt;ch[1]);
    }
}
int Query(int R, int l, int r, Seg_Node *rt1, Seg_Node *rt2)
{
    if (R &amp;gt;= r)
        return rt1-&amp;gt;Sum - rt2-&amp;gt;Sum;
    int m = l + r &amp;gt;&amp;gt; 1;
    if (R &amp;lt;= m)
        return Query(R, l, m, rt1-&amp;gt;ch[0], rt2-&amp;gt;ch[0]);
    return Query(R, l, m, rt1-&amp;gt;ch[0], rt2-&amp;gt;ch[0]) + Query(R, m + 1, r, rt1-&amp;gt;ch[1], rt2-&amp;gt;ch[1]);
}
int main()
{
    null = new Seg_Node();
    null-&amp;gt;ch[0] = null-&amp;gt;ch[1] = null;
    root[0] = null;
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++)
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        Update(a[i], 1, 1e9, root[i], root[i - 1]);
    }
    int m;
    scanf(&quot;%d&quot;, &amp;amp;m);
    int a, b, ans;
    while (m--)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;a, &amp;amp;b);
        int res = 1;
        ans = min(INF, Query(res, 1, 1e9, root[b], root[a - 1]));
        while (ans &amp;gt;= res &amp;amp;&amp;amp; res &amp;lt; 1e9)
        {
            res = ans + 1;
            ans = min(INF, Query(res, 1, 1e9, root[b], root[a - 1]));
        }
        printf(&quot;%d\n&quot;, ans + 1);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>permutation</title><link>https://www.nekomio.com/posts/81/</link><guid isPermaLink="true">https://www.nekomio.com/posts/81/</guid><pubDate>Wed, 09 Aug 2017 20:45:13 GMT</pubDate><content:encoded>&lt;h3&gt;3.1 题目描述&lt;/h3&gt;
&lt;p&gt;一个长度为n 的排列p[1..n]
把排列的每个循环拿出来，写成标准循环，再做一次排序
比如[4, 1, 6, 2, 5, 3]，有3 个循环(421)(63)(5)
其中第一个循环就是4 要到2 的位置，2 要到1 的位置，1 要到4 的位置
&amp;lt;!--more--&amp;gt;
每个循环从任意一个位置开始读都是一样的
比如(412) 也是(124),(241)。n 个循环就一共n 个表达法
我们规定一个标准循环是以循环内最大的数字开头
循环之间排序的关键字就是第一个数字的大小
如(421)(63)(5) 排序后是(421)(5)(63)
如果排序后的拍列和原排列一样，那么就是可行排列
求n 个数的字典序第k 大的排列&lt;/p&gt;
&lt;h3&gt;3.2 输入格式&lt;/h3&gt;
&lt;p&gt;两个整数，n，k 保证k 在long long 范围内，保证有解&lt;/p&gt;
&lt;h3&gt;3.3 输出格式&lt;/h3&gt;
&lt;p&gt;n 个整数，表示满足条件的排列&lt;/p&gt;
&lt;h3&gt;3.4 Sample Input1&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;4 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3.5 Sample Output1&lt;/h3&gt;
&lt;p&gt;1 3 2 4&lt;/p&gt;
&lt;h3&gt;3.6 Sample Input2&lt;/h3&gt;
&lt;p&gt;10 1&lt;/p&gt;
&lt;h3&gt;3.7 Sample Output2&lt;/h3&gt;
&lt;p&gt;1 2 3 4 5 6 7 8 9 10&lt;/p&gt;
&lt;h3&gt;3.8 数据范围及约定&lt;/h3&gt;
&lt;p&gt;对于30% 的数据满足：1 &amp;lt;= n &amp;lt;= 10
对于100% 的数据满足，1 &amp;lt;= n &amp;lt;= 50&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;不要被卡读题&lt;/p&gt;
&lt;p&gt;什么是循环&lt;/p&gt;
&lt;p&gt;比如说 题目中的例子&lt;/p&gt;
&lt;p&gt;4本应在的位置为2在的位置&lt;br /&gt;
2本应在的位置为1在的位置&lt;br /&gt;
1本应在的位置为4在的位置&lt;br /&gt;
这就是一个循环&lt;/p&gt;
&lt;p&gt;然后先打一个表找规律&lt;/p&gt;
&lt;p&gt;我们会惊讶的发现他好像和斐波那契有关&lt;/p&gt;
&lt;p&gt;而且只会有相邻的两个数调换&lt;/p&gt;
&lt;p&gt;然后按照规律跑就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;deque&amp;gt;
using namespace std;
#define LL long long
LL f[55], Sum[55];
int a[55];
bool mark[55];
int main()
{
    LL n, k;
    scanf(&quot;%lld%lld&quot;, &amp;amp;n, &amp;amp;k);
    f[0] = f[1] = f[2] = 1;
    Sum[0] = 1, Sum[1] = 2, Sum[2] = 3;
    for (int i = 3; i &amp;lt;= n; i++)
    {
        f[i] = f[i - 1] + f[i - 2];
        Sum[i] = Sum[i - 1] + f[i];
    }
    for (int i = 1; i &amp;lt;= n; i++)
        a[i] = i;
    while (k &amp;gt; 1)
    {
        int j = lower_bound(Sum, Sum + n + 1, k) - Sum -1;
        k -= Sum[j];
        mark[n - j - 1] = mark[n - j] = 1;
    }
    for (int i = 1; i &amp;lt;= n; i++)
        if (mark[i] &amp;amp;&amp;amp; mark[i + 1])
            mark[i] = mark[i + 1] = 0, swap(a[i], a[i + 1]);
    for (int i = 1; i &amp;lt;= n; i++)
        printf(&quot;%d &quot;, a[i]);
    //while (1)
    ;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>beautiful</title><link>https://www.nekomio.com/posts/80/</link><guid isPermaLink="true">https://www.nekomio.com/posts/80/</guid><pubDate>Wed, 09 Aug 2017 20:37:20 GMT</pubDate><content:encoded>&lt;h3&gt;2.1 题目描述&lt;/h3&gt;
&lt;p&gt;Mavis 有一个序列（不必在乎这些细节），对于每个数都有一个在序列中的优美值，这个优
美值的定义是：找到序列中最长的一段，满足包含这个数并且这个数是这一段的中位数（以数
值为第一关键字，下标为第二关键字排序, 这样的话这一段的长度只有可能是奇数），那么这一
&amp;lt;!--more--&amp;gt;
段的长度就是它的优美值。Mavis 说：“对于我每次手贱点出的左右端点[l, r]，我都要找到[l,
r] 中的所有数中，最大的优美值”
但是Mavis 只会喊口号，不能解决问题，所以这个问题就交给你了&lt;/p&gt;
&lt;h3&gt;2.2 输入格式&lt;/h3&gt;
&lt;p&gt;第一行输入n 接下来n 个整数，代表ai 接下来Q，代表有Q 个区间接下来Q 行，每行
两个整数l, r(l &amp;lt;= r)，表示区间的左右端点&lt;/p&gt;
&lt;h3&gt;2.3 输出格式&lt;/h3&gt;
&lt;p&gt;对于每个区间的询问，输出答案&lt;/p&gt;
&lt;h3&gt;2.4 Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;8&lt;br /&gt;
16 19 7 8 9 11 20 16&lt;br /&gt;
8&lt;br /&gt;
3 8&lt;br /&gt;
1 4&lt;br /&gt;
2 3&lt;br /&gt;
1 1&lt;br /&gt;
5 5&lt;br /&gt;
1 2&lt;br /&gt;
2 8&lt;br /&gt;
7 8&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.5 Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;7&lt;br /&gt;
3&lt;br /&gt;
1&lt;br /&gt;
3&lt;br /&gt;
5&lt;br /&gt;
3&lt;br /&gt;
7&lt;br /&gt;
3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.6 数据范围及约定&lt;/h3&gt;
&lt;p&gt;对于30% 的数据满足：1 &amp;lt;= n;Q &amp;lt;= 50
对于70% 的数据满足：1 &amp;lt;= n;Q &amp;lt; 2000
对于100% 的数据满足，1 &amp;lt;= n &amp;lt;= 2000, 1 &amp;lt;= Q &amp;lt;= 100000, 1 &amp;lt;= ai &amp;lt;= 200&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;可以先预处理出一个数的最大的优美值&lt;br /&gt;
然后就查询就可以了，，区间最大&lt;/p&gt;
&lt;p&gt;关键是预处理&lt;br /&gt;
可以用可持久化Trie N^2logN 求出每个区间的中位数&lt;br /&gt;
然后这个问题就解决了&lt;/p&gt;
&lt;p&gt;先sort一遍在标号&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
struct data
{
    int a, pos;
    bool operator&amp;lt;(const data &amp;amp;b) const
    {
        return a == b.a ? pos &amp;lt; b.pos : a &amp;lt; b.a;
    }
} a[2005];
int comp(const data &amp;amp;a, const data &amp;amp;b)
{
    return a.pos &amp;lt; b.pos;
}
int full = 13;
struct Trie
{
    struct Trie_Node
    {
        Trie_Node *ch[2];
        int s;
        Trie_Node()
        {
            ch[0] = ch[1] = NULL;
            s = 0;
        }
    } * root[2005], *null;
    Trie()
    {
        null = new Trie_Node();
        null-&amp;gt;ch[0] = null-&amp;gt;ch[1] = null;
        root[0] = new Trie_Node();
        root[0]-&amp;gt;ch[1] = root[0]-&amp;gt;ch[0] = null;
    }
    Trie_Node *NewNode()
    {
        Trie_Node *rt = new Trie_Node();
        rt-&amp;gt;ch[0] = rt-&amp;gt;ch[1] = null;
        return rt;
    }
    void copy(Trie_Node *&amp;amp;a, Trie_Node *b)
    {
        if (b == null)
            a = null;
        else
            a = NewNode(), *a = *b;
    }
    void Insert(int x, int cnt)
    {
        copy(root[cnt], root[cnt - 1]);
        Trie_Node *rt1 = root[cnt], *rt2 = root[cnt - 1];
        for (int i = full; i &amp;gt;= 0; i--)
        {
            int k = (x &amp;gt;&amp;gt; i) &amp;amp; 1;
            copy(rt1-&amp;gt;ch[k], rt2-&amp;gt;ch[k]);
            if (rt1-&amp;gt;ch[k] == null)
                rt1-&amp;gt;ch[k] = NewNode();
            rt1 = rt1-&amp;gt;ch[k], rt2 = rt2-&amp;gt;ch[k];
            rt1-&amp;gt;s++;
        }
    }
    int kth(int k, int l, int r)
    {
        int res = 0;
        Trie_Node *rt1 = root[r], *rt2 = root[l - 1];
        for (int i = full; i &amp;gt;= 0; i--)
        {
            if (k &amp;gt; rt1-&amp;gt;ch[0]-&amp;gt;s - rt2-&amp;gt;ch[0]-&amp;gt;s)
            {
                k -= (rt1-&amp;gt;ch[0]-&amp;gt;s - rt2-&amp;gt;ch[0]-&amp;gt;s);
                res |= (1 &amp;lt;&amp;lt; i);
                rt1 = rt1-&amp;gt;ch[1], rt2 = rt2-&amp;gt;ch[1];
            }
            else
            {
                rt1 = rt1-&amp;gt;ch[0], rt2 = rt2-&amp;gt;ch[0];
            }
        }
        return res;
    }
} root;
int pos[2005];
int Maxn[2005 &amp;lt;&amp;lt; 2];
int Max[2005 &amp;lt;&amp;lt; 2];
#define lch l, m, rt &amp;lt;&amp;lt; 1
#define rch m + 1, r, rt &amp;lt;&amp;lt; 1 | 1
void Update(int rt)
{
    Max[rt] = max(Max[rt &amp;lt;&amp;lt; 1], Max[rt &amp;lt;&amp;lt; 1 | 1]);
}
void buildtree(int l, int r, int rt)
{
    if (l == r)
    {
        Max[rt] = Maxn[l];
        return;
    }
    int m = l + r &amp;gt;&amp;gt; 1;
    buildtree(lch);
    buildtree(rch);
    Update(rt);
}
int Query(int L, int R, int l, int r, int rt)
{
    if (L &amp;lt;= l &amp;amp;&amp;amp; R &amp;gt;= r)
        return Max[rt];
    int m = l + r &amp;gt;&amp;gt; 1;
    int MAX = 0;
    if (L &amp;lt;= m)
        MAX = max(MAX, Query(L, R, lch));
    if (R &amp;gt; m)
        MAX = max(MAX, Query(L, R, rch));
    return MAX;
}
int main()
{
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;a[i].a);
        a[i].pos = i;
    }
    sort(a + 1, a + n + 1);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        a[i].a = i;
        pos[a[i].a] = a[i].pos;
    }
    sort(a + 1, a + n + 1, comp);
    for (int i = 1; i &amp;lt;= n; i++)
        root.Insert(a[i].a, i);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        for (int j = 1; j &amp;lt;= i; j++)
        {
            if ((i - j + 1) &amp;amp; 1)
            {
                int k = pos[root.kth((i - j + 1) / 2 + 1, j, i)];
                Maxn[k] = max(Maxn[k], (i - j + 1));
            }
        }
    }
    buildtree(1, n, 1);
    int Q, l, r;
    scanf(&quot;%d&quot;, &amp;amp;Q);
    while (Q--)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;l, &amp;amp;r);
        printf(&quot;%d\n&quot;, Query(l, r, 1, n, 1));
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>calc</title><link>https://www.nekomio.com/posts/79/</link><guid isPermaLink="true">https://www.nekomio.com/posts/79/</guid><pubDate>Wed, 09 Aug 2017 20:34:24 GMT</pubDate><content:encoded>&lt;h3&gt;1.1 题目描述&lt;/h3&gt;
&lt;p&gt;给定一个序列a，a 中任意两个元素都不等。如果i&amp;lt;j, 且a[i]&amp;lt;a[j]，则我们称a[i],a[j] 为一
个顺序对，这个顺序对的值是指a[i+1],a[i+2]…….a[j-1] 中比a[i] 大，且比a[j] 小的数的个数。
求一个序列中所有顺序对的值的和。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;1.2 输入格式&lt;/h3&gt;
&lt;p&gt;第一行n 然后n 个整数表示ai&lt;/p&gt;
&lt;h3&gt;1.3 输出格式&lt;/h3&gt;
&lt;p&gt;一个整数，表示答案&lt;/p&gt;
&lt;h3&gt;1.4 Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5&lt;br /&gt;
1 5 3 4 2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1.5 Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1.6 数据范围及约定&lt;/h3&gt;
&lt;p&gt;对于30% 的数据满足：1 &amp;lt;= n &amp;lt;= 300
对于另外30% 的数据满足：1 &amp;lt;= n &amp;lt;= 3000
对于100% 的数据满足，1 &amp;lt;= n &amp;lt;= 300000, 1 &amp;lt;= ai &amp;lt;= 10^9&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;反正挺伤心的没有想到正确的方向&lt;/p&gt;
&lt;p&gt;对于每一个数他对后面的数所造成的贡献就是&lt;br /&gt;
他前面比他小的数的个数&lt;/p&gt;
&lt;p&gt;然后树状数组维护一下就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
long long Sum[2][300005];
#define lowbit(_) ((_) &amp;amp; (-_))
int n;
void add(int p, int x, int w)
{
    for (int i = x; i &amp;lt;= n; i += lowbit(i))
        Sum[p][i] += w;
}
long long Gsum(int p, int x)
{
    long long ans = 0;
    for (int i = x; i; i -= lowbit(i))
        ans += Sum[p][i];
    return ans;
}
int a[300005], Hash[300005];
int main()
{
    scanf(&quot;%d&quot;, &amp;amp;n);
    long long ans = 0;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
        Hash[i] = a[i];
    }
    sort(Hash + 1, Hash + n + 1);
    int tot = unique(Hash + 1, Hash + n + 1) - Hash - 1;
    for (int i = 1; i &amp;lt;= n; i++)
        a[i] = lower_bound(Hash + 1, Hash + tot + 1,a[i]) - Hash;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        int x = Gsum(0, a[i] - 1);
        add(0, a[i], 1);
        ans += Gsum(1, a[i] - 1);
        add(1, a[i], x);
    }
    printf(&quot;%lld\n&quot;, ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>与非</title><link>https://www.nekomio.com/posts/78/</link><guid isPermaLink="true">https://www.nekomio.com/posts/78/</guid><pubDate>Tue, 08 Aug 2017 20:13:12 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;作为一名新世纪共产主义的接班人，你认识到了资本主义的软弱性与妥协性，决定全面根除资本主义，跑步迈入共产主义。但是当你即将跨入共产主义大门的时候，遇到了万恶的资本家留下的与非电路封印，经过千辛万苦的研究，你终于把复杂的破解转变成了以下问题：
&amp;lt;!--more--&amp;gt;
初始时你有一个空序列，之后有N个操作。&lt;/p&gt;
&lt;p&gt;操作分为一下两种：&lt;/p&gt;
&lt;p&gt;1 x：在序列末尾插入一个元素x(x=0或1)。&lt;/p&gt;
&lt;p&gt;2 L R：定义nand[L,R]为序列第L个元素到第R个元素的与非和，询问nand[L,L]^nand[L,L+1]^nand[L,L+2]^......^nand[L,R]。&lt;/p&gt;
&lt;p&gt;Nand就是先与，再取反&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;从文件nand.in中读入数据。&lt;/p&gt;
&lt;p&gt;输入第一行一个正整数N，表示操作个数。&lt;/p&gt;
&lt;p&gt;接下来N行表示N个操作。&lt;/p&gt;
&lt;p&gt;为了体现程序的在线性，记lastans为上一次操作二的回答，初始lastans=0,。对于操作1，你需要对x异或lastans。对于操作二，设现在序列中的元素个数为M，如果lastans=1，那么你需要作如下操作：L=M-L+1,R=M-R+1,swap(L,R)&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输出到nand.out中。&lt;/p&gt;
&lt;p&gt;输出有多行。为对于每一个操作二的回答。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;6&lt;br /&gt;
1 1&lt;br /&gt;
1 1&lt;br /&gt;
1 0&lt;br /&gt;
2 1 2&lt;br /&gt;
2 1 3&lt;br /&gt;
2 2 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1&lt;br /&gt;
0&lt;br /&gt;
0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【数据规模和约定】&lt;/h3&gt;
&lt;p&gt;数据点	N的规模 操作一的个数M1 操作二的个数M2&lt;/p&gt;
&lt;p&gt;1	N&amp;lt;=1000	M1&amp;lt;=500	M2&amp;lt;=500
2	N&amp;lt;=1000	M1&amp;lt;=500	M2&amp;lt;=500
3	N&amp;lt;=200000	M1&amp;lt;=100000	M2&amp;lt;=100000
4	N&amp;lt;=200000	M1&amp;lt;=100000	M2&amp;lt;=100000
5	N&amp;lt;=1000000	M1&amp;lt;=900000	M2&amp;lt;=100000
N&amp;lt;=4000000 M1&amp;lt;=3900000	M2&amp;lt;=100000&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;想了好久  也没想出来
最后放弃了&lt;/p&gt;
&lt;p&gt;其实可以分类讨论&lt;/p&gt;
&lt;p&gt;最后会发现一个结论&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
using namespace std;
inline int read()
{
    int s = 0, k = 1;
    char ch = getchar();
    while (ch &amp;lt; &apos;0&apos; || ch &amp;gt; &apos;9&apos;)
        k = ch == &apos;-&apos; ? -1 : k, ch = getchar();
    while (ch &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; ch &amp;lt;= &apos;9&apos;)
        s = s * 10 + (ch ^ 48), ch = getchar();
    return s * k;
}
int n;
bool Sum[4000005];
bool f[4000005];
bool a[4000005];
int main()
{
    n = read();
    int t = 0, op, l, r;
    int lastans = 0;
    while (n--)
    {
        op = read();
        if (op == 1)
        {
            l = read() ^ lastans;
            t++;
            a[t] = l;
            if (t == 1)
                f[t] = a[t];
            else
                f[t] = !(f[t - 1] &amp;amp; l);
            Sum[t] = Sum[t - 1] ^ f[t];
        }
        else
        {
            l = read(), r = read();
            if (lastans)
            {
                l = t - l + 1;
                r = t - r + 1;
                swap(l, r);
            }
            lastans = a[l];
            int i = l, now = !(a[l] &amp;amp; a[l + 1]);
            while (now != f[i + 1] &amp;amp;&amp;amp; i &amp;lt; r)
            {
                lastans ^= now;
                i++;
                now = !(now &amp;amp; a[i + 1]);
            }
            if (i &amp;lt; r)
            {
                lastans ^= Sum[r] ^ Sum[i];
            }
            printf(&quot;%d\n&quot;, lastans);
        }
    }
    //while (1);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Number</title><link>https://www.nekomio.com/posts/77/</link><guid isPermaLink="true">https://www.nekomio.com/posts/77/</guid><pubDate>Tue, 08 Aug 2017 20:07:55 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;一个排列，求出了 a 数组，其中 ai 表示第 i 个数左边有多少个数比它小&lt;/p&gt;
&lt;p&gt;计算出原来的排列
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第一行输入 n 接下来 n - 1 个整数 ai，下标从 2 开始&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输出 n 个整数表示原排列&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5&lt;br /&gt;
1&lt;br /&gt;
2&lt;br /&gt;
1&lt;br /&gt;
0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;br /&gt;
4&lt;br /&gt;
5&lt;br /&gt;
3&lt;br /&gt;
1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;提示&lt;/h3&gt;
&lt;p&gt;对于 20% 的数据满足：1 ≤ n ≤ 10
对于 50% 的数据满足：1 ≤ n ≤ 1000
对于 100% 的数据满足，1 ≤ n ≤ 100000
保证解存在&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;输入的树就是按顺序插入时比他小的数的数量&lt;br /&gt;
用一颗平衡树维护就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
using namespace std;
struct Node
{
    Node *ch[2];
    int s, id, key;
    Node(int x)
    {
        key = rand();
        id = x;
        s = 1;
        ch[0] = ch[1] = NULL;
    }
#define size(_) ((_) ? (_)-&amp;gt;s : 0)
    void Update()
    {
        s = size(ch[1]) + size(ch[0]) + 1;
    }
} * root;
Node *Merge(Node *A, Node *B)
{
    if (!A)
        return B;
    if (!B)
        return A;
    if (A-&amp;gt;key &amp;lt; B-&amp;gt;key)
    {
        A-&amp;gt;ch[1] = Merge(A-&amp;gt;ch[1], B);
        A-&amp;gt;Update();
        return A;
    }
    else
    {
        B-&amp;gt;ch[0] = Merge(A, B-&amp;gt;ch[0]);
        B-&amp;gt;Update();
        return B;
    }
}
typedef pair&amp;lt;Node *, Node *&amp;gt; DNode;
DNode Split(Node *rt, int k)
{
    if (!rt)
        return DNode(NULL, NULL);
    DNode o;
    if (size(rt-&amp;gt;ch[0]) &amp;gt;= k)
    {
        o = Split(rt-&amp;gt;ch[0], k);
        rt-&amp;gt;ch[0] = o.second;
        rt-&amp;gt;Update();
        o.second = rt;
    }
    else
    {
        o = Split(rt-&amp;gt;ch[1], k - size(rt-&amp;gt;ch[0]) - 1);
        rt-&amp;gt;ch[1] = o.first;
        rt-&amp;gt;Update();
        o.first = rt;
    }
    return o;
}
void Insert(int x, int k)
{
    DNode y = Split(root, k);
    Node *n = new Node(x);
    root = Merge(y.first, Merge(n, y.second));
}
int Ind = 0;
int a[100005];
void DFS(Node *rt)
{
    if (rt)
    {
        DFS(rt-&amp;gt;ch[0]);
        a[rt-&amp;gt;id] = ++Ind;
        DFS(rt-&amp;gt;ch[1]);
    }
}
int main()
{
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    int c;
    Insert(1, 0);
    for (int i = 2; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;c);
        Insert(i, c);
    }
    DFS(root);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        printf(&quot;%d\n&quot;, a[i]);
    }
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Evensgn 的债务</title><link>https://www.nekomio.com/posts/76/</link><guid isPermaLink="true">https://www.nekomio.com/posts/76/</guid><pubDate>Tue, 08 Aug 2017 19:58:44 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;Evensgn 有一群好朋友，他们经常互相借钱。假如说有三个好朋友 A，B，C。&lt;/p&gt;
&lt;p&gt;A 欠 B 20 元，B 欠 C 20 元，总债务规模为 20+20=40 元。Evensgn 是个追求简约
&amp;lt;!--more--&amp;gt;
的人，他觉得这样的债务太繁杂了。他认为，上面的债务可以完全等价为 A 欠 C&lt;/p&gt;
&lt;p&gt;20 元，B 既不欠别人，别人也不欠他。这样总债务规模就压缩到了 20 元。&lt;/p&gt;
&lt;p&gt;现在给定 n 个人和 m 条债务关系。Evensgn 想找到一种新的债务方案，使得&lt;/p&gt;
&lt;p&gt;每个人欠钱的总数不变，或被欠钱的总数不变（但是对象可以发生变化），并且使&lt;/p&gt;
&lt;p&gt;得总债务规模最小。&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;输入文件第一行两个数字 n; m，含义如题目所述。&lt;/p&gt;
&lt;p&gt;接下来 m 行，每行三个数字 ai; bi; ci，表示 ai 欠 bi 的钱数为 ci。&lt;/p&gt;
&lt;p&gt;注意，数据中关于某两个人 A 和 B 的债务信息可能出现多次，将其累加即可。&lt;/p&gt;
&lt;p&gt;如”A 欠 B 20 元”、”A 欠 B 30 元”、”B 欠 A 10 元”，其等价为”A 欠 B 40 元”。&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输出文件共一行，输出最小的总债务规模。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;样例输入 1&lt;br /&gt;
5 3&lt;br /&gt;
1 2 10&lt;br /&gt;
2 3 1&lt;br /&gt;
2 4 1&lt;br /&gt;
样例输入 2&lt;br /&gt;
4 3&lt;br /&gt;
1 2 1&lt;br /&gt;
2 3 1&lt;br /&gt;
3 1 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;样例输出 1&lt;br /&gt;
10&lt;br /&gt;
样例输出 2&lt;br /&gt;
0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;考试的时候想了想&lt;br /&gt;
发现可以理解为&lt;br /&gt;
每一个人将他的真正的需要交出的钱一起交出&lt;br /&gt;
然后就需要拿钱的人去拿&lt;br /&gt;
统计一下就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
int in[1000005], out[1000005];
long long Sum = 0;
int main()
{
    int n, m, a, b, c;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d%d%d&quot;, &amp;amp;a, &amp;amp;b, &amp;amp;c);
        out[a] += c;
        in[b] += c;
        Sum += c;
    }
    for (int i = 1; i &amp;lt;= n; i++)
    {
        Sum -= min(out[i], in[i]);
    }
    printf(&quot;%lld\n&quot;, Sum);
    //while (1)
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>HDU1693 Eat the Trees &amp;&amp; BZOJ 1210 [HNOI2004] 邮递员</title><link>https://www.nekomio.com/posts/75/</link><guid isPermaLink="true">https://www.nekomio.com/posts/75/</guid><pubDate>Tue, 08 Aug 2017 19:23:32 GMT</pubDate><content:encoded>&lt;p&gt;先来一个最入门的
HDU 1693&lt;/p&gt;
&lt;p&gt;哈密顿回路 多回路&lt;/p&gt;
&lt;h3&gt;Problem Description&lt;/h3&gt;
&lt;p&gt;Most of us know that in the game called DotA(Defense of the Ancient), Pudge is a strong hero in the first period of the game. When the game goes to end however, Pudge is not a strong hero any more.
So Pudge’s teammates give him a new assignment—Eat the Trees!
&amp;lt;!--more--&amp;gt;
The trees are in a rectangle N * M cells in size and each of the cells either has exactly one tree or has nothing at all. And what Pudge needs to do is to eat all trees that are in the cells.
There are several rules Pudge must follow:
I. Pudge must eat the trees by choosing a circuit and he then will eat all trees that are in the chosen circuit.
II. The cell that does not contain a tree is unreachable, e.g. each of the cells that is through the circuit which Pudge chooses must contain a tree and when the circuit is chosen, the trees which are in the cells on the circuit will disappear.
III. Pudge may choose one or more circuits to eat the trees.&lt;/p&gt;
&lt;p&gt;Now Pudge has a question, how many ways are there to eat the trees?
At the picture below three samples are given for N = 6 and M = 3(gray square means no trees in the cell, and the bold black line means the chosen circuit(s))
&lt;img src=&quot;https://i.loli.net/2017/08/08/5989a4fbd2f53.jpg&quot; alt=&quot;HDU1693&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases.
For each case, the first line contains the integer numbers N and M, 1&amp;lt;=N, M&amp;lt;=11. Each of the next N lines contains M numbers (either 0 or 1) separated by a space. Number 0 means a cell which has no trees and number 1 means a cell that has exactly one tree.&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;For each case, you should print the desired number of ways in one line. It is guaranteed, that it does not exceed 263 – 1. Use the format in the sample.&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;br /&gt;
6 3&lt;br /&gt;
1 1 1&lt;br /&gt;
1 0 1&lt;br /&gt;
1 1 1&lt;br /&gt;
1 1 1&lt;br /&gt;
1 0 1&lt;br /&gt;
1 1 1&lt;br /&gt;
2 4&lt;br /&gt;
1 1 1 1&lt;br /&gt;
1 1 1 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Case 1: There are 3 ways to eat the trees.&lt;br /&gt;
Case 2: There are 2 ways to eat the trees.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本题就是一道最基础的求回路的题目&lt;br /&gt;
因为我们不需要 要求一条回路，所以只需记录是否有插头就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
const int Max = (1 &amp;lt;&amp;lt; 12) + 10;
int n, m;
int mp[12][12];
long long DP[12][12][Max];

void dp()
{
    memset(DP, 0, sizeof(DP));
    DP[0][m][0] = 1;
    int bit = 1 &amp;lt;&amp;lt; (m + 1);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        for (int j = 0; j &amp;lt; (bit &amp;gt;&amp;gt; 1); j++)
        {
            DP[i][0][j &amp;lt;&amp;lt; 1] = DP[i - 1][m][j];
        }
        for (int j = 1; j &amp;lt;= m; j++)
        {
            for (int k = 0; k &amp;lt; bit; k++)
            {
                int x = 1 &amp;lt;&amp;lt; (j - 1);
                int y = 1 &amp;lt;&amp;lt; j;
                if (mp[i][j])
                {
                    DP[i][j][k] += DP[i][j - 1][k ^ x ^ y];
                    if ((k &amp;amp; x) &amp;amp;&amp;amp; (k &amp;amp; y))
                        continue;
                    if (!(k &amp;amp; x) &amp;amp;&amp;amp; !(k &amp;amp; y))
                        continue;
                    DP[i][j][k] += DP[i][j - 1][k];
                }
                else
                {
                    if (!(k &amp;amp; x) &amp;amp;&amp;amp; !(k &amp;amp; y))
                        DP[i][j][k] = DP[i][j - 1][k];
                    else
                        DP[i][j][k] = 0;
                }
            }
        }
    }
}
int main()
{
    int t, num = 0;
    scanf(&quot;%d&quot;, &amp;amp;t);
    while (t--)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
        for (int i = 1; i &amp;lt;= n; i++)
        {
            for (int j = 1; j &amp;lt;= m; j++)
            {
                scanf(&quot;%d&quot;, &amp;amp;mp[i][j]);
            }
        }
        dp();
        printf(&quot;Case %d: There are %lld ways to eat the trees.\n&quot;, ++num, DP[n][m][0]);
    }
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后是稍微复杂点的&lt;/p&gt;
&lt;p&gt;单回路&lt;/p&gt;
&lt;p&gt;【题目描述】&lt;/p&gt;
&lt;p&gt;Smith在P市的邮政局工作，他每天的工作是从邮局出发，到自己所管辖的所有邮筒取信件，然后带回邮局。
他所管辖的邮筒非常巧地排成了一个m*n的点阵（点阵中的间距都是相等的）。左上角的邮筒恰好在邮局的门口。
Smith是一个非常标新立异的人，他希望每天都能走不同的路线，但是同时，他又不希望路线的长度增加，他想知道他有多少条不同的路线可走。&lt;/p&gt;
&lt;p&gt;你的程序需要根据给定的输入，给出符合题意的输出：
l 输入包括点阵的m和n的值；
l 你需要根据给出的输入，计算出Smith可选的不同路线的总条数；&lt;/p&gt;
&lt;p&gt;【输入格式】&lt;/p&gt;
&lt;p&gt;输入文件postman.in只有一行。包括两个整数m, n(1 &amp;lt;= m &amp;lt;= 10, 1 &amp;lt;= n &amp;lt;= 20)，表示了Smith管辖内的邮筒排成的点阵。&lt;/p&gt;
&lt;p&gt;【输出格式】&lt;/p&gt;
&lt;p&gt;输出文件只有一行，只有一个整数，表示Smith可选的不同路线的条数。
【样例输入】&lt;/p&gt;
&lt;p&gt;2 2 说明：该输入表示，Smith管辖了2*2的一个邮筒点阵。
【样例输出】&lt;/p&gt;
&lt;p&gt;2
【提示】
&lt;img src=&quot;https://i.loli.net/2017/08/08/5989a54398a57.png&quot; alt=&quot;COGS邮递员&quot; /&gt;&lt;/p&gt;
&lt;p&gt;详情请看代码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;deque&amp;gt;
using namespace std;
#define LL long long
const int BA = 100000, SIZEN = 10, SIZEM = 20, BASE = 200000;
int N, M;
int H[BASE];
class BigNum /**高精度 */
{
  public:
    int n;
    int s[50];
    void operator=(int a)
    {
        n = 1;
        memset(s, 0, sizeof(s));
        s[0] = a;
    }
    void operator+=(BigNum a)
    {
        n = max(n, a.n) + 1;
        for (int i = 0; i &amp;lt;= n; i++)
        {
            s[i] += a.s[i];
            s[i + 1] += s[i] / BA;
            s[i] %= BA;
        }
        while (n &amp;gt; 0 &amp;amp;&amp;amp; s[n - 1] == 0)
        {
            n--;
        }
    }
    void operator*=(int a)
    {
        n++;
        for (int i = 0; i &amp;lt;= n; i++)
            s[i] *= a;
        for (int i = 0; i &amp;lt;= n; i++)
        {
            s[i + 1] += s[i] / BA;
            s[i] %= BA;
        }
        while (n &amp;gt; 0 &amp;amp;&amp;amp; s[n - 1] == 0)
        {
            n--;
        }
    }
    void print()
    {
        printf(&quot;%d&quot;, s[n - 1]);
        for (int i = n - 2; i &amp;gt;= 0; i--)
            printf(&quot;%05d&quot;, s[i]);
    }
} ans;

class Pair /**映射表 */
{
  public:
    BigNum Sum;
    LL Id;
    Pair() {}
    Pair(LL a, BigNum b)
    {
        Id = a;
        Sum = b;
    }
};
deque&amp;lt;Pair&amp;gt; f[2]; /**循环数组 */
void read()       /**read */
{
    scanf(&quot;%d%d&quot;, &amp;amp;N, &amp;amp;M);
    if (N &amp;lt; M)
        swap(N, M);
}
int Get(int x, int j) /**取4进制的操作 */
{
    x &amp;gt;&amp;gt;= 2 * (j - 1);
    x &amp;amp;= 3;
    return x;
}
int Change(int x, int j, int t) /**把x的第j位改成t */
{
    int tmp = x &amp;gt;&amp;gt; (2 * (j - 1));
    x -= tmp &amp;lt;&amp;lt; (j - 1) * 2;
    tmp &amp;gt;&amp;gt;= 2;
    x += tmp &amp;lt;&amp;lt; 2 * j;
    x += t &amp;lt;&amp;lt; ((j - 1) * 2);
    return x;
}
int Find(int x, int j, int dat) /**找与他相连的括号 */
{
    int now = dat, k = j;
    while (k &amp;gt;= 1 &amp;amp;&amp;amp; k &amp;lt;= M + 1)
    {
        k += now;
        int tmp = Get(x, k);
        if (tmp == 1)
            dat++;
        if (tmp == 2)
            dat--;
        if (dat == 0)
            return k;
    }
}
void Push(int k, int Id, BigNum Sum) /**插入hash表 */
{
    int now = Id % BASE;
    while (H[now]) /**如果有 */
    {
        if (f[k][H[now]].Id == Id) /**且就是这个状态 */
        {
            f[k][H[now]].Sum += Sum; /**加值，和并答案 */
            return;
        }
        now++; /**找自己的状态 */
        if (now == BASE)
            now = 0;
    }
    H[now] = f[k].size(); /**如果第一次出现 */
    f[k].push_back(Pair(Id, Sum));
}
/**
 * 1为左括号
 * 2为右括号
 * 0为无括号
 */
void DP()
{
    int k = 0;
    BigNum p;
    p = 1; /**初始化状态 */
    f[k].push_back(Pair(0, p));
    for (int i = 1; i &amp;lt;= N; i++)
    {
        for (int j = 1; j &amp;lt;= M; j++)
        {
            k ^= 1;                  /**滚动数组 */
            f[k].clear();            /**清空本维 */
            memset(H, 0, sizeof(H)); /**hash 数组 */
            for (int m = 0; m &amp;lt; f[k ^ 1].size(); m++)
            {
                int Id = f[k ^ 1][m].Id;       /**取状态 */
                BigNum date = f[k ^ 1][m].Sum; /**取值 */
                int L = Get(Id, j), U = Get(Id, j + 1);
                /**
                 * L:左面的 ，U: 右面的
                 */
                int tmp;      /**分类讨论开始 */
                if (!L &amp;amp;&amp;amp; !U) /**两个插头都是无插头状态 */
                {
                    if (i != N &amp;amp;&amp;amp; j != M) /**如果不是最后一个 */
                    {
                        tmp = Change(Id, j, 1); /**构造一组新的括号 */
                        tmp = Change(tmp, j + 1, 2);
                        Push(k, tmp, date); /**插入Hash */
                    }
                }
                else if (!L &amp;amp;&amp;amp; U) /**左面的没有 */
                {
                    if (j != M)            /**向右转移 */
                        Push(k, Id, date); /**延续状态 当j==M事不能向右动*/
                    if (i != N)            /**向下转移 */
                    {
                        /**将L,U位置的 状态互换 转移*/
                        tmp = Change(Id, j, U);
                        tmp = Change(tmp, j + 1, 0);
                        Push(k, tmp, date);
                    }
                }
                else if (L &amp;amp;&amp;amp; !U) /**上面的没有 */
                {
                    if (i != N) /**向下 */
                        Push(k, Id, date);
                    if (j != M) /**向右 */
                    {
                        /**于上同理 */
                        tmp = Change(Id, j, 0);
                        tmp = Change(tmp, j + 1, L);
                        Push(k, tmp, date);
                    }
                }
                else if (L == 1 &amp;amp;&amp;amp; U == 1) /**两个都是左括号 */
                {
                    tmp = Change(Id, Find(Id, j + 1, 1), 1); /**将与上面相连的右括号转为左括号 */
                    tmp = Change(tmp, j, 0);                 /**这两位都制为无括号 */
                    tmp = Change(tmp, j + 1, 0);
                    Push(k, tmp, date);
                }
                else if (L == 2 &amp;amp;&amp;amp; U == 2)                /**两个都是右括号 */
                {                                         /**与上面对称 */
                    tmp = Change(Id, Find(Id, j, -1), 2); /**将与左面相连的左括号制为右括号 */
                    tmp = Change(tmp, j, 0);               /**这两位都为无括号 */
                    tmp = Change(tmp, j + 1, 0);
                    Push(k, tmp, date);
                }
                else if (L == 2 &amp;amp;&amp;amp; U == 1) /**左插头为右括号 上插头为左括号 */
                {                          /**都制为无 */
                    tmp = Change(Id, j, 0);
                    tmp = Change(tmp, j + 1, 0);
                    Push(k, tmp, date);
                }
                else if (L == 1 &amp;amp;&amp;amp; U == 2)
                {
                    if (i == N &amp;amp;&amp;amp; j == M)
                        ans += date;
                }
            }
        }
        for (int km = 0; km &amp;lt; f[k].size(); km++) /**提前换行准备为下一行使用 */
            f[k][km].Id &amp;lt;&amp;lt;= 2;
    }
    ans *= 2;
    ans.print();
}
int main()
{
    //freopen(&quot;postman.in&quot;, &quot;r&quot;, stdin);
    //freopen(&quot;postman.out&quot;, &quot;w&quot;, stdout);
    read();
    if (M == 1)
    {
        printf(&quot;1&quot;);
        return 0;
    }
    DP();
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>书</title><link>https://www.nekomio.com/posts/74/</link><guid isPermaLink="true">https://www.nekomio.com/posts/74/</guid><pubDate>Tue, 08 Aug 2017 13:10:59 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;Hazel有n本书，编号1为n到 ，叠成一堆。当她每次抽出一本书的时候，上方的书会因重力而下落，这本被取出的书则会被放置在书堆顶。
每次有pi的概率抽取编号为i的书。她每次抽书所消耗的体力与这本书在这堆中是第几本成正比。具体地，抽取堆顶的书所耗费体力值为1 ，抽取第二本耗费体力值为2 ，以此类推。
&amp;lt;!--more--&amp;gt;
现在 想知道，在很久很久以后（可以认为几乎是无穷的），她每次抽书所耗费的体力的期望值是多少。
最终的答案显然可以表示成a/b的形式，请输出a*(b^-1)模1e9+7的值。&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;第一行一个整数n
接下来n行，每行两个整数ai，bi，代表抽取第i本书的概率是ai/bi
保证所有书的概率和等于1&lt;/p&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;输出一行一个整数，代表期望值&lt;/p&gt;
&lt;h3&gt;【输入样例1】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;br /&gt;
227494 333333&lt;br /&gt;
105839 333333&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【输出样例1】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;432679642&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;【输入样例2】&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;10&lt;br /&gt;
159073 999999&lt;br /&gt;
1493 142857&lt;br /&gt;
3422 333333&lt;br /&gt;
4945 37037&lt;br /&gt;
2227 111111&lt;br /&gt;
196276 999999&lt;br /&gt;
190882 999999&lt;br /&gt;
142721 999999&lt;br /&gt;
34858 999999&lt;br /&gt;
101914 999999&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【输出样例2】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;871435606&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【数据规模与约定】&lt;/h3&gt;
&lt;p&gt;对于30%的数据，1&amp;lt;=n&amp;lt;=10。
对于100%的数据，1&amp;lt;=n&amp;lt;=1000,0&amp;lt;=ai&amp;lt;=bi,bi!=0。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;期望DP&lt;/p&gt;
&lt;p&gt;P表示概率
E表示期望体力&lt;/p&gt;
&lt;p&gt;$$ Ans = \sum_{i=1}^{n}{P_i&lt;em&gt;E_i} $$
$$ = \sum_{i=1}^{n}{P_i&lt;/em&gt;(1+\sum_{j=1且就i!=j}^{n}{P_{抽到j比i晚}})}$$
$$ = \sum_{i=1}^{n}{P_i*(1+\sum_{j=1且j!=i}^{n}{\frac{P_j}{P_i+P_j}})}$$&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
#define LL long long
const LL P = 1e9 + 7;
LL pow_mod(LL a, int b)
{
    LL ans = 1;
    while (b)
    {
        if (b &amp;amp; 1)
            ans = ans * a % P;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % P;
    }
    return ans;
}
LL q[1005];
int main()
{
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    LL a, b;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%lld%lld&quot;, &amp;amp;a, &amp;amp;b);
        q[i] = a * pow_mod(b, P - 2) % P;
    }
    LL ans = 0;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        LL sum = 0;
        for (int j = 1; j &amp;lt;= n; j++)
        {
            if (j == i)
                continue;
            sum = (sum + q[j] * pow_mod(q[i] + q[j], P - 2) % P) % P;
        }
        ans = (ans + (1 + sum) * q[i]) % P;
    }
    printf(&quot;%lld&quot;, ans);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>就</title><link>https://www.nekomio.com/posts/73/</link><guid isPermaLink="true">https://www.nekomio.com/posts/73/</guid><pubDate>Tue, 08 Aug 2017 12:53:42 GMT</pubDate><content:encoded>&lt;h3&gt;【背景描述】&lt;/h3&gt;
&lt;p&gt;一排 N 个数， 第 i 个数是 Ai ， 你要找出 K 个不相邻的数， 使得他们的和最大。
请求出这个最大和。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;第一行两个整数 N 和 K。
接下来一行 N 个整数， 第 i 个整数表示 Ai 。&lt;/p&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;一行一个整数表示最大和， 请注意答案可能会超过 int 范围&lt;/p&gt;
&lt;h3&gt;【样例输入】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3 2&lt;br /&gt;
4 5 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【样例输出】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;7&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【数据范围】&lt;/h3&gt;
&lt;p&gt;对于 20% 的数据， N, K ≤ 20 。
对于 40% 的数据， N, K ≤ 1000 。
对于 60% 的数据， N, K ≤ 10000 。
对于 100% 的数据， N, K ≤ 100000 ， 1 ≤ Ai ≤ 1000000000。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;贪心，每次用一个堆维护最大值
每次都找最大的和他两边的合并，其实是一个可反悔的贪心&lt;/p&gt;
&lt;p&gt;主要边界处理&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;set&amp;gt;
#include &amp;lt;list&amp;gt;

using namespace std;

#define LL long long

struct data
{
    LL Num;
    int pos;
    bool operator&amp;lt;(const data &amp;amp;a) const
    {
        return Num == a.Num ? pos &amp;lt; a.pos : Num &amp;gt; a.Num;
    }
};

set&amp;lt;data&amp;gt; st;

LL a[100005];
int nex[100005], fre[100005];

LL Merge()
{
    int A = st.begin()-&amp;gt;pos;
    LL ans = a[A];
    a[A] = -a[A];
    a[A] += a[fre[A]], a[A] += a[nex[A]];
    st.erase(st.begin());
    st.erase((data){a[fre[A]], fre[A]});
    st.erase((data){a[nex[A]], nex[A]});
    st.insert((data){a[A], A});
    if (fre[fre[A]])
        nex[fre[fre[A]]] = A;
    if (nex[nex[A]])
        fre[nex[nex[A]]] = A;
    fre[A] = fre[fre[A]];
    nex[A] = nex[nex[A]];
    return ans;
}
int main()
{
    int n, k;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;k);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%lld&quot;, &amp;amp;a[i]);
        fre[i] = i - 1;
        nex[i] = i + 1;
        st.insert((data){a[i], i});
    }
    nex[n] = 0;
    a[0] = 0x8080808080808080ll;
    LL ans = 0;
    while (k--)
    {
        ans += Merge();
    }
    printf(&quot;%lld&quot;, ans);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Passward</title><link>https://www.nekomio.com/posts/72/</link><guid isPermaLink="true">https://www.nekomio.com/posts/72/</guid><pubDate>Tue, 08 Aug 2017 12:52:32 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;你来到了一个庙前，庙牌上有一个仅包含小写字母的字符串 s。
传说打开庙门的密码是这个字符串的一个子串 t，并且 t 既是 s 的前缀又是 s 的后缀并且还在 s 的中间位置出现过一次。
&amp;lt;!--more--&amp;gt;
如果存在这样的串，请你输出这个串，如有多个满足条件的串，输出最长的那一个。
如果不存在这样的串，输出&quot;Just a legend&quot;(去掉引号)。&lt;/p&gt;
&lt;h3&gt;输入格式：&lt;/h3&gt;
&lt;p&gt;仅一行，字符串 s。&lt;/p&gt;
&lt;h3&gt;输出格式：&lt;/h3&gt;
&lt;p&gt;如题所述&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;fixprefixsuffix&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出：&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;fix&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;数据范围：&lt;/h3&gt;
&lt;p&gt;对于 60%的数据， s 的长度&amp;lt;=100
对于 100%的数据， s 的长度&amp;lt;=100000&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;hash 淼之&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
using namespace std;
char s[2000005];
unsigned long long base = 31;
unsigned long long has[2000005];
unsigned long long Pow(unsigned long long b,int i)
{
    unsigned long long ans = 1;
    while(i)
    {
        if(i &amp;amp; 1)
            ans = ans * b;
        i &amp;gt;&amp;gt;= 1;
        b = b * b;
    }
    return ans;
}
int main()
{
    freopen(&quot;fool.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;fool.out&quot;,&quot;w&quot;,stdout);
    int q;
    scanf(&quot;%d&quot;,&amp;amp;q);
    while(q--){
        scanf(&quot;%s&quot;, s + 1);
        int len = strlen(s + 1);
        for (int i = 1; i &amp;lt;= len; i++)
        {
            has[i] = has[i - 1] * base + s[i];
        }
        int ans = 0;
        for (int i = 1; i &amp;lt;= len; i++)
        {
            unsigned long long T = Pow(base, i); 
            if( has[i] == has[len] - has[len - i] * T)
            {
                for(int j = 2; j &amp;lt; len - i; j++)
                {
                    if(has[j + i] - has[j] * T == has[i])
                    {
                        ans = i;
                        break;
                    }
                }
                if(ans != i)
                    break;
            }
        }
        if(ans)
        {
            for(int i = 1; i &amp;lt;= ans; i++)
            {
                printf(&quot;%c&quot;, s[i]);
            }
            printf(&quot;\n&quot;);
        }
        else 
            puts(&quot;---\n&quot;);
    }
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>K-D 树</title><link>https://www.nekomio.com/posts/71/</link><guid isPermaLink="true">https://www.nekomio.com/posts/71/</guid><pubDate>Mon, 07 Aug 2017 15:04:53 GMT</pubDate><content:encoded>&lt;h2&gt;维护K维的点&lt;/h2&gt;
&lt;p&gt;线段树相当于一颗1-D树&lt;/p&gt;
&lt;h2&gt;建树&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;循环建树&lt;/li&gt;
&lt;li&gt;最大方差建树&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;怎么用&lt;/h2&gt;
</content:encoded></item><item><title>计算几何初步</title><link>https://www.nekomio.com/posts/70/</link><guid isPermaLink="true">https://www.nekomio.com/posts/70/</guid><pubDate>Sun, 06 Aug 2017 20:53:59 GMT</pubDate><content:encoded>&lt;h2&gt;1.什么是计算几何&lt;/h2&gt;
&lt;p&gt;维基百科&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E8%AE%A1%E7%AE%97%E5%87%A0%E4%BD%95&quot;&gt;计算几何&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;计算几何是一门兴起于二十世纪七十年代末的计算机科学的一个分支，主要研究解决几何问题的算法。
&amp;lt;!--more--&amp;gt;
简单来说就是用计算机算解析几何&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;2.计算几何的恶心之处&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;有精度误差&lt;a href=&quot;%E5%9C%A8%E8%AE%A1%E7%AE%97%E5%87%A0%E4%BD%95%E9%97%AE%E9%A2%98%E6%97%B6%E5%BE%88%E5%A4%9A%E6%97%B6%E5%80%99%E7%94%A8%E5%88%B0%E5%A4%8D%E6%9D%82%E7%9A%84%E6%B5%AE%E7%82%B9%E8%BF%90%E7%AE%97%E5%92%8C%E4%B8%89%E8%A7%92%E5%87%BD%E6%95%B0%E8%BF%90%E7%AE%97%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%B0%B1%E4%BC%9A%E4%BA%A7%E7%94%9F%E7%B2%BE%E5%BA%A6%E9%97%AE%E9%A2%98&quot;&gt;^1&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;需要讨论各种边界情况&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;代码长（看一看NOI2017D2T3的标称就知道了）&lt;/p&gt;
&lt;p&gt;解决精度问题&lt;br /&gt;
设$\epsilon$为非常小的量&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$a=b \Leftrightarrow |a-b|&amp;lt; \epsilon$&lt;/li&gt;
&lt;li&gt;$a&amp;lt; b \Leftrightarrow a-b &amp;lt; -\epsilon$&lt;/li&gt;
&lt;li&gt;$a\leq b \Leftrightarrow a - b &amp;lt; \epsilon$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3.二维矢量&lt;/h2&gt;
&lt;h4&gt;矢量&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;既有大小又有方向的量&lt;/li&gt;
&lt;li&gt;又称为向量&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;矢量的表示&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;在n维空间下，矢量经常被表示为 $\vec{a}=(a_1,a_2,\ldots,a_n)$&lt;/li&gt;
&lt;li&gt;在二维空间中则以$(x,y)$来表述&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;点积&lt;/h4&gt;
&lt;p&gt;$(a_1,a_2,\ldots,a_n)\cdot(b_1,b_2,\ldots,b_n) = a_1 b_1 + a_2 b_2+\cdots+ a_n b_n$&lt;/p&gt;
&lt;h4&gt;矢量的模&lt;/h4&gt;
&lt;p&gt;矢量的长度&lt;/p&gt;
&lt;h3&gt;! 二维叉积&lt;/h3&gt;
&lt;p&gt;$(x_1,y_1)\times(x_2,y_2) = x_1 y_2 - x_2 y_1$&lt;/p&gt;
&lt;p&gt;二维叉积满足&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E5%8F%8D%E4%BA%A4%E6%8F%9B%E5%BE%8B&quot;&gt;逆交换律&lt;/a&gt;: $\vec{a}\times\vec{b} = - \vec{b}\times\vec{a}$&lt;/p&gt;
&lt;h4&gt;有向面积&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;由$\vec{a}$和$\vec{b}$所成的平行四边形的面积为$|\vec{a}\times\vec{b}|$ 的值&lt;/li&gt;
&lt;li&gt;去掉绝对值二维叉积定义为有向面积&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;有向面积的符号&lt;/h4&gt;
&lt;p&gt;伸出右手将四指由$\vec{a}$沿小于平角转到$\vec{b}$ 若拇指指向纸面上方则$\vec{a}\times\vec{b}$ 为正否则为负&lt;/p&gt;
&lt;h4&gt;二维矢量的旋转&lt;/h4&gt;
&lt;p&gt;将矢量$\vec{a}$逆时针旋转$\theta$后为$ \begin{pmatrix} \cos\theta &amp;amp; -\sin\theta \ \sin\theta &amp;amp; \cos\theta \ \end{pmatrix} \vec{a} $&lt;/p&gt;
&lt;h4&gt;二维矢量的极角&lt;/h4&gt;
&lt;p&gt;极角指示矢量的方向，以x轴正半轴逆时针转过的角度来指示
矢量$(x,y)$的极角为$atan2(y,x)$&lt;/p&gt;
&lt;h4&gt;直线&lt;/h4&gt;
&lt;p&gt;用两个相异点来表示
$\forall\lambda \in R,\lambda A +(1-\lambda)B$
表示直线上任意一点&lt;/p&gt;
&lt;h4&gt;点到直线的距离&lt;/h4&gt;
&lt;p&gt;点$P$到直线$AB$的距离
即$|\vec{AP}-\vec{AB}\frac{\vec{AB}\cdot\vec{AP}}{\vec{AB}^2}|$&lt;/p&gt;
&lt;h4&gt;分点&lt;/h4&gt;
&lt;p&gt;若A,B,C共线，且$\frac{|\vec{AC}|}{\vec{CB}} =\frac{\lambda_1}{\lambda_2}$
则$C=\frac{\lambda_2 A + \lambda_1 B}{\lambda_1 + \lambda_2}$&lt;/p&gt;
&lt;h4&gt;三角形的面积&lt;/h4&gt;
&lt;p&gt;$ S(\Delta ABC) = \frac{|\vec{AB}\times\vec{AC}|}{2}$&lt;/p&gt;
&lt;h4&gt;两直线交点&lt;/h4&gt;
&lt;p&gt;$\frac{|\vec{AO}|}{|\vec{OB}|} = \frac{S(\Delta ADC)}{S(\Delta BCD)} = \frac {\vec{AD}\times\vec{AC}}{\vec{BC}\times\vec{BD}}$&lt;/p&gt;
&lt;h2&gt;为完待续.....(2017-8-6)&lt;/h2&gt;
</content:encoded></item><item><title>[GDOI2014] 拯救莫莉斯</title><link>https://www.nekomio.com/posts/69/</link><guid isPermaLink="true">https://www.nekomio.com/posts/69/</guid><pubDate>Sun, 06 Aug 2017 20:51:44 GMT</pubDate><content:encoded>&lt;h3&gt;问题描述&lt;/h3&gt;
&lt;p&gt;莫莉斯·乔是圣域里一个叱咤风云的人物，他凭借着自身超强的经济头脑，牢牢控制了圣域的石油市场。&lt;/p&gt;
&lt;p&gt;圣域的地图可以看成是一个n*m的矩阵。每个整数坐标点(x , y)表示一座城市（1&amp;lt;=x&amp;lt;= n, 1&amp;lt;=y&amp;lt;=m）。两座城市间相邻的定义为：对于城市$(A_x, A_y)$和城市$(B_x, B_y)$，满足$(A_x - B_x)^2 + (A_y - B_y)^2 = 1$。
由于圣域的石油贸易总量很大，莫莉斯意识到不能让每笔石油订购单都从同一个油库里发货。为了提高效率，莫莉斯·乔决定在其中一些城市里建造油库，最终使得每一个城市X都满足下列条件之一：
&amp;lt;!--more--&amp;gt;
1.该城市X内建有油库，&lt;/p&gt;
&lt;p&gt;2.某城市Y内建有油库，且城市X与城市Y相邻。&lt;/p&gt;
&lt;p&gt;与地球类似，圣域里不同城市间的地价可能也会有所不同，所以莫莉斯想让完成目标的总花费尽可能少。如果存在多组方案，为了方便管理，莫莉斯会选择建造较少的油库个数。&lt;/p&gt;
&lt;h3&gt;输入格式&lt;/h3&gt;
&lt;p&gt;第一行两个正整数n,m ( n * m &amp;lt;= 50 且m&amp;lt;=n)，表示矩阵的大小。&lt;/p&gt;
&lt;p&gt;接下来一个n行m列的矩阵F，Fi, j表示在城市(i,j)建造油库的代价。&lt;/p&gt;
&lt;h3&gt;输出格式&lt;/h3&gt;
&lt;p&gt;输出两个数，建造方案的油库个数和方案的总代价。&lt;/p&gt;
&lt;h3&gt;输入样例：&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3 3&lt;br /&gt;
6 5 4&lt;br /&gt;
1 2 3&lt;br /&gt;
7 8 9&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;输出样例：&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3 6&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;数据范围&lt;/h3&gt;
&lt;p&gt;对于30%数据满足 n * m &amp;lt;= 25;
对于100%数据满足n * m &amp;lt;= 50; 0 &amp;lt;= Fi, j &amp;lt;= 100000&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;按照题目的定义，第i行的状态，只会对i-1行至i+1行产生影响
F[i][j][k] 为对于前i行，第i-1行状态为j， 第i行的状态为k，并且对于任意一行x（x&amp;lt;i），该行的所有城市满足题目的要求（附近城市里有油库）
&amp;lt;!--more--&amp;gt;
F[i][j][k]的值表示其所能达到的最小代价
（辅助数组G[i][j][k] 表示F[i][j][k]所对应方案里的油库数量）&lt;/p&gt;
&lt;p&gt;F[i+1][k][X] = min(F[i][j][k] + cost[i+1][X]); (0 &amp;lt;= X &amp;lt;= 2m )&lt;/p&gt;
&lt;p&gt;cost[i][j] 表示第i行，所取状态为j时所需要花费的代价。&lt;/p&gt;
&lt;p&gt;转移方程中，X状态可取，需使第i行的所有城市满足要求，即：
(X|j|k|(k&amp;lt;&amp;lt;1)|(k&amp;gt;&amp;gt;1))&amp;amp;(2^m-1)=2^m-1
答案：max(F[n+1][x][0])(0&amp;lt;=X&amp;lt;=2m)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
int F[52][(1 &amp;lt;&amp;lt; 8) + 1][(1 &amp;lt;&amp;lt; 8) + 1], G[52][(1 &amp;lt;&amp;lt; 8) + 1][(1 &amp;lt;&amp;lt; 8) + 1];
int a[55][55], n, m, N;
int check(int x, int S)
{
    int ans = 0;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        if (((1 &amp;lt;&amp;lt; (i - 1)) &amp;amp; S))
            ans += a[x][i];
    }
    return ans;
}
int Get_num(int x)
{
    int ans = 0;
    while (x)
    {
        if (x &amp;amp; 1)
            ans++;
        x &amp;gt;&amp;gt;= 1;
    }
    return ans;
}
int main()
{
    //freopen(&quot;proj.in&quot;, &quot;r&quot;, stdin);
    //freopen(&quot;proj.out&quot;, &quot;w&quot;, stdout);
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    for (int i = 1; i &amp;lt;= n; i++)
        for (int j = 1; j &amp;lt;= m; j++)
            scanf(&quot;%d&quot;, &amp;amp;a[i][j]);
    memset(F, 0x3f, sizeof(F));
    N = (1 &amp;lt;&amp;lt; m) - 1;
    for (int i = 0; i &amp;lt;= N; i++)
    {
        //if ((((i &amp;gt;&amp;gt; 1) | (i &amp;lt;&amp;lt; 1) | i) &amp;amp; N) == N)
        //{
            int ans = check(1, i);
            F[1][0][i] = ans;
            G[1][0][i] = Get_num(i);
        //}
    }
    for (int i = 1; i &amp;lt;= n; i++)
        for (int j = 0; j &amp;lt;= N; j++)
            for (int k = 0; k &amp;lt;= N; k++)
                for (int m = 0; m &amp;lt;= N; m++)
                    if (((j | k | m | (k &amp;lt;&amp;lt; 1) | (k &amp;gt;&amp;gt; 1)) &amp;amp; (N)) == N)
                    {
                        if (F[i][j][k] + check(i + 1, m) &amp;lt; F[i + 1][k][m])
                        {
                            F[i + 1][k][m] = F[i][j][k] + check(i + 1, m);
                            G[i + 1][k][m] = G[i][j][k] + Get_num(m);
                        }
                    }
    int ans = 0x3f3f3f4f, num = 0;
    for (int i = 0; i &amp;lt;= N; i++)
    {
        if (F[n + 1][i][0] &amp;lt; ans)
        {
            ans = F[n + 1][i][0];
            num = G[n + 1][i][0];
        }
        else if (F[n + 1][i][0] == ans)
        {
            if (num &amp;gt; G[n + 1][i][0])
                num = G[n + 1][i][0];
        }
    }
    printf(&quot;%d %d&quot;, num, ans);
    //while (1)
    ;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>选美</title><link>https://www.nekomio.com/posts/68/</link><guid isPermaLink="true">https://www.nekomio.com/posts/68/</guid><pubDate>Sun, 06 Aug 2017 20:42:41 GMT</pubDate><content:encoded>&lt;h3&gt;【题目描述】&lt;/h3&gt;
&lt;p&gt;一年一度的星哥选美又拉开了帷幕&lt;/p&gt;
&lt;p&gt;N个人报名参加选拔，每个人都有着各自的相貌参数和身材参数（不大于 10000 的正整数）。你的任务是尽可能让更多人被星哥选中，而唯一要求就是，在这只队伍里面的每个人，都需满足以下不等式：
&amp;lt;!--more--&amp;gt;
$A (H− h) +B(W− w) ≤ C$&lt;/p&gt;
&lt;p&gt;其中H和W为这个人的相貌和身材， h和w为选中者中的最小相貌参数和最小身材参数，而A、 B、 C为三个不大于 10000 的正的整型常数。&lt;/p&gt;
&lt;p&gt;现在请计算星哥最多可以选中多少人。&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;第一行：一个整数： N(0&amp;lt;N&amp;lt;=2000)&lt;/p&gt;
&lt;p&gt;第二行：三个分开的整数： A,B和C&lt;/p&gt;
&lt;p&gt;第三行到第N+ 2行：每行有两个用空格分开的整数，分别表示一个人的相貌参数和身材参数&lt;/p&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;第一行：最多被选的人数&lt;/p&gt;
&lt;h3&gt;【输入样例】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;8&lt;br /&gt;
1 2 4&lt;br /&gt;
5 1&lt;br /&gt;
3 2&lt;br /&gt;
2 3&lt;br /&gt;
2 1&lt;br /&gt;
7 2&lt;br /&gt;
6 4&lt;br /&gt;
5 1&lt;br /&gt;
4 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【输出样例】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;只有$n^2\log_2{n}$的算法&lt;/p&gt;
&lt;p&gt;先按H排序&lt;/p&gt;
&lt;p&gt;枚举每一个h&lt;/p&gt;
&lt;p&gt;然后将他后面的部分再按w排序&lt;/p&gt;
&lt;p&gt;由树状树状维护前缀和就可以求出来了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-08-06 17:57:21 
 * @Last Modified by: WildRage
 * @Last Modified time: 2017-08-07 19:11:10
 */
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;map&amp;gt;
using namespace std;
struct data
{
    int h, w;
} a[2005], b[2005];
int n, A, B, C, m;
int comp(const data &amp;amp;a, const data &amp;amp;b)
{
    return a.h &amp;lt; b.h;
}
int cmp(const data &amp;amp;a, const data &amp;amp;b)
{
    return a.w &amp;lt; b.w;
}
int c[2005];
int lowbit(int x)
{
    return x &amp;amp; (-x);
}
void add(int x, int w)
{
    for (int i = x; i &amp;lt;= m; i += lowbit(i))
        c[i] += w;
}
int sum(int x)
{
    int s = 0;
    for (int i = x; i; i -= lowbit(i))
        s += c[i];
    return s;
}
int ans = 0;
void solve(int from)
{
    int h_min = a[from].h, w_min;
    int all;
    memcpy(b, a, sizeof(b));
    memset(c, 0, sizeof(c));
    sort(b + from, b + n + 1, cmp);
    int Sum[2005], Hash[2005];
    for (int i = from; i &amp;lt;= n; i++)
        Hash[i] = Sum[i] = b[i].h * A + b[i].w * B;
    sort(Hash + from, Hash + n + 1);
    m = unique(Hash + from, Hash + n + 1) - Hash - 1;
    for (int i = from; i &amp;lt;= n; i++)
    {
        int x = upper_bound(Hash + from, Hash + m + 1, Sum[i]) - Hash - 1;
        add(x, 1);
    }
    for (int i = from; i &amp;lt;= n; i++)
    {
        w_min = b[i].w;
        all = C + A * h_min + B * w_min;
        int x = upper_bound(Hash + from, Hash + m + 1, all) - Hash - 1;
        ans = max(ans, sum(x));
        add(upper_bound(Hash + from, Hash + m + 1, Sum[i]) - Hash - 1, -1);
    }
}
int main()
{
    //freopen(&quot;beauty.in&quot;, &quot;r&quot;, stdin);
    //freopen(&quot;beauty.out&quot;, &quot;w&quot;, stdout);
    scanf(&quot;%d&quot;, &amp;amp;n);
    scanf(&quot;%d%d%d&quot;, &amp;amp;A, &amp;amp;B, &amp;amp;C);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;a[i].h, &amp;amp;a[i].w);
    }
    sort(a + 1, a + n + 1, comp);
    for (int i = 1; i &amp;lt;= n; i++)
        solve(i);
    printf(&quot;%d&quot;, ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>天鹅会面</title><link>https://www.nekomio.com/posts/67/</link><guid isPermaLink="true">https://www.nekomio.com/posts/67/</guid><pubDate>Sun, 06 Aug 2017 20:34:46 GMT</pubDate><content:encoded>&lt;h2&gt;题目描述&lt;/h2&gt;
&lt;p&gt;两头白天鹅生活在一个部分湖面结了冰的湖泊中，湖面的形状为一个长方形，并且被分割成R行C列的小方格，某些方格中结了冰，这样的方格称之为冰格，其余的方格称之为水格。冬天过去了，湖面上的冰渐渐开始溶解了，每一天与水相邻的冰格就将消融而转化为水格。所谓两个方格相邻是指它们在水平或垂直方向有公共边，两个呈对角的方格是不相邻的，下图给出样例数据的演化过程。
&amp;lt;!--more--&amp;gt;
白天鹅只能在水中沿水平或垂直方向游动，写一个程序判断多少天后两只白天鹅才能够相会。&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;输入文件第一行包含两个用空格隔开的整数R和C，其中1 ≤ R, C ≤ 1500，接下来的R行每行包含C个字符，描述湖面的初始状态，‘·’表示水格，‘ X’表示冰格，‘ L’表示一只白天鹅。&lt;/p&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;输出文件仅一行包含一个整数表示两只白天鹅等到相邻那一天所需的天数。&lt;/p&gt;
&lt;h3&gt;【输入样例】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;8 17&lt;br /&gt;
...XXXXXX..XX.XXX&lt;br /&gt;
....XXXXXXXXX.XXX&lt;br /&gt;
...XXXXXXXXXXXX..&lt;br /&gt;
..XXXXX.LXXXXXX..&lt;br /&gt;
.XXXXXX..XXXXXX..&lt;br /&gt;
XXXXXXX...XXXX...&lt;br /&gt;
..XXXXX...XXX....&lt;br /&gt;
....XXXXX.XXXL...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【输出样例】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Hint&lt;/h3&gt;
&lt;p&gt;30%数据1 ≤ R《400.1 ≤ C《300&lt;br /&gt;
100%其中1 ≤ R, C ≤ 1500&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;怎么说呢，本来和简单的一道题&lt;br /&gt;
结果因为一个知识点不熟&lt;br /&gt;
然后就没做出来&lt;br /&gt;
其实就是两遍DFS
第一遍求出每个点到他的最近的水的距离&lt;br /&gt;
然后一边dfs求出起点到终点的过程中的最小值&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
bool map[1505][1505];
int dis[1505][1505];
struct Point
{
    int x, y;
} S, E, Q[20000000];
int R, C;
int movex[5] = {0, 0, 0, 1, -1},
    movey[5] = {0, 1, -1, 0, 0};
bool flag[1505][1505];
void bfs_init()
{
    //memset(flag,0,sizeof(flag));
    int l = 1, r = 0;
    memset(dis, 0x3f, sizeof(dis));
    for (int i = 1; i &amp;lt;= R; i++)
    {
        for (int j = 1; j &amp;lt;= C; j++)
        {
            if (!map[i][j])
            {
                Q[++r] = (Point){i, j};
                dis[i][j] = 0;
            }
        }
    }
    while (l &amp;lt;= r)
    {
        Point k = Q[l++];
        for (int i = 1; i &amp;lt;= 4; i++)
        {
            if (k.x + movex[i] &amp;gt; R || k.x + movex[i] &amp;lt; 1)
                continue;
            if (k.y + movey[i] &amp;gt; C || k.y + movey[i] &amp;lt; 1)
                continue;
            if (dis[k.x + movex[i]][k.y + movey[i]] &amp;gt; dis[k.x][k.y] + 1)
            {
                dis[k.x + movex[i]][k.y + movey[i]] = dis[k.x][k.y] + 1;
                Q[++r] = (Point) { k.x + movex[i], k.y + movey[i] };
            }
        }
    }
}
int d[1505][1505];
 
int SPFA()
{
    memset(d, 0x3f, sizeof(d));
    d[S.x][S.y] = 0;
    int l = 1, r = 0;
    Q[++r] = S;
    //flag[S.x][S.y] = 1;
    while (l &amp;lt;= r)
    {
        Point k = Q[l++];
        //flag[k.x][k.y] = 0;
        for (int i = 1; i &amp;lt;= 4; i++)
        {
            if (k.x + movex[i] &amp;gt; R || k.x + movex[i] &amp;lt; 1)
                continue;
            if (k.y + movey[i] &amp;gt; C || k.y + movey[i] &amp;lt; 1)
                continue;
            if (d[k.x + movex[i]][k.y + movey[i]] &amp;gt; max(d[k.x][k.y], dis[k.x + movex[i]][k.y + movey[i]]))
            {
                d[k.x + movex[i]][k.y + movey[i]] = max(d[k.x][k.y], dis[k.x + movex[i]][k.y + movey[i]]);
                //if (!flag[k.x + movex[i]][k.y + movey[i]])
                //{
                    Q[++r] = (Point){k.x + movex[i], k.y + movey[i]};
                    //flag[k.x + movex[i]][k.y + movey[i]] = 1;
                //}
            }
        }
    }
    return d[E.x][E.y];
}
int main()
{
    //freopen(&quot;swan.in&quot;, &quot;r&quot;, stdin);
    // freopen(&quot;swan.out&quot;, &quot;w&quot;, stdout);
    char c;
    scanf(&quot;%d%d&quot;, &amp;amp;R, &amp;amp;C);
    bool flag = 0;
    for (int i = 1; i &amp;lt;= R; i++)
    {
        for (int j = 1; j &amp;lt;= C; j++)
        {
            c = getchar();
            while (c != &apos;.&apos; &amp;amp;&amp;amp; c != &apos;X&apos; &amp;amp;&amp;amp; c != &apos;L&apos;)
                c = getchar();
            if (c == &apos;X&apos;)
                map[i][j] = 1;
            else if (c == &apos;L&apos;)
            {
                if (flag)
                    E = (Point){i, j};
                else
                {
                    S = (Point){i, j};
                    flag = 1;
                }
            }
        }
    }
    bfs_init();
    printf(&quot;%d&quot;, SPFA());
    //while (1)
    ;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BZOJ3166]: [Heoi2013] Alo</title><link>https://www.nekomio.com/posts/66/</link><guid isPermaLink="true">https://www.nekomio.com/posts/66/</guid><pubDate>Sat, 05 Aug 2017 11:18:36 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;Welcome to ALO ( Arithmetic and Logistic Online)。这是一个VR MMORPG ，
如名字所见，到处充满了数学的谜题。
现在你拥有n颗宝石，每颗宝石有一个能量密度，记为ai，这些宝石的能量
密度两两不同。现在你可以选取连续的一些宝石（必须多于一个）进行融合，设为 ai, ai+1, …, a j，则融合而成的宝石的能量密度为这些宝石中能量密度的次大值
&amp;lt;!--more--&amp;gt;
与其他任意一颗宝石的能量密度按位异或的值，即，设该段宝石能量密度次大值
为k，则生成的宝石的能量密度为max{k xor ap | ap ≠ k , i ≤ p ≤ j}。
现在你需要知道你怎么选取需要融合的宝石，才能使生成的宝石能量密度最大。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行，一个整数 n，表示宝石个数。
第二行， n个整数，分别表示a1至an，表示每颗宝石的能量密度，保证对于i ≠ j有 ai ≠ aj。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;输出一行一个整数，表示最大能生成的宝石能量密度。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5&lt;br /&gt;
9 2 1 4 7&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;14&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;【样例解释】
选择区间[1,5]，最大值为 7 xor 9。
对于 100%的数据有 1 ≤ n ≤ 50000, 0 ≤ ai ≤ 10^9&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;如图由左右比他大的值得到了一个区间
&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/05/1181169-20170803204801365-12244565356d7b7.png&quot; alt=&quot;1181169-20170803204801365-12244565356d7b7.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;我们用Set维护查排名比他大1的就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;set&amp;gt;
#include &amp;lt;algorithm&amp;gt;
int n;
const int INF = 1000000000;
const int full = 30;
struct Trie
{
	struct Trie_Node
	{
		Trie_Node *ch[2];
		int s;
		Trie_Node()
		{
			ch[0] = ch[1] = NULL;
			s = 0;
		}
	} * root[100005], *null;
	Trie()
	{
		null = new Trie_Node();
		null-&amp;gt;ch[0] = null-&amp;gt;ch[1] = null;
		root[0] = new Trie_Node();
		root[0]-&amp;gt;ch[1] = root[0]-&amp;gt;ch[0] = null;
	}
	Trie_Node *NewNode()
	{
		Trie_Node *rt = new Trie_Node();
		rt-&amp;gt;ch[0] = rt-&amp;gt;ch[1] = null;
		return rt;
	}
	void copy(Trie_Node *&amp;amp;a, Trie_Node *b)
	{
		if (b == null)
			a = null;
		else
			a = NewNode(), *a = *b;
	}
	void Insert(int x, int cnt)
	{
		copy(root[cnt], root[cnt - 1]);
		Trie_Node *rt1 = root[cnt], *rt2 = root[cnt - 1];
		for (int i = full; i &amp;gt;= 0; i--)
		{
			int k = (x &amp;gt;&amp;gt; i) &amp;amp; 1;
			copy(rt1-&amp;gt;ch[k], rt2-&amp;gt;ch[k]);
			if (rt1-&amp;gt;ch[k] == null)
				rt1-&amp;gt;ch[k] = NewNode();
			rt1 = rt1-&amp;gt;ch[k], rt2 = rt2-&amp;gt;ch[k];
			rt1-&amp;gt;s++;
		}
	}
	int Query(int val, int l, int r)
	{
		int res = 0;
		Trie_Node *rt1 = root[r], *rt2 = root[l - 1];
		for (int i = full; i &amp;gt;= 0; i--)
		{
			int next = (val &amp;gt;&amp;gt; i) &amp;amp; 1;
			if (rt1-&amp;gt;ch[next ^ 1]-&amp;gt;s - rt2-&amp;gt;ch[next ^ 1]-&amp;gt;s)
			{
				rt1 = rt1-&amp;gt;ch[next ^ 1], rt2 = rt2-&amp;gt;ch[next ^ 1];
				res |= (1 &amp;lt;&amp;lt; i);
			}
			else
			{
				rt1 = rt1-&amp;gt;ch[next], rt2 = rt2-&amp;gt;ch[next];
			}
		}
		return res;
	}
} root;
struct data
{
	int val, i;
	bool operator &amp;lt; (const data &amp;amp;a)const 
	{
		return val &amp;gt; a.val;
	}
} a[50005];
std::set&amp;lt;int&amp;gt; st;
int main()
{
	scanf(&quot;%d&quot;, &amp;amp;n);
	for (int i = 1; i &amp;lt;= n; i++)
	{
		scanf(&quot;%d&quot;, &amp;amp;a[i].val);
		a[i].i = i;
	}
	for (int i = 1; i &amp;lt;= n; ++i)
	{
		root.Insert(a[i].val, i);
	}
	st.insert(-1), st.insert(INF), st.insert(-2), st.insert(INF + 1);
	std::sort(a + 1, a + n + 1);
	st.insert(a[1].i);
	int ans = 0;
	for (int i = 2; i &amp;lt;= n; i++)
	{
		int l = a[i].i, r = a[i].i;
		std::set&amp;lt;int&amp;gt;::iterator T, P;
		P = st.lower_bound(a[i].i);
		T = P;
		r = *T; T++; r = *T - 1;
		l = *--P; P--;l = *P + 1;
		l = std::max(1, l), r = std::min(r, n);
		if (l != r)
		{
			ans = std::max(ans, root.Query(a[i].val, l, r));
		}
		st.insert(a[i].i);
	}
	printf(&quot;%d&quot;, ans);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BZOJ2432][Noi2011]兔农 矩阵乘法+exgcd</title><link>https://www.nekomio.com/posts/65/</link><guid isPermaLink="true">https://www.nekomio.com/posts/65/</guid><pubDate>Sat, 05 Aug 2017 08:57:32 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;农夫栋栋近年收入不景气，正在他发愁如何能多赚点钱时，他听到隔壁的小朋友在讨论兔子繁殖的问题。
问题是这样的：第一个月初有一对刚出生的小兔子，经过两个月长大后，这对兔子从第三个月开始，每个月初生一对小兔子。新出生的小兔子生长两个月后又能每个月生出一对小兔子。问第n个月有多少只兔子？
&amp;lt;!--more--&amp;gt;
聪明的你可能已经发现，第n个月的兔子数正好是第n个Fibonacci(斐波那契)数。栋栋不懂什么是Fibonacci数，但他也发现了规律：第i+2个月的兔子数等于第i个月的兔子数加上第i+1个月的兔子数。前几个月的兔子数依次为：
1 1 2 3 5 8 13 21 34 …
栋栋发现越到后面兔子数增长的越快，期待养兔子一定能赚大钱，于是栋栋在第一个月初买了一对小兔子开始饲养。
每天，栋栋都要给兔子们喂食，兔子们吃食时非常特别，总是每k对兔子围成一圈，最后剩下的不足k对的围成一圈，由于兔子特别害怕孤独，从第三个月开始，如果吃食时围成某一个圈的只有一对兔子，这对兔子就会很快死掉。
我们假设死去的总是刚出生的兔子，那么每个月的兔子数仍然是可以计算的。例如，当k=7时，前几个月的兔子数依次为：
1 1 2 3 5 7 12 19 31 49 80 …
给定n，你能帮助栋栋计算第n个月他有多少对兔子么？由于答案可能非常大，你只需要告诉栋栋第n个月的兔子对数除p的余数即可。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;输入一行，包含三个正整数n, k, p。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;输出一行，包含一个整数，表示栋栋第n个月的兔子对数除p的余数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;6 7 100&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;7&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;$1&amp;lt;=N&amp;lt;=10^18$
$2&amp;lt;=K&amp;lt;=10^6$
$2&amp;lt;=P&amp;lt;=10^9$&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;暴力75 暴力给的很足
可是后面的25分死一样难拿&lt;/p&gt;
&lt;p&gt;我们可以以%7为例打一个表
如果以 减1为0 为分界那么会出现这样的情况&lt;/p&gt;
&lt;p&gt;1, 1, 2, 3, 5, 0,
5, 5, 3, 0,
3, 3, 6, 2, 0,
2, 2, 4, 6, 3, 2, 5, 0,
5, 5, 3, 0,
3, 3, 6, 2, 0,
·········&lt;/p&gt;
&lt;p&gt;那么我们会发现他用2个性质&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;我们发现，每段开头必为相同的两数，并且它们恰是上一段的最末一位非0数；由于总共只有k−1种余数，所以不超过k段就会出现循环（如果有的话）。&lt;/li&gt;
&lt;li&gt;设开头的数为x 那么这个数列为%k意义下的斐波那契数列&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们发现在最后一个数变为0前&lt;br /&gt;
$ x*f[len] \equiv 1 (mod k)$
那么f[len]为x在模k意义下的逆元&lt;br /&gt;
所以，我们可以通过exgcd或者扩展欧拉定理，来快速求出f[len]。
如果没有逆元直接斐波那契数列矩阵快速幂过去就可以了&lt;/p&gt;
&lt;p&gt;然后我们需要len
其实这个我们可以预处理出来vis&lt;br /&gt;
每次查询即可&lt;/p&gt;
&lt;p&gt;最后由 $x*f[len-1]$ 得下一段的开头&lt;/p&gt;
&lt;p&gt;有一个很强的结论：斐波那契数列在模k意义下一定是以0 1 1……为开头的循环，并且循环节长度&amp;lt;=6*k，所以暴力算vis就可以了&lt;/p&gt;
&lt;p&gt;然后我们需要行内的转移矩阵
$$ \begin{bmatrix} 1 &amp;amp; 1 &amp;amp; 0 \ 1 &amp;amp; 0 &amp;amp; 0 \ 0 &amp;amp; 0 &amp;amp; 1 \end{bmatrix} $$&lt;/p&gt;
&lt;p&gt;行间的转移矩阵&lt;/p&gt;
&lt;p&gt;$$ \begin{bmatrix} 1 &amp;amp; 0 &amp;amp; 0 \ 0 &amp;amp; 1 &amp;amp; 0 \ -1 &amp;amp; 0 &amp;amp; 1 \end{bmatrix} $$&lt;/p&gt;
&lt;p&gt;什么你问我代码？
我也没打出来啊。。。。。&lt;/p&gt;
</content:encoded></item><item><title>[NOIP2011] 聪明的质监员</title><link>https://www.nekomio.com/posts/64/</link><guid isPermaLink="true">https://www.nekomio.com/posts/64/</guid><pubDate>Sat, 05 Aug 2017 08:36:01 GMT</pubDate><content:encoded>&lt;h3&gt;【问题描述】&lt;/h3&gt;
&lt;p&gt;小 T 是一名质量监督员，最近负责检验一批矿产的质量。这批矿产共有n个矿石，从 1 到n逐一编号，每个矿石都有自己的重量$w_i$以及价值$v_i$。检验矿产的流程是：
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;给定 m个区间$[L_i,R_i]$；&lt;/li&gt;
&lt;li&gt;选出一个参数W；&lt;/li&gt;
&lt;li&gt;对于一个区间$[L_i,R_i]$，计算矿石在这个区间上的检验值$Y_i$：&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;$$ Y_i = \sum_{j}{1}*\sum_{j}{v_j},j \in [L_i,R_i] \and w_j≥W,{j是矿石编号} $$
这批矿产的检验结果Y为各个区间的检验值之和。即：
$$ Y=\sum_{i=1}^{m}{Y_i} $$&lt;/p&gt;
&lt;p&gt;若这批矿产的检验结果与所给标准值 S 相差太多，就需要再去检验另一批矿产。小 T 不想费时间去检验另一批矿产，所以他想通过调整参数 W 的值，让检验结果尽可能的靠近标准值 S，即使得S−Y的绝对值最小。请你帮忙求出这个最小值。&lt;/p&gt;
&lt;h3&gt;【输入】&lt;/h3&gt;
&lt;p&gt;输入文件 qc.in。
第一行包含三个整数n，m，S，分别表示矿石的个数、区间的个数和标准值。
接下来的n 行，每行2 个整数，中间用空格隔开，第i+1 行表示i 号矿石的重量wi 和价值vi 。
接下来的m 行，表示区间，每行2 个整数，中间用空格隔开，第i+n+1 行表示区间$[L_i,R_i]$的两个端点$L_i$ 和$R_i$。注意：不同区间可能重合或相互重叠。&lt;/p&gt;
&lt;h3&gt;【输出】&lt;/h3&gt;
&lt;p&gt;输出文件名为qc.out。
输出只有一行，包含一个整数，表示所求的最小值。&lt;/p&gt;
&lt;h3&gt;【输入输出样例】&lt;/h3&gt;
&lt;h4&gt;qc.in&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;5 3 15&lt;br /&gt;
1 5&lt;br /&gt;
2 5&lt;br /&gt;
3 5&lt;br /&gt;
4 5&lt;br /&gt;
5 5&lt;br /&gt;
1 5&lt;br /&gt;
2 4&lt;br /&gt;
3 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;qc.out&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;10&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【输入输出样例说明】&lt;/h3&gt;
&lt;p&gt;当W 选4 的时候，三个区间上检验值分别为20、5、0，这批矿产的检验结果为25，此时与标准值S 相差最小为10。&lt;/p&gt;
&lt;h3&gt;【数据范围】&lt;/h3&gt;
&lt;p&gt;对于10%的数据，有$1≤n，m≤10$；&lt;br /&gt;
对于30%的数据，有$1≤n，m≤500$；&lt;br /&gt;
对于50%的数据，有$1≤n，m≤5,000$；&lt;br /&gt;
对于70%的数据，有$1≤n，m≤10,000$；&lt;br /&gt;
对于100%的数据，有$1≤n，m≤200,000,0 &amp;lt; w_i, v_i≤10^6，0 &amp;lt; S≤10^12，1≤L_i≤R_i≤n$。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;三分W&lt;br /&gt;
$O(n+m)$ 求出Y
然后比较找最近的&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
#define LL long long
int n, m;
struct data
{
    int w, v;
} a[200005];
struct Data
{
    int l, r;
} Q[200005];
int Sumn[200005];
LL Sumv[200005];
LL check(int w)
{
    Sumn[0] = 0;
    Sumv[0] = 1;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        Sumn[i] = Sumn[i - 1] + (a[i].w &amp;gt; w);
        Sumv[i] = Sumv[i - 1] + (a[i].w &amp;gt; w ? a[i].v : 0);
    }
    LL Y = 0;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        Y += (Sumn[Q[i].r] - Sumn[Q[i].l - 1]) * (Sumv[Q[i].r] - Sumv[Q[i].l - 1]);
    }
    return Y;
}
int main()
{
    freopen(&quot;qc.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;qc.out&quot;, &quot;w&quot;, stdout);
    LL S;
    scanf(&quot;%d%d%lld&quot;, &amp;amp;n, &amp;amp;m, &amp;amp;S);
    int Max = 0;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;a[i].w, &amp;amp;a[i].v);
        Max = max(Max, a[i].w);
    }
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;Q[i].l, &amp;amp;Q[i].r);
    }
    LL l = 0, r = Max;
    LL ans = 0x3fffffffffffffffLL;
    while (l &amp;lt; r)
    {
        LL mid = l + r &amp;gt;&amp;gt; 1;
        LL t = check(mid);
        if (t &amp;lt; S)
        {
            ans = min(ans, abs(t - S));
            r = mid;
        }
        else
        {
            ans = min(ans, abs(t - S));
            l = mid + 1;
        }
    }
    printf(&quot;%lld&quot;, ans);

    //while (1);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BZOJ 1124][POI 2008] 枪战 Maf</title><link>https://www.nekomio.com/posts/63/</link><guid isPermaLink="true">https://www.nekomio.com/posts/63/</guid><pubDate>Thu, 03 Aug 2017 08:37:31 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;有n个人，每个人手里有一把手枪。一开始所有人都选定一个人瞄准（有可能瞄准自己）。然后他们按某个顺序开枪，且任意时刻只有一个人开枪。因此，对于不同的开枪顺序，最后死的人也不同。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;输入n人数&amp;lt;1000000 每个人的aim&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;你要求最后死亡数目的最小和最大可能&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;8&lt;br /&gt;
2 3 2 2 6 7 8 5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3 5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;我也不会啊&lt;/h2&gt;
&lt;p&gt;树DP&lt;a href=&quot;https://www.cnblogs.com/TSHugh/p/7273841.html&quot;&gt;TH_Hugh&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://www.cnblogs.com/liu-runda/p/5940191.html&quot;&gt;liu_runda&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;贴代码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;queue&amp;gt;
using namespace std;
int a[1000005], Maxn, t, Min, Max;
int times[1000005];
bool die[1000005], nodie[1000005];
int Q[1000005];
int main()
{
    //freopen(&quot;maf.in&quot;, &quot;r&quot;, stdin);
    //freopen(&quot;maf.out&quot;, &quot;w&quot;, stdout);
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
        times[a[i]]++;
    }
    //Q.resize(1000001);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        if (!times[i])
        {
            Max++;
            Q[++Min] = i;
        }
    }
    //printf(&quot;%d\n&quot;,Max);

    //for (vector&amp;lt;int&amp;gt;::iterator it = Q.begin(); it != Q.end(); it++)
    for (int i = 1; i &amp;lt;= Min; i++)
    {
        //printf(&quot;%d---------%d=======\n&quot;,it-Q.begin(),*it);
        int k = a[Q[i]];
        if (die[k])
            continue;
        die[k] = 1;
        nodie[a[k]] = 1;
        --times[a[k]];
        if (!times[a[k]])
        {
            Q[++Min]=a[k]; 
        }
    }
    int sum;
    bool All_NoDied;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        if (times[i] &amp;amp;&amp;amp; !die[i])
        {
            sum = 0;
            All_NoDied = 0;
            for (int j = i; !die[j]; j = a[j])
            {
                die[j] = 1;
                sum++;
                All_NoDied |= nodie[j];
            }
            if (!All_NoDied &amp;amp;&amp;amp; sum &amp;gt; 1)
                Max++;
            Min += sum / 2;
        }
    }
    printf(&quot;%d %d\n&quot;, n - Min, n - Max);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BZOJ 1647][USACO 2007 Open] Fliptile 翻格子游戏</title><link>https://www.nekomio.com/posts/62/</link><guid isPermaLink="true">https://www.nekomio.com/posts/62/</guid><pubDate>Thu, 03 Aug 2017 08:36:56 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;Farmer John knows that an intellectually satisfied cow is a happy cow who will give more milk. He has arranged a brainy activity for cows in which they manipulate an M x N grid (1 &amp;lt;= M &amp;lt;= 15; 1 &amp;lt;= N &amp;lt;= 15) of square tiles, each of which is colored black on one side and white on the other side. As one would guess, when a single white tile is flipped, it changes to black;
&amp;lt;!--more--&amp;gt;
when a single black tile is flipped, it changes to white. The cows are rewarded when they flip the tiles so that each tile has the white side face up. However, the cows have rather large hooves and when they try to flip a certain tile, they also flip all the adjacent tiles (tiles that share a full edge with the flipped tile). Since the flips are tiring, the cows want to minimize the number of flips they have to make. Help the cows determine the minimum number of flips required, and the locations to flip to achieve that minimum. If there are multiple ways to achieve the task with the minimum amount of flips, return the one with the least lexicographical ordering in the output when considered as a string. If the task is impossible, print one line with the word &quot;IMPOSSIBLE&quot;.&lt;/p&gt;
&lt;p&gt;约翰知道，那些高智力又快乐的奶牛产奶量特别高．所以他做了一个翻瓦片的益智游戏来娱乐奶牛．在一个M×N(1≤M，N≤15)的骨架上，每一个格子里都有一个可以翻转的瓦片．瓦片的一面是黑色的，而另一面是白色的．对一个瓦片进行翻转，可以使黑变白，也可以使白变黑．然而，奶牛们的蹄子是如此的巨大而且笨拙，所以她们翻转一个瓦片的时候，与之有公共边的相邻瓦片也都被翻转了．那么，这些奶牛们最少需要多少次翻转，使所有的瓦片都变成白面向上呢？如杲可以做到，输出字典序最小的结果（将结果当成字符串处理）．如果不能做到，输出“IMPOSSIBLE”．&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Line 1: Two space-separated integers: M and N&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lines 2..M+1: Line i+1 describes the colors (left to right) of row i of the grid with N space-separated integers which are 1 for black and 0 for white&lt;/p&gt;
&lt;p&gt;第1行输入M和N，之后M行N列，输入游戏开始时的瓦片状态．0表示白面向上，1表示黑面向上．&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Lines 1..M: Each line contains N space-separated integers, each specifying how many times to flip that particular location.&lt;/p&gt;
&lt;p&gt;输出M行，每行N个用空格隔开的整数，表示对应的格子进行了多少次翻转．&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;4 4&lt;br /&gt;
1 0 0 1&lt;br /&gt;
0 1 1 0&lt;br /&gt;
0 1 1 0&lt;br /&gt;
1 0 0 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;0 0 0 0&lt;br /&gt;
1 0 0 1&lt;br /&gt;
1 0 0 1&lt;br /&gt;
0 0 0 0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;OUTPUT DETAILS:&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;After flipping at row 2 column 1, the board will look like:&lt;br /&gt;
0 0 0 1&lt;br /&gt;
1 0 1 0&lt;br /&gt;
1 1 1 0&lt;br /&gt;
1 0 0 1&lt;/p&gt;
&lt;p&gt;After flipping at row 2 column 4, the board will look like:&lt;br /&gt;
0 0 0 0&lt;br /&gt;
1 0 0 1&lt;br /&gt;
1 1 1 1&lt;br /&gt;
1 0 0 1&lt;/p&gt;
&lt;p&gt;After flipping at row 3 column 1, the board will look like:&lt;br /&gt;
0 0 0 0&lt;br /&gt;
0 0 0 1&lt;br /&gt;
0 0 1 1&lt;br /&gt;
0 0 0 1&lt;/p&gt;
&lt;p&gt;After flipping at row 3 column 4, the board will look like:&lt;br /&gt;
0 0 0 0&lt;br /&gt;
0 0 0 0&lt;br /&gt;
0 0 0 0&lt;br /&gt;
0 0 0 0&lt;/p&gt;
&lt;p&gt;Another solution might be:&lt;br /&gt;
0 1 1 0&lt;br /&gt;
0 0 0 0&lt;br /&gt;
0 0 0 0&lt;br /&gt;
0 1 1 0&lt;br /&gt;
but this solution is lexicographically higher than the solution above.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;枚举第一行就可以了&lt;br /&gt;
然后往下跑&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
int n, m;
int b[17][17], a[17][17], op[17][17];
inline void DoChange(int x)
{
    for (int j = 1; j &amp;lt;= n; j++)
    {
        if (op[x][j])
        {
            a[x - 1][j] ^= 1;
            a[x][j - 1] ^= 1;
            a[x][j + 1] ^= 1;
            a[x + 1][j] ^= 1;
        }
    }
}
inline bool ok()
{
    for (int i = 1; i &amp;lt;= m; i++)
    {
        for (int j = 1; j &amp;lt;= n; j++)
        {
            if (a[i][j] == 1)
                return 0;
        }
    }
    return 1;
}
inline void print()
{
    for (int i = 1; i &amp;lt;= m; i++)
    {
        for (int j = 1; j &amp;lt;= n; j++)
        {
            printf(&quot;%d &quot;, op[i][j]);
        }
        printf(&quot;\n&quot;);
    }
}
int main()
{
    //freopen(&quot;fliptile.in&quot;, &quot;r&quot;, stdin);
    //freopen(&quot;fliptile.out&quot;, &quot;w&quot;, stdout);
    scanf(&quot;%d%d&quot;, &amp;amp;m, &amp;amp;n);
    for (int i = 1; i &amp;lt;= m; i++)
        for (int j = 1; j &amp;lt;= n; j++)
        {
            scanf(&quot;%d&quot;, &amp;amp;b[i][j]);
        }
    int N = (1 &amp;lt;&amp;lt; n) - 1;
    for (int i = 0; i &amp;lt;= N; i++)
    {
        memcpy(a, b, sizeof(a));
        memset(op, 0, sizeof(op));
        for (int j = 1; j &amp;lt;= n; j++)
        {
            if (i &amp;amp; (1 &amp;lt;&amp;lt; (j - 1)))
            {
                op[1][j] = 1;
                a[1 - 1][j] ^= 1;
                a[1][j - 1] ^= 1;
                a[1][j] ^= 1;
                a[1][j + 1] ^= 1;
                a[1 + 1][j] ^= 1;
            }
        }
        for (int j = 1; j &amp;lt; m; j++)
        {
            for (int k = 1; k &amp;lt;= n; k++)
            {
                if (a[j][k])
                {
                    op[j + 1][k] = 1;
                    a[j][k] ^= 1;
                    a[j + 1][k] ^= 1;
                    a[j + 1][k - 1] ^= 1;
                    a[j + 1][k + 1] ^= 1;
                    a[j + 2][k] ^= 1;
                }
            }
        }
        if (ok())
        {
            print();
            //while (1);
            exit(0);
        }
    }
    printf(&quot;IMPOSSIBLE\n&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BZOJ 1592] Making The Grade路面修整</title><link>https://www.nekomio.com/posts/61/</link><guid isPermaLink="true">https://www.nekomio.com/posts/61/</guid><pubDate>Thu, 03 Aug 2017 08:24:30 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;FJ打算好好修一下农场中某条凹凸不平的土路。按奶牛们的要求，修好后的路面高度应当单调上升或单调下降，也就是说，高度上升与高度下降的路段不能同时出现在修好的路中。 整条路被分成了N段，N个整数A_1, ... , A_N (1 &amp;lt;= N &amp;lt;= 2,000)依次描述了每一段路的高度(0 &amp;lt;= A_i &amp;lt;= 1,000,000,000)。FJ希望找到一个恰好含N个元素的不上升或不下降序列B_1, ... , B_N，作为修过的路中每个路段的高度。由于将每一段路垫高或挖低一个单位的花费相同，修路的总支出可以表示为：$ |A_1 - B_1| + |A_2 - B_2| + ... + |A_N - B_N| $请你计算一下，FJ在这项工程上的最小支出是多少。FJ向你保证，这个支出不会超过2^31-1。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;第1行: 输入1个整数：N * 第2..N+1行: 第i+1行为1个整数：A_i&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;第1行: 输出1个正整数，表示FJ把路修成高度不上升或高度不下降的最小花费&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;7&lt;br /&gt;
1&lt;br /&gt;
3&lt;br /&gt;
2&lt;br /&gt;
4&lt;br /&gt;
5&lt;br /&gt;
3&lt;br /&gt;
9&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;FJ将第一个高度为3的路段的高度减少为2，将第二个高度为3的路段的高度增加到5，总花费为|2-3|+|5-3| = 3，并且各路段的高度为一个不下降序列 1,2,2,4,5,5,9。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;方程 $f_{i,j}=min( f_{i,j-1}, f_{i-1,j}+ \left | a_i - b_j \right | ) $&lt;br /&gt;
不知道为什么只正向能过&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cmath&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
int a[2005], n, size;
int f[2005][2005];
int Hash[2005];
inline void Hash_init()
{
    sort(Hash + 1, Hash + n + 1);
    size = unique(Hash + 1, Hash + n + 1) - Hash - 1;
}
int main()
{
    // freopen(&quot;grading.in&quot;,&quot;r&quot;,stdin);
    // freopen(&quot;grading.out&quot;,&quot;w&quot;,stdout);
    scanf(&quot;%d\n&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
        Hash[i] = a[i];
    }
    Hash_init();
    int minn = 0x3f3f3f3f;
    for (int i = 1; i &amp;lt;= n; i++)
    {   
        minn = 0x3f3f3f3f;
        for (int j = 1; j &amp;lt;= size; j++)
        {
            minn = min(minn, f[i - 1][j]);
            f[i][j] = minn +abs(Hash[j] - a[i]);
        }
    }
    int ans = 0x3f3f3f3f;
    for (int i = 1; i &amp;lt;= size; i++)
        ans = min(ans, f[n][i]);
    memset(f,0,sizeof(f));
    // for (int i = n; i &amp;gt;= 1; i++)
    // {   
    //     minn = 0x3f3f3f3f;
    //     for (int j = 1; j &amp;lt;= size; j++)
    //     {
    //         minn = min(minn, f[i + 1][j]);
    //         f[i][j] = minn +abs(Hash[j] - a[i]);
    //     }
    // }
    // for (int i = 1; i &amp;lt;= size; i++)
    //     ans = min(ans, f[1][i]);
    printf(&quot;%d\n&quot;, ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BZOJ 4832] [Lydsy2017年4月月赛]抵制克苏恩</title><link>https://www.nekomio.com/posts/59/</link><guid isPermaLink="true">https://www.nekomio.com/posts/59/</guid><pubDate>Thu, 03 Aug 2017 08:14:26 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;小Q同学现在沉迷炉石传说不能自拔。他发现一张名为克苏恩的牌很不公平。如果你不玩炉石传说，不必担心，小Q
同学会告诉你所有相关的细节。炉石传说是这样的一个游戏，每个玩家拥有一个 30 点血量的英雄，并且可以用牌
召唤至多 7 个随从帮助玩家攻击对手，其中每个随从也拥有自己的血量和攻击力。小Q同学有很多次游戏失败都是
因为对手使用了克苏恩这张牌，所以他想找到一些方法来抵御克苏恩。他去求助职业炉石传说玩家椎名真白，真白
&amp;lt;!--more--&amp;gt;
告诉他使用奴隶主这张牌就可以啦。如果你不明白我上面在说什么，不必担心，小Q同学会告诉你他想让你做什么
。现在小Q同学会给出克苏恩的攻击力是 K ，表示克苏恩会攻击 K 次，每次会从对方场上的英雄和随从中随机选
择一个并对其产生 1 点伤害。现在对方有一名克苏恩，你有一些奴隶主作为随从，每名奴隶主的血量是给定的。
如果克苏恩攻击了你的一名奴隶主，那么这名奴隶主的血量会减少 1 点，当其血量小于等于 0 时会死亡，如果受
到攻击后不死亡，并且你的随从数量没有达到 7 ，这名奴隶主会召唤一个拥有 3 点血量的新奴隶主作为你的随从
；如果克苏恩攻击了你的英雄，你的英雄会记录受到 1 点伤害。你应该注意到了，每当克苏恩进行一次攻击，你
场上的随从可能发生很大的变化。小Q同学为你假设了克苏恩的攻击力，你场上分别有 1 点、 2 点、 3 点血量的
奴隶主数量，你可以计算出你的英雄受到的总伤害的期望值是多少吗？&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;输入包含多局游戏。
第一行包含一个整数 T (T&amp;lt;100) ，表示游戏的局数。
每局游戏仅占一行，包含四个非负整数 K, A, B 和 C ，表示克苏恩的攻击力是 K ，你有 A 个 1 点血量的奴隶
主， B 个 2 点血量的奴隶主， C 个 3 点血量的奴隶主。
保证 K 是小于 50 的正数， A+B+C 不超过 7 。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;对于每局游戏，输出一个数字表示总伤害的期望值，保留两位小数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1&lt;br /&gt;
1 1 1 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;0.25&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;简单的基础概率DP&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
double f[55][8][8][8];
int main(int argc, char const *argv[])
{
    int T, a, b, c, k;
    scanf(&quot;%d&quot;, &amp;amp;T);
    while (T--)
    {
        scanf(&quot;%d%d%d%d&quot;, &amp;amp;k, &amp;amp;a, &amp;amp;b, &amp;amp;c);
        memset(f, 0, sizeof(f));
        f[1][a][b][c] = 1;
        double ans = 0;
        for (int i = 1; i &amp;lt;= k; i++)
        {
            for (int j = 0; j &amp;lt;= 7; j++)
                for (int l = 0; l &amp;lt;= 7; l++)
                    for (int m = 0; m &amp;lt;= 7; m++)
                    {
                        if (l + j + m &amp;lt;= 7)
                        {
                            if (j &amp;gt; 0)
                                f[i + 1][j - 1][l][m] += f[i][j][l][m] * j * 1.0 / (l + j + m + 1);
                            if (l &amp;gt; 0)
                            {
                                if (l + j + m &amp;lt;= 6)
                                    f[i + 1][j + 1][l - 1][m + 1] += f[i][j][l][m] * l * 1.0 / (l + j + m + 1);
                                else
                                    f[i + 1][j + 1][l - 1][m] += f[i][j][l][m] * l * 1.0 / (l + j + m + 1);
                            }
                            if (m &amp;gt; 0)
                            {
                                if (l + j + m &amp;lt;= 6)
                                    f[i + 1][j][l + 1][m] += f[i][j][l][m] * m * 1.0 / (l + j + m + 1);
                                else
                                    f[i + 1][j][l + 1][m - 1] += f[i][j][l][m] * m * 1.0 / (l + j + m + 1);
                            }
                            f[i + 1][j][l][m] += f[i][j][l][m] * 1.0 / (l + j + m + 1);
                            ans += f[i][j][l][m] * 1.0 / (l + j + m + 1);
                        }
                    }
        }
        printf(&quot;%.2lf\n&quot;, ans);
    }
    //while (1)
        ;
    return 0;
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BZOJ 3829][POI2014] FarmCraft</title><link>https://www.nekomio.com/posts/60/</link><guid isPermaLink="true">https://www.nekomio.com/posts/60/</guid><pubDate>Thu, 03 Aug 2017 08:14:26 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;In a village called Byteville, there are   houses connected with N-1 roads. For each pair of houses, there is a unique way to get from one to another. The houses are numbered from 1 to  . The house no. 1 belongs to the village administrator Byteasar. As part of enabling modern technologies for rural areas framework,   computers have been delivered to Byteasar&apos;s house. Every house is to be supplied with a computer, and it is Byteasar&apos;s task to distribute them. The citizens of Byteville have already agreed to play the most recent version of FarmCraft (the game) as soon as they have their computers.
&amp;lt;!--more--&amp;gt;
Byteasar has loaded all the computers on his pickup truck and is about to set out to deliver the goods. He has just the right amount of gasoline to drive each road twice. In each house, Byteasar leaves one computer, and immediately continues on his route. In each house, as soon as house dwellers get their computer, they turn it on and install FarmCraft. The time it takes to install and set up the game very much depends on one&apos;s tech savviness, which is fortunately known for each household. After he delivers all the computers, Byteasar will come back to his house and install the game on his computer. The travel time along each road linking two houses is exactly 1 minute, and (due to citizens&apos; eagerness to play) the time to unload a computer is negligible.
Help Byteasar in determining a delivery order that allows all Byteville&apos;s citizens (including Byteasar) to start playing together as soon as possible. In other words, find an order that minimizes the time when everyone has FarmCraft installed.
mhy住在一棵有n个点的树的1号结点上，每个结点上都有一个妹子。
mhy从自己家出发，去给每一个妹子都送一台电脑，每个妹子拿到电脑后就会开始安装zhx牌杀毒软件，第i个妹子安装时间为Ci。
树上的每条边mhy能且仅能走两次，每次耗费1单位时间。mhy送完所有电脑后会回自己家里然后开始装zhx牌杀毒软件。
卸货和装电脑是不需要时间的。
求所有妹子和mhy都装好zhx牌杀毒软件的最短时间。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;The first line of the standard input contains a single integer N(2&amp;lt;=N&amp;lt;=5 00 000)  that gives the number of houses in Byteville. The second line contains N integers C1,C2…Cn(1&amp;lt;=Ci&amp;lt;=10^9), separated by single spaces; Ci is the installation time (in minutes) for the dwellers of house no. i.
The next N-1  lines specify the roads linking the houses. Each such line contains two positive integers a and b(1&amp;lt;=a&amp;lt;b&amp;lt;=N) , separated by a single space. These indicate that there is a direct road between the houses no. a and b.&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;The first and only line of the standard output should contain a single integer: the (minimum) number of minutes after which all citizens will be able to play FarmCraft together.&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;6&lt;br /&gt;
1 8 9 6 3 2&lt;br /&gt;
1 3&lt;br /&gt;
2 3&lt;br /&gt;
3 4&lt;br /&gt;
4 5&lt;br /&gt;
4 6&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;11&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;Explanation: Byteasar should deliver the computers to the houses in the following order: 3, 2, 4, 5, 6, and 1. The game will be installed after 11, 10, 10, 10, 8, and 9 minutes respectively, in the house number order. Thus everyone can play after 11 minutes.&lt;/p&gt;
&lt;p&gt;If Byteasar delivered the game in the following order: 3, 4, 5, 6, 2, and 1, then the game would be installed after: 11, 16, 10, 8, 6, and 7 minutes respectively. Hence, everyone could play only after 16 minutes,&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;直接搞&lt;br /&gt;
记录一个值为总时间减遍历时间&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;functional&amp;gt;
using namespace std;
struct edge
{
    int END, next;
} v[1000005];
int w[500005], first[500005], p;
void add(int a, int b)
{
    v[p].END = b;
    v[p].next = first[a];
    first[a] = p++;
}
int f[500005];
int dfs(int x, int fa)
{
    int t = 0;
    for (int i = first[x]; i != -1; i = v[i].next)
    {
        if (v[i].END != fa)
        {
            f[v[i].END] = dfs(v[i].END, x);
            t += f[v[i].END] + 2;
        }
    }
    return t;
}
int t[500005];
int comp(const int &amp;amp;a, const int &amp;amp;b)
{
    return t[a] &amp;gt; t[b];
}
void DP(int x, int fa)
{
    vector&amp;lt;int&amp;gt; re;
    for (int i = first[x]; i != -1; i = v[i].next)
        if (v[i].END != fa)
        {
            DP(v[i].END, x);
            re.push_back(v[i].END);
        }
    sort(re.begin(), re.end(), comp);
    if (x != 1)
        t[x] = w[x] - f[x];
    int now = f[x];
    for (int i = 0; i &amp;lt; re.size(); i++)
    {
        now -= (f[re[i]] + 2);
        t[x] = max(t[x], t[re[i]] - now - 1);
    }
    t[x] = max(t[x], 0);
}
int main()
{
    freopen(&quot;farmcraft.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;farmcraft.out&quot;, &quot;w&quot;, stdout);
    //memset(f, -1, sizeof(f));
    memset(first, -1, sizeof(first));
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;w[i]);
    }
    int a, b;
    for (int i = 1; i &amp;lt; n; i++)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;a, &amp;amp;b);
        add(a, b);
        add(b, a);
    }
    f[1] = dfs(1, 0);
    //for (int i = 1; i &amp;lt;= n; i++)
    // printf(&quot;%d &quot;, f[i]);
    //printf(&quot;\n======================\n&quot;);
    DP(1, 0);
    //while(1);
    printf(&quot;%d\n&quot;, f[1] + max(w[1], t[1]));
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[NOIP2015] 斗地主</title><link>https://www.nekomio.com/posts/58/</link><guid isPermaLink="true">https://www.nekomio.com/posts/58/</guid><pubDate>Thu, 03 Aug 2017 07:45:19 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中，牌的大小关系根据牌的数码表示如下：3&amp;lt;4&amp;lt;5&amp;lt;6&amp;lt;7&amp;lt;8&amp;lt;9&amp;lt;10&amp;lt;J&amp;lt;Q&amp;lt;K&amp;lt;A&amp;lt;2&amp;lt;小王&amp;lt;大王，而花色并不对牌的大小产生影响。每一局游戏中，一副手牌由n张牌组成。游戏者每次可以根据规定的牌型进行出牌，首先打光自己的手牌一方取得游戏的胜利。现在，牛牛只想知道，对于自己的若干组手牌，分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。需要注意的是，本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。具体规则如下：&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/03/11.PNG_7260344acb43.png&quot; alt=&quot;11.PNG_7260344acb43.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行包含用空格隔开的2个正整数T,N，表示手牌的组数以及每组手牌的张数。&lt;/p&gt;
&lt;p&gt;接下来T组数据，每组数据N行，每行一个非负整数对Ai,Bi，表示一张牌，其中Ai表示牌的数码,Bi表示牌的花色，中间用空格隔开。特别的，我们用1来表示数码A，11表示数码J，12表示数码Q，13表示数码K；黑桃、红心、梅花、方片分别用1-4来表示；小王的表示方法为01，大王的表示方法为02。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;共T行，每行一个整数，表示打光第T组手牌的最少次数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1 8&lt;br /&gt;
7 4&lt;br /&gt;
8 4&lt;br /&gt;
9 1&lt;br /&gt;
10 4&lt;br /&gt;
11 1&lt;br /&gt;
5 1&lt;br /&gt;
1 4&lt;br /&gt;
1 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;共有1组手牌，包含8张牌：方片7，方片8，黑桃9，方片10，黑桃J，黑桃5，方片A以及黑桃A。可以通过打单顺子（方片7，方片8，黑桃9，方片10，黑桃J），单张牌（黑桃5）以及对子牌（黑桃A以及方片A）在3次内打光。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;搜吧&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
struct data
{
    int t, l, r;
};
int cnt[16];
int backcnt[16];
vector&amp;lt;data&amp;gt; s;
int times[5];
int Query()
{
    memcpy(backcnt, cnt, sizeof(backcnt));
    memset(times, 0, sizeof(times));
    // int ans = s.size();
    // for (int i = 0; i &amp;lt; s.size(); i++)
    // {
    //     for (int j = s[i].l; j &amp;lt;= s[i].r; j++)
    //         backcnt[j] -= s[i].t;
    // }
    int ans = 0;
    for (int i = 1; i &amp;lt;= 14; i++)
    {
        times[backcnt[i]]++;
    }
    while (times[4] &amp;gt; 0 &amp;amp;&amp;amp; times[2] &amp;gt; 1)
    {
        times[4]--;
        times[2] -= 2;
        ans++;
    }
    while (times[4] &amp;gt; 0 &amp;amp;&amp;amp; times[1] &amp;gt; 1)
    {
        times[4]--;
        times[1] -= 2;
        ans++;
    }
    while (times[4] &amp;gt; 0 &amp;amp;&amp;amp; times[2] &amp;gt; 0)
    {
        times[4]--;
        times[2]--;
        ans++;
    }
    while (times[3] &amp;gt; 0 &amp;amp;&amp;amp; times[2] &amp;gt; 0)
    {
        times[3]--;
        times[2]--;
        ans++;
    }
    while (times[3] &amp;gt; 0 &amp;amp;&amp;amp; times[1] &amp;gt; 0)
    {
        times[3]--;
        times[1]--;
        ans++;
    }
    while (times[4] &amp;gt; 0)
    {
        times[4]--;
        ans++;
    }
    while (times[3] &amp;gt; 0)
    {
        times[3]--;
        ans++;
    }
    while (times[2] &amp;gt; 0)
    {
        times[2]--;
        ans++;
    }
    while (times[1] &amp;gt; 0)
    {
        times[1]--;
        ans++;
    }
    return ans;
}
int DFS()
{
    //int ans = 0x3f3f3f3f;
    int ans = Query();
    for (int i = 1; i &amp;lt;= 12; i++)
    {
        if (cnt[i])
        {
            for (int j = i + 1; j &amp;lt;= 12; j++)
            {
                if (!cnt[j])
                    break;
                if (j - i + 1 &amp;gt;= 5)
                {
                    //s.push_back((data){1, i, j});
                    for (int k = i; k &amp;lt;= j; k++)
                        cnt[k] -= 1;
                    ans = min(ans, DFS()+1);
                    for (int k = i; k &amp;lt;= j; k++)
                        cnt[k] += 1;
                    //ans = min(ans, Query(1));
                    //s.pop_back();
                }
            }
        }
        if (cnt[i] &amp;gt;= 2)
        {
            for (int j = i + 1; j &amp;lt;= 12; j++)
            {
                if (cnt[j] &amp;lt; 2)
                    break;
                if (j - i + 1 &amp;gt;= 3)
                {
                    for (int k = i; k &amp;lt;= j; k++)
                        cnt[k] -= 2;
                    ans = min(ans, DFS()+1);
                    for (int k = i; k &amp;lt;= j; k++)
                        cnt[k] += 2;
                    // s.push_back((data){2, i, j});
                    // ans = min(ans, DFS(j + 1));
                    // ans = min(ans, Query(1));
                    // s.pop_back();
                }
            }
        }
        if (cnt[i] &amp;gt;= 3)
        {
            for (int j = i + 1; j &amp;lt;= 12; j++)
            {
                if (cnt[j] &amp;lt; 3)
                    break;
                if (j - i + 1 &amp;gt;= 2)
                {
                    for (int k = i; k &amp;lt;= j; k++)
                        cnt[k] -= 3;
                    ans = min(ans, DFS()+1);
                    for (int k = i; k &amp;lt;= j; k++)
                        cnt[k] += 3;
                    // s.push_back((data){3, i, j});
                    // ans = min(ans, DFS(j + 1));
                    // ans = min(ans, Query(1));
                    // s.pop_back();
                }
            }
        }
    }
    //ans = min(ans, Query(1));
    return ans;
}
int main(int argc, char const *argv[])
{
    freopen(&quot;landlords.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;landlords.out&quot;, &quot;w&quot;, stdout);
    int T, n;
    //int C = 1;
    scanf(&quot;%d%d&quot;, &amp;amp;T, &amp;amp;n);
    while (T--)
    {
        int a, b;
        memset(cnt, 0, sizeof(cnt));
        for (int i = 1; i &amp;lt;= n; i++)
        {
            scanf(&quot;%d%d&quot;, &amp;amp;a, &amp;amp;b);
            if (a)
                if ((a + 11) % 13)
                    cnt[(a + 11) % 13]++;
                else
                    cnt[13]++;
            else
                cnt[14]++;
        }
        s.clear();
        printf(&quot;%d\n&quot;, DFS());
    }

    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 2588 [Spoj 10628] Count on a tree</title><link>https://www.nekomio.com/posts/56/</link><guid isPermaLink="true">https://www.nekomio.com/posts/56/</guid><pubDate>Thu, 03 Aug 2017 06:24:05 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;给定一棵N个节点的树，每个点有一个权值，对于M个询问(u,v,k)，你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案，初始为0，即第一个询问的u是明文。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行两个整数N,M。
第二行有N个整数，其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y)，表示点x到点y有一条边。
最后M行每行两个整数(u,v,k)，表示一组询问。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;M行，表示每个询问的答案。最后一个询问不输出换行符&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;8 5&lt;br /&gt;
105 2 9 3 8 5 7 7&lt;br /&gt;
1 2&lt;br /&gt;
1 3&lt;br /&gt;
1 4&lt;br /&gt;
3 5&lt;br /&gt;
3 6&lt;br /&gt;
3 7&lt;br /&gt;
4 8&lt;br /&gt;
2 5 1&lt;br /&gt;
0 5 2&lt;br /&gt;
10 5 3&lt;br /&gt;
11 5 4&lt;br /&gt;
110 8 2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;br /&gt;
8&lt;br /&gt;
9&lt;br /&gt;
105&lt;br /&gt;
7&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;简单来说可以每个节点复制他父亲的节点在新版本中插入自己&lt;br /&gt;
然后两个点之间的k小值就是a-lca + b-fa[lca];&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;climits&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
struct Seg_Node *null;
struct Seg_Node
{
    Seg_Node *ch[2];
    int cnt;
    //#define cnt(_) ((_) ? (_)-&amp;gt;cnt : 0)
    Seg_Node(Seg_Node *l, Seg_Node *r)
    {
        ch[0] = l, ch[1] = r;
        cnt = ch[0]-&amp;gt;cnt + ch[1]-&amp;gt;cnt;
    }
    Seg_Node(Seg_Node *l, Seg_Node *r, int _cnt)
    {
        ch[0] = l, ch[1] = r;
        cnt = _cnt;
    }
    Seg_Node *insert(int l, int r, int x)
    {
        if (l == r)
            return new Seg_Node(null, null, cnt + 1);
        else
        {
            int m = l + (r - l) / 2;
            if (x &amp;lt;= m)
                return new Seg_Node(ch[0]-&amp;gt;insert(l, m, x), ch[1]);
            else
                return new Seg_Node(ch[0], ch[1]-&amp;gt;insert(m + 1, r, x));
        }
    }
};
struct Node
{
    vector&amp;lt;Node *&amp;gt; ch;
    Node *fa;
    int dep, w;
    bool vis;
    Seg_Node *Seg;
} v[100005];
 
void addedge(int a, int b)
{
    v[a].ch.push_back(&amp;amp;v[b]);
    v[b].ch.push_back(&amp;amp;v[a]);
}
void init()
{
    null = new Seg_Node(NULL, NULL, 0);
    null-&amp;gt;ch[0] = null-&amp;gt;ch[1] = null;
}
int n, f[100005][20], logn;
void build()
{
    v[0].vis = 1;
    v[0].Seg = null;
    queue&amp;lt;Node *&amp;gt; Q;
    Q.push(&amp;amp;v[1]);
    v[1].vis = 1;
    v[1].dep = 1;
    v[1].fa = &amp;amp;v[0];
    while (!Q.empty())
    {
        Node *e = Q.front();
        Q.pop();
        e-&amp;gt;Seg = e-&amp;gt;fa-&amp;gt;Seg-&amp;gt;insert(0, INT_MAX, e-&amp;gt;w);
        for (Node **p = &amp;amp;e-&amp;gt;ch.front(), *u = *p; p &amp;lt;= &amp;amp;e-&amp;gt;ch.back(); u = *++p)
        {
            if (!u-&amp;gt;vis)
            {
                u-&amp;gt;vis = 1;
                u-&amp;gt;dep = e-&amp;gt;dep + 1;
                u-&amp;gt;fa = e;
                Q.push(u);
            }
        }
    }
    while ((1 &amp;lt;&amp;lt; (logn + 1)) &amp;lt;= n)
        logn++;
    f[1][0] = 1;
    for (int i = 2; i &amp;lt;= n; i++)
        f[i][0] = v[i].fa - v;
    for (int j = 1; j &amp;lt;= logn; j++)
    {
        for (int i = 1; i &amp;lt;= n; i++)
        {
            f[i][j] = f[f[i][j - 1]][j - 1];
        }
    }
}
int lca(int s, int e)
{
    if (v[s].dep &amp;lt; v[e].dep)
        swap(s, e);
    if (v[s].dep &amp;gt; v[e].dep)
    {
        for (int i = logn; i &amp;gt;= 0; i--)
        {
            if (v[f[s][i]].dep &amp;gt;= v[e].dep)
                s = f[s][i];
        }
    }
    if (s != e)
    {
        for (int i = logn; i &amp;gt;= 0; i--)
        {
            if (f[s][i] != f[e][i])
            {
                s = f[s][i];
                e = f[e][i];
            }
        }
        return f[s][0];
    }
    return s;
}
int Query(int s, int e, int k)
{
    int p = lca(s, e);
    Seg_Node *Su = v[s].Seg, *Sv = v[e].Seg, *Sp = v[p].Seg, *Sf = v[p].fa-&amp;gt;Seg;
    int l = 0, r = INT_MAX;
    while (l &amp;lt; r)
    {
        int m = l + (r - l) / 2;
        int S = Su-&amp;gt;ch[0]-&amp;gt;cnt + Sv-&amp;gt;ch[0]-&amp;gt;cnt - Sp-&amp;gt;ch[0]-&amp;gt;cnt - Sf-&amp;gt;ch[0]-&amp;gt;cnt;
        if (k &amp;gt; S)
        {
            k -= S;
            l = m + 1;
            Su = Su-&amp;gt;ch[1];
            Sv = Sv-&amp;gt;ch[1];
            Sp = Sp-&amp;gt;ch[1];
            Sf = Sf-&amp;gt;ch[1];
        }
        else
        {
            r = m;
            Su = Su-&amp;gt;ch[0];
            Sv = Sv-&amp;gt;ch[0];
            Sp = Sp-&amp;gt;ch[0];
            Sf = Sf-&amp;gt;ch[0];
        }
    }
    return l;
}
int main()
{
    int m;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    for (int i = 1; i &amp;lt;= n; i++)
        scanf(&quot;%d&quot;, &amp;amp;v[i].w);
    for (int i = 1; i &amp;lt;= n - 1; i++)
    {
        int s, e;
        scanf(&quot;%d%d&quot;, &amp;amp;s, &amp;amp;e);
        addedge(s, e);
    }
    init();
    build();
    int ans = 0;
    while (m--)
    {
        int s, e, k;
        scanf(&quot;%d%d%d&quot;, &amp;amp;s, &amp;amp;e, &amp;amp;k);
        s ^= ans;
        printf(m ? &quot;%d\n&quot; : &quot;%d&quot;, ans = Query(s, e, k));
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BZOJ 1409] Password</title><link>https://www.nekomio.com/posts/57/</link><guid isPermaLink="true">https://www.nekomio.com/posts/57/</guid><pubDate>Thu, 03 Aug 2017 06:24:05 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;Rivest是密码学专家。近日他正在研究一种数列E = {E[1],E[2],……,E[n]}，
且E[1] = E[2] = p（p为一个质数），E[i] = E[i-2]*E[i-1] （若2&amp;lt;i&amp;lt;=n）。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;
例如{2,2,4,8,32,256,8192,……}就是p = 2的数列。在此基础上他又设计了一种加密算法，该算法可以通过一个密钥q (q &amp;lt; p)将一个正整数n加密成另外一个正整数d，计算公式为：d = E[n] mod q。现在Rivest想对一组数据进行加密，但他对程序设计不太感兴趣，请你帮助他设计一个数据加密程序。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行读入m，p。其中m表示数据个数，p用来生成数列E。 以下有m行，每行有2个整数n，q。n为待加密数据，q为密钥。 数据范围: 0 &amp;lt; p n&amp;lt; 2^31 0 &amp;lt; q &amp;lt; p 0 &amp;lt; m &amp;lt;= 5000。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;将加密后的数据按顺序输出到文件 第i行输出第i个加密后的数据。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;输入样例1&lt;br /&gt;
2 7&lt;br /&gt;
4 5&lt;br /&gt;
4 6&lt;br /&gt;
输入样例2&lt;br /&gt;
4 7&lt;br /&gt;
2 4&lt;br /&gt;
7 1&lt;br /&gt;
6 5&lt;br /&gt;
9 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;输出样例1&lt;br /&gt;
3&lt;br /&gt;
1&lt;br /&gt;
输出样例2&lt;br /&gt;
3&lt;br /&gt;
0&lt;br /&gt;
1&lt;br /&gt;
1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;设斐波那契数列的第i项为$F(i)$&lt;br /&gt;
&lt;a href=&quot;https://oeis.org/A000045&quot;&gt;斐波那契数列&lt;/a&gt;&lt;br /&gt;
可以发现$E[i]=p^F(i)$&lt;br /&gt;
所以我们的任务变为了求$F(i)$然后矩阵快速幂&lt;br /&gt;
$$
\begin{bmatrix}
1 &amp;amp; 1 \
1 &amp;amp; 0 \
\end{bmatrix}
$$
最后乘上$ \begin{bmatrix} 1 \ 1 \ \end{bmatrix} $ 就可以了&lt;/p&gt;
&lt;p&gt;然后由出现了一个问题&lt;br /&gt;
我们需要取膜（雾）&lt;br /&gt;
要知道 $ a^b%p!=a^{b%p}%p $
所以我们需要欧拉定理&lt;br /&gt;
$$ a^{\phi{n}} \equiv 1 (mod n) $$
然后易得&lt;br /&gt;
$$ a^{b%\phi{p}} \equiv a^b (mod p) $$&lt;br /&gt;
使用条件是 a与p 互质&lt;/p&gt;
&lt;p&gt;然后就可以了筛出素数
$ \sqrt{n} $求$\phi{n}$就行了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cmath&amp;gt;
using namespace std;
bool isnprime[1000005];
int prime[200005], Idx;
void Get_Prime()
{
    isnprime[1] = 1;
    for (int i = 2; i &amp;lt;= 1000000; i++)
    {
        if (!isnprime[i])
        {
            prime[++Idx] = i;
        }
        for (int j = 1; j &amp;lt;= Idx; j++)
        {
            if (prime[j] * i &amp;gt; 1000000)
                break;
            isnprime[i * prime[j]] = 1;
            if (i % prime[j] == 0)
                break;
        }
    }
}
long long Get_Phi(long long x)
{
    if (x == 1)
        return 0;
    int i = 1;
    int Sq = sqrt(x);
    long long ans = x;
    while (x != 1)
    {
        if (prime[i] &amp;gt; Sq)
        {
            ans = ans - ans / x;
            break;
        }
        if (x % prime[i] == 0)
        {
            ans = ans - ans / prime[i];
            while (x % prime[i] == 0)
                x /= prime[i];
        }
        ++i;
    }
    return ans;
}
long long phi;
class Matrix
{
  public:
    int n, m;
    long long a[3][3];
    Matrix(int n1, int m1)
    {
        n = n1, m = m1;
        memset(a, 0, sizeof(a));
    }
    Matrix operator*(const Matrix &amp;amp;A)
    {
        Matrix ans(n, A.m);
        for (int i = 1; i &amp;lt;= n; i++)
            for (int k = 1; k &amp;lt;= A.m; k++)
            {
                for (int j = 1; j &amp;lt;= m; j++)
                    ans.a[i][k] += a[i][j] * A.a[j][k];
                if (ans.a[i][k] &amp;gt;= phi)
                    ans.a[i][k] = ans.a[i][k] % phi/* + phi*/;
            }
        return ans;
    }
    Matrix operator^(const long long &amp;amp;b)
    {
        long long k = b;
        Matrix ans(n, m);
        for (int i = 1; i &amp;lt;= n; i++)
        {
            ans.a[i][i] = 1;
        }
        Matrix A = *this;
        while (k)
        {
            if (k &amp;amp; 1)
                ans = ans * A;
            k &amp;gt;&amp;gt;= 1;
            A = A * A;
        }
        return ans;
    }
};
long long pow_mod(long long a, long long b, long long mod)
{
    long long ans = 1;
    while (b)
    {
        if (b &amp;amp; 1)
            ans = ans * a % mod;
        b &amp;gt;&amp;gt;= 1;
        a = a * a % mod;
    }
    return ans;
}
int main()
{
    freopen(&quot;password.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;password.out&quot;, &quot;w&quot;, stdout);
    long long m, p;
    Get_Prime();
    Matrix O(2, 2);
    O.a[1][1] = O.a[1][2] = O.a[2][1] = 1;
    Matrix L(2, 1);
    L.a[1][1] = 1;
    scanf(&quot;%lld%lld&quot;, &amp;amp;m, &amp;amp;p);
    while (m--)
    {
        long long n, q;
        scanf(&quot;%lld%lld&quot;, &amp;amp;n, &amp;amp;q);
        if (q == 1)
        {
            printf(&quot;0\n&quot;);
            continue;
        }
        int t = p - q;
        if (t == 1)
        {
            printf(&quot;1\n&quot;);
            continue;
        }
        phi = Get_Phi(q);
        printf(&quot;%lld\n&quot;, pow_mod(p, ((O ^ n) * L).a[2][1], q));
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 1901 [Zju2112] Dynamic Rankings</title><link>https://www.nekomio.com/posts/55/</link><guid isPermaLink="true">https://www.nekomio.com/posts/55/</guid><pubDate>Thu, 03 Aug 2017 05:38:04 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;给定一个含有n个数的序列a[1],a[2],a[3]……a[n]，程序必须回答这样的询问：对于给定的i,j,k，在a[i],a[i+1
],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1)，并且，你可以改变一些a[i]的值，改变后，程序还能针对改
变后的a继续回答上面的问题。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行一个数字N，代表测试组数
对于每组数据第一行有两个正整数n(1≤n≤10000)，m(1≤m≤10000)。
分别表示序列的长度和指令的个数。
第二行有n个数，表示a[1],a[2]……a[n]，这些数都小于10^9。
接下来的m行描述每条指令
每行的格式是下面两种格式中的一种。
Q i j k 或者 C i t
Q i j k （i,j,k是数字，1≤i≤j≤n, 1≤k≤j-i+1）
表示询问指令，询问a[i]，a[i+1]……a[j]中第k小的数。
C i t (1≤i≤n，0≤t≤10^9)表示把a[i]改变成为t&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;对于每一次询问，你都需要输出他的答案，每一个输出占单独的一行。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1&lt;br /&gt;
5 3&lt;br /&gt;
3 2 1 4 7&lt;br /&gt;
Q 1 4 3&lt;br /&gt;
C 2 6&lt;br /&gt;
Q 2 5 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;br /&gt;
6&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;简单的来说就是待修改的区间k小值&lt;/p&gt;
&lt;p&gt;我们用让线段树外面套一层树状数组就可以修改了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
const int N = 1000000000;
#define lowbit(_) ((_) &amp;amp; (-_))
struct Seg_Node
{
    Seg_Node *ch[2];
    int sum, l, r;
    Seg_Node(int L, int R)
    {
        sum = 0, l = L, r = R;
        ch[1] = ch[0] = NULL;
    }
#define sum(_) ((_) ? (_)-&amp;gt;sum : 0)
    void Pushup()
    {
        sum = sum(ch[0]) + sum(ch[1]);
    }
} * root[50005];
int a[50005];
int n;
void Insert(Seg_Node *rt, int num)
{
    if (rt-&amp;gt;l == rt-&amp;gt;r)
    {
        rt-&amp;gt;sum++;
        return;
    }
    int m = rt-&amp;gt;l + rt-&amp;gt;r &amp;gt;&amp;gt; 1;
    if (num &amp;lt;= m)
    {
        if (!rt-&amp;gt;ch[0])
            rt-&amp;gt;ch[0] = new Seg_Node(rt-&amp;gt;l, m);
        Insert(rt-&amp;gt;ch[0], num);
    }
    else
    {
        if (!rt-&amp;gt;ch[1])
            rt-&amp;gt;ch[1] = new Seg_Node(m + 1, rt-&amp;gt;r);
        Insert(rt-&amp;gt;ch[1], num);
    }
    rt-&amp;gt;Pushup();
}
void Insert(int x, int num)
{
    for (int i = x; i &amp;lt;= n; i += lowbit(i))
    {
        if (root[i] == NULL)
            root[i] = new Seg_Node(0, N);
        Insert(root[i], num);
    }
}
void Delete(Seg_Node *&amp;amp;rt, int num)
{
    if (rt-&amp;gt;l == rt-&amp;gt;r)
    {
        rt-&amp;gt;sum--;
        if (!rt-&amp;gt;sum)
            delete rt, rt = NULL;
        return;
    }
    int m = rt-&amp;gt;l + rt-&amp;gt;r &amp;gt;&amp;gt; 1;
    if (num &amp;lt;= m)
        Delete(rt-&amp;gt;ch[0], num);
    else
        Delete(rt-&amp;gt;ch[1], num);
    rt-&amp;gt;Pushup();
    if (!rt-&amp;gt;sum)
        delete rt, rt = NULL;
}
void Delete(int x, int num)
{
    for (int i = x; i &amp;lt;= n; i += lowbit(i))
    {
        Delete(root[i], num);
    }
}
vector&amp;lt;Seg_Node *&amp;gt; Get(int x)
{
    vector&amp;lt;Seg_Node *&amp;gt; ans;
    for (int i = x; i &amp;gt; 0; i -= lowbit(i))
    {
        ans.push_back(root[i]);
    }
    return ans;
}
vector&amp;lt;Seg_Node *&amp;gt; Get_ch(vector&amp;lt;Seg_Node *&amp;gt; x, int op)
{
    for (int i=0;i&amp;lt;x.size();i++)
        if (x[i])
            x[i] = x[i]-&amp;gt;ch[op];
    return x;
}
int Query(vector&amp;lt;Seg_Node *&amp;gt; list1, vector&amp;lt;Seg_Node *&amp;gt; list2, int l, int r, int k)
{
    if (l == r)
        return l;
    int ans = 0;
    for (int i=0;i&amp;lt;list2.size();i++)
        if (list2[i])
            ans += sum(list2[i]-&amp;gt;ch[0]);
    for (int i=0;i&amp;lt;list1.size();i++)
        if (list1[i])
            ans -= sum(list1[i]-&amp;gt;ch[0]);
    int m = l + r &amp;gt;&amp;gt; 1;
    if (ans &amp;gt;= k)
        return Query(Get_ch(list1, 0), Get_ch(list2, 0), l, m, k);
    else
        return Query(Get_ch(list1, 1), Get_ch(list2, 1), m + 1, r, k - ans);
}
void DFS(Seg_Node *&amp;amp;rt)
{
    if (rt)
    {
        DFS(rt-&amp;gt;ch[0]);
        DFS(rt-&amp;gt;ch[1]);
        delete rt;
        rt=NULL;
    }
}
void remove()
{
    for (int i = 1; i &amp;lt;= n; i++)
    {
        DFS(root[i]);
    }
}
int main(int argc, char const *argv[])
{
    //freopen(&quot;dynrank.in&quot;,&quot;r&quot;,stdin);
    //freopen(&quot;dynrank.out&quot;,&quot;w&quot;,stdout);
    //int T;
    //scanf(&quot;%d&quot;, &amp;amp;T);
    //while (T--)
    //{
        int m;
        scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
        //memset(a,0,sizeof(a));
        for (int i = 1; i &amp;lt;= n; i++)
        {
            scanf(&quot;%d&quot;, &amp;amp;a[i]);
            Insert(i, a[i]);
        }
        //sort(a + 1, a + n + 1);
        char op[3];
        int p, b, c;
        for (int i = 1; i &amp;lt;= m; i++)
        {
            scanf(&quot;%s&quot;, op);
            if (op[0] == &apos;Q&apos;)
            {
                scanf(&quot;%d%d%d&quot;, &amp;amp;p, &amp;amp;b, &amp;amp;c);
                printf(&quot;%d\n&quot;, Query(Get(p - 1), Get(b), 0, N, c));
            }
            else
            {
                scanf(&quot;%d%d&quot;, &amp;amp;p, &amp;amp;b);
                Delete(p, a[p]);
                Insert(p, b);
                a[p] = b;
            }
        }
        remove();
 //   }
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;树套树&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
int a[50005], n;
class Treap
{
    class Node
    {
      public:
        int size, v, key;
        Node *ch[2];
        Node(int x)
        {
            key = rand();
            v = x;
            size = 1;
            ch[0] = ch[1] = NULL;
        }
#define size(_) ((_) ? (_)-&amp;gt;size : 0)
        void Pushup()
        {
            size = size(ch[0]) + size(ch[1]) + 1;
        }
    } * root;
    Node *Merge(Node *A, Node *B)
    {
        if (!A)
            return B;
        if (!B)
            return A;
        if (A-&amp;gt;key &amp;gt; B-&amp;gt;key)
        {
            A-&amp;gt;ch[1] = Merge(A-&amp;gt;ch[1], B);
            A-&amp;gt;Pushup();
            return A;
        }
        else
        {
            B-&amp;gt;ch[0] = Merge(A, B-&amp;gt;ch[0]);
            B-&amp;gt;Pushup();
            return B;
        }
    }
    typedef pair&amp;lt;Node *, Node *&amp;gt; DNode;
    DNode Split(Node *rt, int k)
    {
        if (!rt)
            return DNode(NULL, NULL);
        DNode o;
        if (size(rt-&amp;gt;ch[0]) &amp;gt;= k)
        {
            o = Split(rt-&amp;gt;ch[0], k);
            rt-&amp;gt;ch[0] = o.second;
            rt-&amp;gt;Pushup();
            o.second = rt;
        }
        else
        {
            o = Split(rt-&amp;gt;ch[1], k - size(rt-&amp;gt;ch[0]) - 1);
            rt-&amp;gt;ch[1] = o.first;
            rt-&amp;gt;Pushup();
            o.first = rt;
        }
        return o;
    }
  public:
    Treap()
    {
        root = NULL;
    }
    int kth(int k)
    {
        DNode x = Split(root, k - 1);
        DNode y = Split(x.second, 1);
        Node *ans = y.first;
        root = Merge(x.first, Merge(y.first, y.second));
        return ans-&amp;gt;v;
    }
    int rank(int x)
    {
        return rank(root, x);
    }
    int rank(Node *rt, int x)
    {
        if (!rt)
            return 0;
        return x &amp;lt;= rt-&amp;gt;v ? rank(rt-&amp;gt;ch[0], x) : rank(rt-&amp;gt;ch[1], x) + size(rt-&amp;gt;ch[0]) + 1;
    }
    void Insert(int x)
    {
        int k = rank(root, x);
        DNode y = Split(root, k);
        Node *n = new Node(x);
        root = Merge(Merge(y.first, n), y.second);
    }
    void remove(int x)
    {
        int k = rank(root, x);
        DNode a = Split(root, k);
        DNode b = Split(a.second, 1);
        root = Merge(a.first, b.second);
    }
} root[50005 &amp;lt;&amp;lt; 2];
#define lch l, m, rt &amp;lt;&amp;lt; 1
#define rch m + 1, r, rt &amp;lt;&amp;lt; 1 | 1
void build(int l, int r, int rt)
{
    for (int i = l; i &amp;lt;= r; i++)
        root[rt].Insert(a[i]);
}
void buildtree(int l, int r, int rt)
{
    build(l, r, rt);
    if (l == r)
        return;
    int m = l + r &amp;gt;&amp;gt; 1;
    buildtree(lch);
    buildtree(rch);
}
void updata(int k, int x, int y, int l, int r, int rt)
{
    root[rt].remove(y);
    root[rt].Insert(x);
    if (l == r)
        return;
    int m = l + r &amp;gt;&amp;gt; 1;
    if (k &amp;lt;= m)
        updata(k, x, y, lch);
    else
        updata(k, x, y, rch);
}
int rank(int L, int R, int x, int l, int r, int rt)
{
    if (L &amp;lt;= l &amp;amp;&amp;amp; R &amp;gt;= r)
        return root[rt].rank(x);
    int m = l + r &amp;gt;&amp;gt; 1;
    if (R &amp;lt;= m)
        return rank(L, R, x, lch);
    if (L &amp;gt; m)
        return rank(L, R, x, rch);
    return rank(L, R, x, lch) + rank(L, R, x, rch);
}
int kth(int L, int R, int k)
{
    int l = -1e10, r = 1e10;
    while (l &amp;lt;= r)
    {
        int m = l + r &amp;gt;&amp;gt; 1;
        int num = rank(L, R, m, 1, n, 1) + 1;
        if (num &amp;lt;= k)
            l = m + 1;
        else
            r = m - 1;
    }
    return r;
}
int main()
{
    //freopen(&quot;dynrank.in&quot;, &quot;r&quot;, stdin);
    //freopen(&quot;dynrank.out&quot;, &quot;w&quot;, stdout);
    //int T;
    //scanf(&quot;%d&quot;, &amp;amp;T);
    //while (T--)
    //{
    //    memset(root,0,sizeof(root));
        int m;
        scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
        for (int i = 1; i &amp;lt;= n; i++)
            scanf(&quot;%d&quot;, &amp;amp;a[i]);
        buildtree(1, n, 1);
        char s[5];
        int i, j, k, t;
        while (m--)
        {
            scanf(&quot;%s&quot;, s);
            if (s[0] == &apos;Q&apos;)
            {
                scanf(&quot;%d%d%d&quot;, &amp;amp;i, &amp;amp;j, &amp;amp;k);
                printf(&quot;%d\n&quot;, kth(i, j, k));
            }
            else
            {
                scanf(&quot;%d%d&quot;, &amp;amp;i, &amp;amp;t);
                updata(i, t, a[i], 1, n, 1);
                a[i] = t;
            }
        }
    //}
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>COGS 930 [河南省队2012] 找第k小的数</title><link>https://www.nekomio.com/posts/54/</link><guid isPermaLink="true">https://www.nekomio.com/posts/54/</guid><pubDate>Wed, 02 Aug 2017 21:45:43 GMT</pubDate><content:encoded>&lt;h2&gt;简单题面&lt;/h2&gt;
&lt;p&gt;求区间第k小&lt;/p&gt;
&lt;p&gt;COGS 1534 == 930 找第k小的数
本来是主席树或树套树的题
然而 可持久化Trie树 可以过
&amp;lt;!--more--&amp;gt;
查了查好像用可持久化Trie做区间k小的人很少啊（我好像是没有查到）
事实上 可持久化Trie树 比较好打，代码很短。
本来想用 可持久化Treap 做区间k小的结果和 zzh 又调又改弄了一个晚上
结果发现是真的不能做啊，Treap 区间不可减 他会变化
然后想到了可持久化Trie 发现好像可行啊，然后就出来了。
跑的好像也很快比树套树和不离散的主席树快。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
const int full = 21, fix = 1000001;
struct Trie
{
    struct Trie_Node
    {
        Trie_Node *ch[2];
        int s;
        Trie_Node()
        {
            ch[0] = ch[1] = NULL;
            s = 0;
        }
    } * root[100005],*null;
    Trie()
    {
        null = new Trie_Node();
        null-&amp;gt;ch[0] = null-&amp;gt;ch[1] = null;
        root[0] = new Trie_Node();
        root[0]-&amp;gt;ch[1] = root[0]-&amp;gt;ch[0] = null;
    }
    Trie_Node *NewNode()
    {
        Trie_Node *rt = new Trie_Node();
        rt-&amp;gt;ch[0] = rt-&amp;gt;ch[1] = null;
        return rt;
    }
    void copy(Trie_Node *&amp;amp;a, Trie_Node *b)
    {
        if (b == null)
            a = null;
        else
            a = NewNode(), *a = *b;
    }
    void Insert(int x, int cnt)
    {
        x += fix;
        copy(root[cnt], root[cnt - 1]);
        Trie_Node *rt1 = root[cnt], *rt2 = root[cnt - 1];
        for (int i = full; i &amp;gt;= 0; i--)
        {
            int k = (x &amp;gt;&amp;gt; i) &amp;amp; 1;
            copy(rt1-&amp;gt;ch[k], rt2-&amp;gt;ch[k]);
            if (rt1-&amp;gt;ch[k] == null)
                rt1-&amp;gt;ch[k] = NewNode();
            rt1 = rt1-&amp;gt;ch[k], rt2 = rt2-&amp;gt;ch[k];
            rt1-&amp;gt;s++;
        }
    }
    int kth(int k, int l, int r)
    {
        int res = 0;
        Trie_Node *rt1 = root[r], *rt2 = root[l - 1];
        for (int i = full; i &amp;gt;= 0; i--)
        {
            if (k &amp;gt; rt1-&amp;gt;ch[0]-&amp;gt;s - rt2-&amp;gt;ch[0]-&amp;gt;s)
            {
                k -= (rt1-&amp;gt;ch[0]-&amp;gt;s - rt2-&amp;gt;ch[0]-&amp;gt;s);
                res |= (1 &amp;lt;&amp;lt; i);
                rt1 = rt1-&amp;gt;ch[1], rt2 = rt2-&amp;gt;ch[1];
            }
            else
            {
                rt1 = rt1-&amp;gt;ch[0], rt2 = rt2-&amp;gt;ch[0];
            }
        }
        return res - fix;
    }
} root;
int main()
{
    freopen(&quot;kth.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;kth.out&quot;,&quot;w&quot;,stdout);
    int n, m, a;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;a);
        root.Insert(a, i);
    }
    int b, k;
    while (m--)
    {
        scanf(&quot;%d%d%d&quot;, &amp;amp;a, &amp;amp;b, &amp;amp;k);
        printf(&quot;%d\n&quot;, root.kth(k, a, b));
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>HDU 5996 dingyeye loves stone</title><link>https://www.nekomio.com/posts/53/</link><guid isPermaLink="true">https://www.nekomio.com/posts/53/</guid><pubDate>Sun, 30 Jul 2017 20:55:15 GMT</pubDate><content:encoded>&lt;h3&gt;Problem Description&lt;/h3&gt;
&lt;p&gt;dingyeye loves play stone game with you.&lt;/p&gt;
&lt;p&gt;dingyeye has an n-point tree.The nodes are numbered from 0 to n−1,while the root is numbered 0.Initially,there are a[i] stones on the i-th node.The game is in turns.When one move,he can choose a node and move some(this number cannot be 0) of the stones on it to its father.One loses the game if he can&apos;t do anything when he moves.
&amp;lt;!--more--&amp;gt;
You always move first.You want to know whether you can win the game if you play optimally.&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;In the first line, there is an integer $ T $ indicating the number of test cases.&lt;/p&gt;
&lt;p&gt;In each test case,the first line contains one integer n refers to the number of nodes.
The next line contains $ n−1 $ integers $ fa[1]⋯fa[n−1] $,which describe the father of nodes $ 1⋯n−1 $(node 0 is the root).It is guaranteed that $ 0≤fa[i]&amp;lt;i $.
The next line contains n integers $ a[0]⋯a[n−1] $,which describe the initial stones on each nodes.It is guaranteed that 0≤a[i]&amp;lt;134217728.
$ 1≤T≤100,1≤n≤100000 $.&lt;/p&gt;
&lt;p&gt;It is guaranteed that there is at most $ 7 $ test cases such that $n&amp;gt;100$.&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;For each test case output one line.If you can win the game,print &quot;win&quot;.Ohterwise,print &quot;lose&quot;.&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;br /&gt;
2&lt;br /&gt;
0&lt;br /&gt;
1000 1&lt;br /&gt;
4&lt;br /&gt;
0 1 0&lt;br /&gt;
2 3 3 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;p&gt;win&lt;br /&gt;
lose&lt;/p&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;由叶节点向根移石子&lt;br /&gt;
移不了的输&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;可看做多个阶梯博弈&lt;br /&gt;
将奇数层异或就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
int f[100005], a[100005];
vector&amp;lt;int&amp;gt; ch[100005];
int S;
void DFS(int x,int D)
{
    if(D&amp;amp;1) S^=a[x];
    for(auto i:ch[x])
    {
        DFS(i,D+1);
    }
}
int main(int argc, char const *argv[])
{
    int T;
    scanf(&quot;%d&quot;, &amp;amp;T);
    while (T--)
    {
        int n;
        scanf(&quot;%d&quot;, &amp;amp;n);
        for (int i = 0; i &amp;lt; n; i++)
            ch[i].clear();
        for (int i = 1; i &amp;lt;= n - 1; i++)
        {
            scanf(&quot;%d&quot;, &amp;amp;f[i]);
            ch[f[i]].push_back(i);
        }
        for (int i = 0; i &amp;lt;= n - 1; i++)
        {
            scanf(&quot;%d&quot;, &amp;amp;a[i]);
        }
        S = 0;
        DFS(0,0);
        if(S)
            printf(&quot;win\n&quot;);
        else 
            printf(&quot;lose\n&quot;);
    }
    //while(1);
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>POJ 1704 Georgia and Bob</title><link>https://www.nekomio.com/posts/52/</link><guid isPermaLink="true">https://www.nekomio.com/posts/52/</guid><pubDate>Sun, 30 Jul 2017 20:30:56 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;Georgia and Bob decide to play a self-invented game. They draw a row of grids on paper, number the grids from left to right by 1, 2, 3, ..., and place N chessmen on different grids, as shown in the following figure for example:
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;Georgia and Bob move the chessmen in turn. Every time a player will choose a chessman, and move it to the left without going over any other chessmen or across the left edge. The player can freely choose number of steps the chessman moves, with the constraint that the chessman must be moved at least ONE step and one grid can at most contains ONE single chessman. The player who cannot make a move loses the game.&lt;/p&gt;
&lt;p&gt;Georgia always plays first since &quot;Lady first&quot;. Suppose that Georgia and Bob both do their best in the game, i.e., if one of them knows a way to win the game, he or she will be able to carry it out.&lt;/p&gt;
&lt;p&gt;Given the initial positions of the n chessmen, can you predict who will finally win the game?&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;The first line of the input contains a single integer T (1 &amp;lt;= T &amp;lt;= 20), the number of test cases. Then T cases follow. Each test case contains two lines. The first line consists of one integer N (1 &amp;lt;= N &amp;lt;= 1000), indicating the number of chessmen. The second line contains N different integers P1, P2 ... Pn (1 &amp;lt;= Pi &amp;lt;= 10000), which are the initial positions of the n chessmen.&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;For each test case, prints a single line, &quot;Georgia will win&quot;, if Georgia will win the game; &quot;Bob will win&quot;, if Bob will win the game; otherwise &apos;Not sure&apos;.&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;br /&gt;
3&lt;br /&gt;
1 2 3&lt;br /&gt;
8&lt;br /&gt;
1 5 6 7 9 12 14 17&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Bob will win&lt;br /&gt;
Georgia will win&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;简单题意&lt;/h3&gt;
&lt;p&gt;在 1 * n 的格子上有一些石子&lt;br /&gt;
轮流将石子向右移动&lt;br /&gt;
不能移动的输&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;将间隙看做石子&lt;br /&gt;
做阶梯博弈&lt;br /&gt;
及 将奇数层的石子看做 Nim 游戏&lt;br /&gt;
偶数层不用管&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
int x[100005], b[100005];
int main(int argc, char const *argv[])
{
    int T;
    scanf(&quot;%d&quot;,&amp;amp;T);
    while (T--)
    {
        int n;
        scanf(&quot;%d&quot;, &amp;amp;n);
        for (int i = 1; i &amp;lt;= n; i++)
        {
            scanf(&quot;%d&quot;, &amp;amp;x[i]);
        }
        sort(x+1,x+n+1);
        for (int i = 1; i &amp;lt;= n; i++)
        {
            b[i] = x[i] - x[i - 1] - 1;
        }
        int S = 0;
        for (int i = n; i &amp;gt;= 1; i -= 2)
        {
            S ^= b[i];
        }
        if (S)
            printf(&quot;Georgia will win\n&quot;);
        else
            printf(&quot;Bob will win\n&quot;);
    }
    return 0;
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[bzoj 1449] [JSOI2009] 球队收益</title><link>https://www.nekomio.com/posts/51/</link><guid isPermaLink="true">https://www.nekomio.com/posts/51/</guid><pubDate>Sun, 30 Jul 2017 15:45:56 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/645602374fcf3.gif&quot; alt=&quot;645602374fcf3.gif&quot; /&gt;
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/72452186e227.gif&quot; alt=&quot;72452186e227.gif&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;一个整数表示联盟里所有球队收益之和的最小值。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3 3&lt;br /&gt;
1 0 2 1&lt;br /&gt;
1 1 10 1&lt;br /&gt;
0 1 3 3&lt;br /&gt;
1 2&lt;br /&gt;
2 3&lt;br /&gt;
3 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;43&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/469131504db0e.gif&quot; alt=&quot;469131504db0e.gif&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;题解懒得写了&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-07-29 15:51:58 
 * @Last Modified by: WildRage
 * @Last Modified time: 2017-07-29 16:05:11
 */
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
int win[5005], lose[5005];
int C[5005], D[5005], du[5005];
const int INF = 0x3f3f3f3f;
class Mincost
{
  public:
    int first[20005], p;
    Mincost()
    {
        memset(first, -1, sizeof(first));
    }
    class edge
    {
      public:
        int END, S, next, cap, cost;
    } v[100005];

    void add(int a, int b, int f, int c)
    {
        v[p].END = b, v[p].next = first[a], v[p].S = a, v[p].cap = f, v[p].cost = c, first[a] = p++;
        v[p].END = a, v[p].next = first[b], v[p].S = b, v[p].cap = 0, v[p].cost = -c, first[b] = p++;
    }
    int dis[20005], pre[20005];
    bool vis[20005];
    bool spfa(int S, int E)
    {
        memset(dis, 0x3f, sizeof(dis));
        memset(pre, -1, sizeof(pre));
        memset(vis, 0, sizeof(vis));
        queue&amp;lt;int&amp;gt; Q;
        Q.push(S);
        vis[S] = 1;
        dis[S] = 0;
        while (!Q.empty())
        {
            int u = Q.front();
            Q.pop();
            vis[u] = 0;
            for (int i = first[u]; i != -1; i = v[i].next)
            {
                if (!v[i].cap)
                    continue;
                if (dis[v[i].END] &amp;gt; dis[u] + v[i].cost)
                {
                    dis[v[i].END] = dis[u] + v[i].cost;
                    pre[v[i].END] = i;
                    if (!vis[v[i].END])
                    {
                        vis[v[i].END] = 1;
                        Q.push(v[i].END);
                    }
                }
            }
        }
        return dis[E] != 0x3f3f3f3f;
    }
    int MinCost(int S, int T)
    {
        int ans = 0, flow;
        while (spfa(S, T))
        {
            flow = INF;
            for (int i = pre[T]; i != -1; i = pre[v[i].S])
                flow = min(flow, v[i].cap);
            for (int i = pre[T]; i != -1; i = pre[v[i].S])
                v[i].cap -= flow, v[i ^ 1].cap += flow;
            ans += dis[T] * flow;
        }
        return ans;
    }
} Min;
int main(int argc, char const *argv[])
{
    int n, m, a, b;
    int S = 0, T = 10005;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d%d%d%d&quot;, &amp;amp;win[i], &amp;amp;lose[i], &amp;amp;C[i], &amp;amp;D[i]);
    }
    int ans = 0;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        Min.add(S, i, 1, 0);
        scanf(&quot;%d%d&quot;, &amp;amp;a, &amp;amp;b);
        Min.add(i, m + a, 1, 0);
        Min.add(i, m + b, 1, 0);
        du[a]++, du[b]++;
    }
    for (int i = 1; i &amp;lt;= n; i++)
        lose[i] += du[i];
    for (int i = 1; i &amp;lt;= n; i++)
        ans += lose[i] * lose[i] * D[i] + win[i] * win[i] * C[i];
    for (int i = 1; i &amp;lt;= n; i++)
    {
        for (int j = 1; j &amp;lt;= du[i]; j++)
        {
            Min.add(m + i, T, 1, 2 * win[i] * C[i] + C[i] + D[i] - 2 * lose[i] * D[i]);
            lose[i]--;
            win[i]++;
        }
    }
    printf(&quot;%d\n&quot;, ans + Min.MinCost(S, T));
    //while (1)
        ;
    return 0;
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[网络流24题] 搭配飞行员</title><link>https://www.nekomio.com/posts/50/</link><guid isPermaLink="true">https://www.nekomio.com/posts/50/</guid><pubDate>Sun, 30 Jul 2017 15:31:12 GMT</pubDate><content:encoded>&lt;h3&gt;【问题描述】&lt;/h3&gt;
&lt;p&gt;飞行大队有若干个来自各地的驾驶员，专门驾驶一种型号的飞机，这种飞机每架有两个驾驶员,需一个正驾驶员和一个副驾驶员。由于种种原因，例如相互配合的问题，有些驾驶员不能在同一架飞机上飞行，问如何搭配驾驶员才能使出航的飞机最多。
&amp;lt;!--more--&amp;gt;
&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/93216950253b1.jpg&quot; alt=&quot;93216950253b1.jpg&quot; /&gt;
如图，假设有10个驾驶员，如图中的V1，V2，…，V10就代表达10个驾驶员,其中V1，V2，V3，V4，V5是正驾驶员,V6，V7，V8，V9，V10是副驾驶员。如果一个正驾驶员和一个副驾驶员可以同机飞行，就在代表他们两个之间连一条线,两个人不能同机飞行，就不连。例如V1和V7可以同机飞行，而V1和V8就不行。请搭配飞行员，使出航的飞机最多。注意:因为驾驶工作分工严格,两个正驾驶员或两个副驾驶员都不能同机飞行.&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;输入文件有若干行
第一行，两个整数n与n1，表示共有n个飞行员(2&amp;lt;=n&amp;lt;=100),其中有n1名飞行员是正驾驶员.
下面有若干行,每行有2个数字a,b。表示正驾驶员a和副驾驶员b可以同机飞行。
注:正驾驶员的编号在前,即正驾驶员的编号小于副驾驶员的编号.&lt;/p&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;输出文件有一行
第一行，1个整数，表示最大起飞的飞机数。&lt;/p&gt;
&lt;h3&gt;【输入输出样例】&lt;/h3&gt;
&lt;h3&gt;输入文件名： flyer.in&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;10 5&lt;br /&gt;
1 7&lt;br /&gt;
2 6&lt;br /&gt;
2 10&lt;br /&gt;
3 7&lt;br /&gt;
4 8&lt;br /&gt;
5 9&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;输出文件名：flyer.out&lt;/h3&gt;
&lt;p&gt;4&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;二分图直接建图&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
const int INF = 0x3f3f3f3f;
class Dinic
{
  public:
    struct edge
    {
        int END, next, cap;
    } v[1005];
    int first[105], p;
    Dinic()
    {
        memset(first, -1, sizeof(first));
    }
    void add(int a, int b, int c)
    {
        v[p].END = b, v[p].next = first[a], v[p].cap = c, first[a] = p++;
        v[p].END = a, v[p].next = first[b], v[p].cap = 0, first[b] = p++;
    }
    int dis[105];
    bool vis[10005];
    bool BFS(int S, int E)
    {
        memset(vis, 0, sizeof(vis));
        memset(dis, -1, sizeof(dis));
        queue&amp;lt;int&amp;gt; Q;
        Q.push(S);
        dis[S] = 0;
        vis[S] = 1;
        while (!Q.empty())
        {
            int u = Q.front();
            Q.pop();
            for (int i = first[u]; i != -1; i = v[i].next)
            {
                if (!vis[v[i].END] &amp;amp;&amp;amp; v[i].cap &amp;gt; 0)
                {
                    vis[v[i].END] = 1;
                    dis[v[i].END] = dis[u] + 1;
                    if (v[i].END == E)
                        return 1;
                    Q.push(v[i].END);
                }
            }
        }
        return 0;
    }
    int DFS(int S, int E, int a)
    {
        if (S == E || a == 0)
            return a;
        int flow = 0, f;
        for (int i = first[S]; i != -1; i = v[i].next)
        {
            if (dis[v[i].END] == dis[S] + 1 &amp;amp;&amp;amp; (f = DFS(v[i].END, E, min(a, v[i].cap)) &amp;gt; 0))
            {
                v[i].cap -= f;
                v[i ^ 1].cap += f;
                a -= f;
                flow += f;
                if (f == 0)
                    break;
            }
        }
        if (!flow)
            dis[S] = -1;
        return flow;
    }
    int dinic(int S, int E)
    {
        int ans = 0;
        while (BFS(S, E))
        {
            ans += DFS(S, E, INF);
        }
        return ans;
    }
} dinic;
 
int main(int argc, char const *argv[])
{
    freopen(&quot;flyer.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;flyer.out&quot;,&quot;w&quot;,stdout);
    int n, n1, a, b;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;n1);
    while (scanf(&quot;%d%d&quot;, &amp;amp;a, &amp;amp;b) != EOF)
        dinic.add(a, b, 1);
    int S = 0, T = n + 1;
    for (int i = 1; i &amp;lt;= n1; i++)
    {
        dinic.add(S, i, 1);
    }
    for (int i = n1 + 1; i &amp;lt;= n; i++)
    {
        dinic.add(i, T, 1);
    }
    printf(&quot;%d\n&quot;, dinic.dinic(S, T));
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>vijos 天神下凡</title><link>https://www.nekomio.com/posts/48/</link><guid isPermaLink="true">https://www.nekomio.com/posts/48/</guid><pubDate>Sun, 30 Jul 2017 15:16:05 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;Czy找到宝藏获得屠龙宝刀和神秘秘籍！现在他要去找经常ntr他的Jmars报仇……&lt;/p&gt;
&lt;p&gt;Czy学会了一招“堕天一击”，他对一个地点发动堕天一击，地面上就会留下一个很大的圆坑。圆坑的周围一圈能量太过庞大，因此无法通过。所以每次czy发动技能都会把地面分割。Jmars拥有好大好大的土地，几十眼都望不到头，所以可以假设土地的大小是无限大。现在czy对他发动了猛烈的攻击，他想知道在泽宇攻击之后他的土地被切成几份了?
&amp;lt;!--more--&amp;gt;
Czy毕竟很虚，因此圆心都在x坐标轴上。另外，保证所有圆两两之间不会相交。&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;输入第一行为整数n，表示czy放了n次堕天一击。&lt;/p&gt;
&lt;p&gt;接下来n行，每行两个整数x[i]，r[i]。表示在坐标（x[i] , 0）放了一次堕天一击，半径为r[i]。&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输出一行，表示地面被分割成几块。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;4&lt;br /&gt;
7 5&lt;br /&gt;
-9 11&lt;br /&gt;
11 9&lt;br /&gt;
0 20&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;6&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;题解&lt;/h3&gt;
&lt;p&gt;那个栈扫一遍&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;stack&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
struct data
{
    int l, r, id;
    bool operator&amp;lt;(const data &amp;amp;a) const
    {
        return l == a.l ? r &amp;gt; a.r : l &amp;lt; a.l;
    }
} a[1000001];
int main(int argc, char const *argv[])
{
    stack&amp;lt;data&amp;gt; st;
    int n, s, r;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 0; i &amp;lt; n; i++)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;s, &amp;amp;r);
        a[i].l = s - r, a[i].id = i, a[i].r = s + r;
    }
    sort(a, a + n);
    // for (int i = 0; i &amp;lt; n; i++)
    // {
    //     printf(&quot;%d %d %d\n&quot;, a[i].l, a[i].r, a[i].id);
    // }
    //while (1)
        ;
    int ans = 0;
    for (int i = 0; i &amp;lt; n; i++)
    {
        if (a[i].l == a[i + 1].l &amp;amp;&amp;amp; i + 1 != n - 1)
        {
            st.push(a[i]);
            continue;
        }
        if (!st.empty() &amp;amp;&amp;amp; a[i].r == st.top().r)
        {
            st.pop();
            ans++;
        }
        if (a[i].r != a[i + 1].l)
        {
            if (!st.empty())
                st.pop();
        }
    }
    printf(&quot;%d&quot;, ans + n + 1);
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[网络流24题] 餐巾</title><link>https://www.nekomio.com/posts/49/</link><guid isPermaLink="true">https://www.nekomio.com/posts/49/</guid><pubDate>Sun, 30 Jul 2017 15:16:05 GMT</pubDate><content:encoded>&lt;h3&gt;【问题描述】&lt;/h3&gt;
&lt;p&gt;一个餐厅在相继的N天里，第i天需要Ri块餐巾(i=l，2，…，N)。餐厅可以从三种途径获得餐巾。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;购买新的餐巾，每块需p分；&lt;/li&gt;
&lt;li&gt;把用过的餐巾送到快洗部，洗一块需m天，费用需f分(f&amp;lt;p)。如m=l时，第一天送到快洗部的餐巾第二天就可以使用了，送慢洗的情况也如此。&lt;br /&gt;
&amp;lt;!--more--&amp;gt;&lt;/li&gt;
&lt;li&gt;把餐巾送到慢洗部，洗一块需n天(n&amp;gt;m)，费用需s分(s&amp;lt;f)。在每天结束时，餐厅必须决定多少块用过的餐巾送到快洗部，多少块送慢洗部。在每天开始时，餐厅必须决定是否购买新餐巾及多少，使洗好的和新购的餐巾之和满足当天的需求量Ri，并使N天总的费用最小。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;【输入】&lt;/h3&gt;
&lt;p&gt;输入文件共 3 行，第 1 行为总天数；第 2 行为每天所需的餐巾块数；第 3 行为每块餐巾的新购费用 p ，快洗所需天数 m ，快洗所需费用 f ，慢洗所需天数 n ，慢洗所需费用 s 。&lt;/p&gt;
&lt;h3&gt;【输出】&lt;/h3&gt;
&lt;p&gt;一行，最小的费用&lt;/p&gt;
&lt;h3&gt;【样例】&lt;/h3&gt;
&lt;h3&gt;napkin.in&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;br /&gt;
3 2 4&lt;br /&gt;
10 1 6 2 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;napkin.out&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;64&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【数据规模】&lt;/h3&gt;
&lt;p&gt;n&amp;lt;=200,Ri&amp;lt;=50&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;将天拆点&lt;br /&gt;
由源点向天的第一个点连边&lt;br /&gt;
然后由天的第二个点向汇点连边&lt;br /&gt;
流量都为Ri  费用为零&lt;br /&gt;
由源点向天的第二个点连流量为正无穷 费用为p的边&lt;br /&gt;
然后由前一天的剩下的向后一天连边&lt;br /&gt;
由前一天洗过的向能用的那一天连边&lt;br /&gt;
然后跑最小费用最大流就好了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;queue&amp;gt;
using namespace std;
const int INF = 0x3f3f3f3f;
class Mincost
{
  public:
    int first[20005], p;
    Mincost()
    {
        memset(first, -1, sizeof(first));
    }
    class edge
    {
      public:
        int END, S, next, cap, cost;
    } v[100005];
 
    void add(int a, int b, int f, int c)
    {
        v[p].END = b, v[p].next = first[a], v[p].S = a, v[p].cap = f, v[p].cost = c, first[a] = p++;
        v[p].END = a, v[p].next = first[b], v[p].S = b, v[p].cap = 0, v[p].cost = -c, first[b] = p++;
    }
    int dis[20005], pre[20005];
    bool vis[20005];
    bool spfa(int S, int E)
    {
        memset(dis, 0x3f, sizeof(dis));
        memset(pre, -1, sizeof(pre));
        memset(vis, 0, sizeof(vis));
        queue&amp;lt;int&amp;gt; Q;
        Q.push(S);
        vis[S] = 1;
        dis[S] = 0;
        while (!Q.empty())
        {
            int u = Q.front();
            Q.pop();
            vis[u] = 0;
            for (int i = first[u]; i != -1; i = v[i].next)
            {
                if (!v[i].cap)
                    continue;
                if (dis[v[i].END] &amp;gt; dis[u] + v[i].cost)
                {
                    dis[v[i].END] = dis[u] + v[i].cost;
                    pre[v[i].END] = i;
                    if (!vis[v[i].END])
                    {
                        vis[v[i].END] = 1;
                        Q.push(v[i].END);
                    }
                }
            }
        }
        return dis[E] != 0x3f3f3f3f;
    }
    int MinCost(int S, int T)
    {
        int ans = 0, flow;
        while (spfa(S, T))
        {
            flow = INF;
            for (int i = pre[T]; i != -1; i = pre[v[i].S])
                flow = min(flow, v[i].cap);
            for (int i = pre[T]; i != -1; i = pre[v[i].S])
                v[i].cap -= flow, v[i ^ 1].cap += flow;
            ans += dis[T] * flow;
        }
        return ans;
    }
} Min;
int a[205];
int main(int argc, char const *argv[])
{
    freopen(&quot;napkin.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;napkin.out&quot;,&quot;w&quot;,stdout);
    int n, p, m, f, c, s;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, a + i);
    }
    scanf(&quot;%d%d%d%d%d&quot;, &amp;amp;p, &amp;amp;m, &amp;amp;f, &amp;amp;c, &amp;amp;s);
    int S = 0, T = n * 3;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        Min.add(S, i, a[i], 0);
        Min.add(n + i, T, a[i], 0);
        Min.add(S, i + n, INF, p);
        //Min.add(i, i + n, a[i], 0);
        if (i + 1 &amp;lt;= n)
            Min.add(i, i + 1, INF, 0);
        if (i + m &amp;lt;= n)
            Min.add(i, i + n + m, INF, f);
        if (i + c &amp;lt;= n)
            Min.add(i, i + n + c, INF, s);
    }
    printf(&quot;%d&quot;, Min.MinCost(S, T));
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>vijos 藏宝图</title><link>https://www.nekomio.com/posts/47/</link><guid isPermaLink="true">https://www.nekomio.com/posts/47/</guid><pubDate>Sun, 30 Jul 2017 06:27:22 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;Czy爬上黑红树，到达了一个奇怪的地方……&lt;/p&gt;
&lt;p&gt;Czy发现了一张奇怪的藏宝图。图上有n个点，m条无向边。已经标出了图中两两之间距离dist。但是czy知道，只有当图刚好又是一颗树的时候，这张藏宝图才是真的。如果藏宝图是真的，那么经过点x的边的边权平均数最大的那个x是藏着宝物的地方。请计算这是不是真的藏宝图，如果是真的藏宝之处在哪里。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;输入数据第一行一个数T,表示T组数据。&lt;/p&gt;
&lt;p&gt;对于每组数据，第一行一个n，表示藏宝图上的点的个数。&lt;/p&gt;
&lt;p&gt;接下来n行,每行n个数，表示两两节点之间的距离。&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输出一行或两行。第一行”Yes”或”No”，表示这是不是真的藏宝图。&lt;/p&gt;
&lt;p&gt;若是真的藏宝图，第二行再输出一个数，表示哪个点是藏宝之处。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;br /&gt;
3&lt;br /&gt;
0 7 9&lt;br /&gt;
7 0 2&lt;br /&gt;
9 2 0&lt;br /&gt;
3&lt;br /&gt;
0 2 7&lt;br /&gt;
2 0 9&lt;br /&gt;
7 9 0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Yes&lt;br /&gt;
1&lt;br /&gt;
Yes&lt;br /&gt;
3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;样例解释:第一棵树的形状是1--2--3。1、2之间的边权是7，2、3之间是2。&lt;br /&gt;
第二棵树的形状是2--1--3。2、1之间的边权是2，1、3之间是7。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;提示&lt;/h3&gt;
&lt;p&gt;对于30%数据，n&amp;lt;=50,1&amp;lt;=树上的边的长度&amp;lt;=10^9。
对于50%数据，n&amp;lt;=600.
对于100%数据，1&amp;lt;=n&amp;lt;=2500,除30%小数据外任意0&amp;lt;=dist[i][j]&amp;lt;=10^9,T&amp;lt;=5&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;跑最小生成树&lt;br /&gt;
然后跑两两之间距离DFS&lt;br /&gt;
比较一下两个矩阵就出来了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>vijos 黑红树</title><link>https://www.nekomio.com/posts/46/</link><guid isPermaLink="true">https://www.nekomio.com/posts/46/</guid><pubDate>Sun, 30 Jul 2017 06:16:02 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;Mz们在czy的生日送他一个黑红树种子……czy种下种子，结果种子很快就长得飞快，它的枝干伸入空中看不见了……&lt;/p&gt;
&lt;p&gt;Czy发现黑红树具有一些独特的性质。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;这是二叉树，除根节点外每个节点都有红与黑之间的一种颜色。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;每个节点的两个儿子节点都被染成恰好一个红色一个黑色。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这棵树你是望不到头的（树的深度可以到无限大）
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;黑红树上的高度这样定义:h(根节点)=0，h[son]=h[father]+1。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Czy想从树根顺着树往上爬。他有p/q的概率到达红色的儿子节点，有1-p/q的概率到达黑色节点。但是他知道如果自己经过的路径是不平衡的，他会马上摔下来。一条红黑树上的链是不平衡的，当且仅当红色节点与黑色节点的个数之差大于1。现在他想知道他刚好在高度为h的地方摔下来的概率的精确值a/b，gcd(a,b)=0。那可能很大，所以他只要知道a,b对K取模的结果就可以了。另外，czy对输入数据加密：第i个询问Qi真正大小将是给定的Q减上一个询问的第一个值a%K.&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第一行四个数p,q,T,k，表示走红色节点概率是p/q，以下T组询问，答案对K取模。接下来T行，每行一个数 Q,表示czy想知道刚好在高度Q掉下来的概率（已加密）&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输出T行，每行两个整数，表示要求的概率a/b中a%K和b%K的精确值。如果这个概率就是0或1，直接输出0 0或1 1（中间有空格）。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;p&gt;样例输入1&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2 3 2 100&lt;br /&gt;
1&lt;br /&gt;
2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;样例输入2&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2 3 2 20&lt;br /&gt;
4&lt;br /&gt;
6&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;p&gt;样例输出1&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;0 0&lt;br /&gt;
5 9&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;样例输出2&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;0 1
0 9&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;提示&lt;/h3&gt;
&lt;p&gt;对于30%数据,p,q&amp;lt;=5,T&amp;lt;=1000,K&amp;lt;=127,对于任意解密后的Q，有Q&amp;lt;=30&lt;/p&gt;
&lt;p&gt;对于60%数据,p,q&amp;lt;=20,T&amp;lt;=100000,K&amp;lt;=65535,对于任意解密后的Q,有Q&amp;lt;=1000&lt;/p&gt;
&lt;p&gt;对于100%数据,p,q&amp;lt;=100,T&amp;lt;=1000000, K&amp;lt;=1000000007,对于任意解密后的Q,有Q&amp;lt;=1000000&lt;/p&gt;
&lt;p&gt;对于100%数据,有q&amp;gt;p,即0&amp;lt;= p/q&amp;lt;=1&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;不写了&lt;br /&gt;
主要就是两行两行的考虑&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
int P;
class frac
{
  public:
    long long a, b;
    long long gcd(long long A, long long B)
    {
        return B == 0 ? A : gcd(B, A % B);
    }
    frac Update(frac s)
    {
        if (s.a == 0)
            return s;
        int GCD = s.gcd(s.a, s.b);
        return (frac){s.a / GCD, s.b / GCD};
    }
    frac operator*(const frac A)
    {
        return (frac){a * A.a % P, b * A.b % P};
    }
    frac operator*(const int A)
    {
        return (frac){a * A % P, b % P};
    }
};
frac ans[1000001];
// 0 b, 1 r
// 0 = ,1 b&amp;gt;r ,2,b&amp;lt;r
int main()
{
    //freopen(&quot;brtree.in&quot;, &quot;r&quot;, stdin);
    //freopen(&quot;brtree.out&quot;, &quot;w&quot;, stdout);
    int p, q, T;
    scanf(&quot;%d%d%d%d&quot;, &amp;amp;p, &amp;amp;q, &amp;amp;T, &amp;amp;P);
    p %= P;
    q %= P;
    frac B = (frac){q - p, q};
    frac R = (frac){p, q};
    frac BR = B * R * 2;
    frac BBRR = (frac){p * p + (q - p) * (q - p), q * q};
    BR = BR.Update(BR);
    BBRR = BBRR.Update(BBRR);
    ans[2] = BBRR;
    for (int i = 4; i &amp;lt;= 1000000; i += 2)
    {
        ans[i] = ans[i - 2] * BR;
    }
    int k = 0, r = 0;
    while (T--)
    {
        scanf(&quot;%d&quot;, &amp;amp;k);
        k -= r;
        //int Gcd = ans[k].gcd(ans[k].a, ans[k].b);
        r = 0;
        printf(&quot;%lld %lld\n&quot;, ans[k].a % P, ans[k].b % P);
        r = ans[k].a % P;
    }
}
 
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 2510 弱题</title><link>https://www.nekomio.com/posts/45/</link><guid isPermaLink="true">https://www.nekomio.com/posts/45/</guid><pubDate>Thu, 27 Jul 2017 21:18:32 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;有M个球，一开始每个球均有一个初始标号，标号范围为1～N且为整数，标号为i的球有ai个，并保证Σai = M。
每次操作等概率取出一个球（即取出每个球的概率均为1/M），若这个球标号为k（k &amp;lt; N），则将它重新标号为k + 1；若这个球标号为N，则将其重标号为1。（取出球后并不将其丢弃）
现在你需要求出，经过K次这样的操作后，每个标号的球的期望个数。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第1行包含三个正整数N，M，K，表示了标号与球的个数以及操作次数。
第2行包含N个非负整数ai，表示初始标号为i的球有ai个。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;应包含N行，第i行为标号为i的球的期望个数，四舍五入保留3位小数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2 3 2&lt;br /&gt;
3 0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1.667&lt;br /&gt;
1.333&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;h5&gt;【样例说明】&lt;/h5&gt;
&lt;p&gt;第1次操作后，由于标号为2球个数为0，所以必然是一个标号为1的球变为标号为2的球。所以有2个标号为1的球，有1个标号为2的球。&lt;/p&gt;
&lt;p&gt;第2次操作后，有1/3的概率标号为2的球变为标号为1的球（此时标号为1的球有3个），有2/3的概率标号为1的球变为标号为2的球（此时标号为1的球有1个），所以标号为1的球的期望个数为1/3&lt;em&gt;3+2/3&lt;/em&gt;1 = 5/3。同理可求出标号为2的球期望个数为4/3。&lt;/p&gt;
&lt;h5&gt;【数据规模与约定】&lt;/h5&gt;
&lt;p&gt;对于10%的数据，N ≤ 5, M ≤ 5, K ≤ 10；&lt;br /&gt;
对于20%的数据，N ≤ 20, M ≤ 50, K ≤ 20；&lt;br /&gt;
对于30%的数据，N ≤ 100, M ≤ 100, K ≤ 100；&lt;br /&gt;
对于40%的数据，M ≤ 1000, K ≤ 1000；&lt;br /&gt;
对于100%的数据，N ≤ 1000, M ≤ 100,000,000, K ≤ 2,147,483,647。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;一看k的范围&lt;br /&gt;
就能看出要矩阵乘优化&lt;br /&gt;
易得矩阵为
$$
\begin{bmatrix}
1-\frac{1}{m} &amp;amp; \frac{1}{m} &amp;amp; 0 &amp;amp; \cdots &amp;amp; 0 \
0 &amp;amp; 1-\frac{1}{m} &amp;amp; \frac{1}{m} &amp;amp;\cdots &amp;amp; 0 \
\vdots &amp;amp; \vdots &amp;amp; \vdots &amp;amp; \ddots &amp;amp; \vdots \
\frac{1}{m} &amp;amp; 0 &amp;amp; 0 &amp;amp; \cdots &amp;amp; 1-\frac{1}{m} \
\end{bmatrix}
$$&lt;/p&gt;
&lt;p&gt;然后我们发现n=1000过不了&lt;br /&gt;
但是我们发现这个矩阵是一个循环矩阵&lt;br /&gt;
只用维护第一行就可以了&lt;br /&gt;
降低到$ n^2*log_2{k} $
就可以跑了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;iostream&amp;gt;
using namespace std;
struct Martix
{
    double a[1005];
    int n;
    Martix(int x)
    {
        n = x;
        memset(a, 0, sizeof(a));
    }
    Martix operator*(const Martix &amp;amp;b)
    {
        Martix ans(n);
        ans.a[1] = 0;
        for (int i = 1; i &amp;lt;= n; i++)
        {
            for (int k = 1; k &amp;lt;= n; k++)
            {
                int t=(i-k+n+1)%n;
                if(!t) t+=n;
                ans.a[i] += a[k] * b.a[t];
            }
        }
        return ans;
    }
    Martix operator^(const int x)
    {
        Martix a = *this, ans(n);
        int k = x;
        ans.a[1] = 1;
        while (k)
        {
            if (k &amp;amp; 1)
                ans = ans * a;
            k &amp;gt;&amp;gt;= 1;
            a = a * a;
        }
        return ans;
    }
};
int a[1005];
double ans[1005];
int main(int argc, char const *argv[])
{
    int n, m, k;
    scanf(&quot;%d%d%d&quot;,&amp;amp;n,&amp;amp;m,&amp;amp;k);
    for (int i = 1; i &amp;lt;= n; i++)
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
    Martix K(n);
    K.a[1] = (double)1 - ((double)1 / m);
    K.a[2] = ((double)1 / m);
    K=K^k;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        for (int j = 1; j &amp;lt;= n; j++)
        {
            int t=(i+j-1)%n;
            if(!t) t+=n;
            ans[t] += K.a[i] * a[j];
        }
    }
    for (int i = 1; i &amp;lt;= n; i++)
    {
        printf(&quot;%.3lf\n&quot;, ans[i]);
    }
    //while(1);
    return 0;
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[NOIP2011] 玛雅游戏</title><link>https://www.nekomio.com/posts/44/</link><guid isPermaLink="true">https://www.nekomio.com/posts/44/</guid><pubDate>Thu, 27 Jul 2017 21:04:01 GMT</pubDate><content:encoded>&lt;h3&gt;【问题描述】&lt;/h3&gt;
&lt;p&gt;Mayan puzzle 是最近流行起来的一个游戏。游戏界面是一个7 行5 列的棋盘，上面堆放着一些方块，方块不能悬空堆放，即方块必须放在最下面一行，或者放在其他方块之上。游戏通关是指在规定的步数内消除所有的方块，消除方块的规则如下：
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;每步移动可以且仅可以沿横向（即向左或向右）拖动某一方块一格：当拖动这一方块时，如果拖动后到达的位置（以下称目标位置）也有方块，那么这两个方块将交换位置（参见输入输出样例说明中的图6 到图7）；如果目标位置上没有方块，那么被拖动的方块将从原来的竖列中抽出，并从目标位置上掉落（直到不悬空，参见下面图1 和图2）；
&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/5211920921a01.png&quot; alt=&quot;5211920921a01.png&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;任一时刻，如果在一横行或者竖列上有连续三个或者三个以上相同颜色的方块，则它们将立即被消除（参见图1 到图3）。
&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/53446976e072a.png&quot; alt=&quot;53446976e072a.png&quot; /&gt;
注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果同时有多组方块满足消除条件，几组方块会同时被消除（例如下面图4，三个颜色为1 的方块和三个颜色为2 的方块会同时被消除，最后剩下一个颜色为2 的方块）。&lt;/li&gt;
&lt;li&gt;当出现行和列都满足消除条件且行列共享某个方块时，行和列上满足消除条件的所有方块会被同时消除（例如下面图5 所示的情形，5 个方块会同时被消除）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;方块消除之后，消除位置之上的方块将掉落，掉落后可能会引起新的方块消除。注意：掉落的过程中将不会有方块的消除。&lt;br /&gt;
上面图1 到图3 给出了在棋盘上移动一块方块之后棋盘的变化。棋盘的左下角方块的坐标为（0, 0），将位于（3, 3）的方块向左移动之后，游戏界面从图1 变成图2 所示的状态，此时在一竖列上有连续三块颜色为4 的方块，满足消除条件，消除连续3 块颜色为4 的方块后，上方的颜色为3 的方块掉落，形成图3 所示的局面。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;【输入】&lt;/h3&gt;
&lt;p&gt;输入文件mayan.in，共6 行。&lt;br /&gt;
第一行为一个正整数n，表示要求游戏通关的步数。&lt;br /&gt;
接下来的5 行，描述7*5 的游戏界面。每行若干个整数，每两个整数之间用一个空格隔开，每行以一个0 结束，自下向上表示每竖列方块的颜色编号（颜色不多于10 种，从1 开始顺序编号，相同数字表示相同颜色）。&lt;br /&gt;
输入数据保证初始棋盘中没有可以消除的方块。&lt;/p&gt;
&lt;h3&gt;【输出】&lt;/h3&gt;
&lt;p&gt;输出文件名为mayan.out。&lt;br /&gt;
如果有解决方案，输出n 行，每行包含3 个整数x，y，g，表示一次移动，每两个整数之间用一个空格隔开，其中（x，y）表示要移动的方块的坐标，g 表示移动的方向，1 表示向右移动，-1 表示向左移动。注意：多组解时，按照x 为第一关健字，y 为第二关健字，1优先于-1，给出一组字典序最小的解。游戏界面左下角的坐标为（0，0）。&lt;br /&gt;
如果没有解决方案，输出一行，包含一个整数-1。&lt;/p&gt;
&lt;h3&gt;mayan.in&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;br /&gt;
1 0&lt;br /&gt;
2 1 0&lt;br /&gt;
2 3 4 0&lt;br /&gt;
3 1 0&lt;br /&gt;
2 4 3 4 0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;mayan.out&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2 1 1&lt;br /&gt;
3 1 1&lt;br /&gt;
3 0 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【输入输出样例说明】&lt;/h3&gt;
&lt;p&gt;按箭头方向的顺序分别为图6 到图11
&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/19512145e77e.png&quot; alt=&quot;19512145e77e.png&quot; /&gt;
样例输入的游戏局面如上面第一个图片所示，依次移动的三步是：（2，1）处的方格向右移动，（3，1）处的方格向右移动，（3，0）处的方格向右移动，最后可以将棋盘上所有方块消除。&lt;/p&gt;
&lt;h3&gt;【数据范围】&lt;/h3&gt;
&lt;p&gt;对于30%的数据，初始棋盘上的方块都在棋盘的最下面一行；&lt;br /&gt;
对于100%的数据，0 &amp;lt; n≤5。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;大暴搜&lt;br /&gt;
读完题先看数据范围&lt;br /&gt;
发现这道题的 n 很小&lt;br /&gt;
感觉应该可以搜&lt;br /&gt;
然后想到了BFS&lt;br /&gt;
一个一个的试&lt;br /&gt;
现在的问题就是如何消除和下落在消除的时候横着扫一遍竖着扫一遍&lt;br /&gt;
两个for打上标记&lt;br /&gt;
然后一遍循环搞掉标记的点&lt;br /&gt;
在BFS传参数的时候要注意备份用 &lt;code&gt;memcpy();&lt;/code&gt;&lt;br /&gt;
在搜的时候及时退出&lt;code&gt;exit(0);&lt;/code&gt;&lt;br /&gt;
否则可能被卡&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;stack&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
using namespace std;
//#define WILDRAGE 1
int a[6][8];
bool over[6][8];
void print(const int c[6][8])
{
    for (int i = 1; i &amp;lt;= 5; i++)
    {
        for (int j = 1; j &amp;lt;= 7; j++)
            printf(&quot;%d &quot;, c[i][j]);
        printf(&quot;\n&quot;);
    }
    printf(&quot;\n&quot;);
}
bool ok(const int c[6][8])
{
    //return 0;
    for (int i = 1; i &amp;lt;= 5; i++)
    {
        if (c[i][1])
            return 0;
    }
    return 1;
}
bool remove(int c[6][8])
{
    int it1, it2;
    for (int i = 1; i &amp;lt;= 5; i++)
    {
        it1 = it2 = 1;
        while (1)
        {
            while (c[i][it1] != 0 &amp;amp;&amp;amp; it1 &amp;lt;= 7)
                it1++;
            it2 = it1;
            while (c[i][it2] == 0 &amp;amp;&amp;amp; it2 &amp;lt;= 7)
                it2++;
            if (it2 != 8)
                swap(c[i][it2], c[i][it1]);
            else
                break;
        }
    }
    // memset(over,0,sizeof(over));
    int times = 1;
    for (int i = 1; i &amp;lt;= 5; i++)
        for (int j = 1; j &amp;lt;= 7; j++)
        {
            if (c[i][j] &amp;amp;&amp;amp; c[i][j] == c[i][j - 1])
            {
                times++;
                if (times &amp;gt;= 3 &amp;amp;&amp;amp; times &amp;lt; 4)
                {
                    over[i][j - 2] = over[i][j - 1] = over[i][j] = 1;
                }
                if (times &amp;gt;= 4)
                    over[i][j] = 1;
            }
            else
                times = 1;
        }
    times = 1;
    for (int j = 1; j &amp;lt;= 7; j++)
        for (int i = 1; i &amp;lt;= 5; i++)
        {
            if (c[i][j] &amp;amp;&amp;amp; c[i][j] == c[i - 1][j])
            {
                times++;
                if (times &amp;gt;= 3 &amp;amp;&amp;amp; times &amp;lt; 4)
                {
                    over[i - 2][j] = over[i - 1][j] = over[i][j] = 1;
                }
                if (times &amp;gt;= 4)
                    over[i][j] = 1;
            }
            else
                times = 1;
        }
    bool yes = 0;
    for (int i = 1; i &amp;lt;= 5; i++)
        for (int j = 1; j &amp;lt;= 7; j++)
            if (over[i][j])
                yes = 1, over[i][j] = 0, c[i][j] = 0;
    if (!yes)
        return 0;
    //int it1, it2;
    for (int i = 1; i &amp;lt;= 5; i++)
    {
        it1 = it2 = 1;
        while (1)
        {
            while (c[i][it1] != 0 &amp;amp;&amp;amp; it1 &amp;lt;= 7)
                it1++;
            it2 = it1;
            while (c[i][it2] == 0 &amp;amp;&amp;amp; it2 &amp;lt;= 7)
                it2++;
            if (it2 != 8)
                swap(c[i][it2], c[i][it1]);
            else
                break;
        }
    }
    return 1;
}
struct data
{
    int x, y, t;
};
stack&amp;lt;data&amp;gt; op;
stack&amp;lt;data&amp;gt; ans;
int n;
void dfs(int t, const int c[6][8])
{
    if (t == n)
    {
#ifdef WILDRAGE
        print(c);
#endif
        if (ok(c))
        {
            while (!op.empty())
            {
                ans.push(op.top());
                op.pop();
            }
            while (!ans.empty())
            {
                printf(&quot;%d %d %d\n&quot;, ans.top().x - 1, ans.top().y - 1, ans.top().t);
                ans.pop();
            }
            exit(0);
        }
        return;
    }
    else
    {
        int s[6][8];
        for (int i = 1; i &amp;lt;= 5; i++)
        {
            for (int j = 1; j &amp;lt;= 7; j++)
            {
                if (c[i][j] &amp;amp;&amp;amp; i + 1 &amp;lt;= 5)
                {
                    op.push((data){i, j, 1});
                    memcpy(s, c, sizeof(s));
                    swap(s[i][j], s[i + 1][j]);
#ifdef WILDRAGE
//print(s);
#endif
                    while (remove(s))
                        ;
#ifdef WILDRAGE
                    printf(&quot;%d %d %d\n&quot;, i, j, 1);
                    print(s);
#endif
                    dfs(t + 1, s);
                    op.pop();
                }
                if (c[i][j] &amp;amp;&amp;amp; i - 1 &amp;gt; 0 &amp;amp;&amp;amp; !c[i - 1][j])
                {
                    op.push((data){i, j, -1});
                    memcpy(s, c, sizeof(s));
                    swap(s[i][j], s[i - 1][j]);
#ifdef WILDRAGE
//print(s);
#endif
                    while (remove(s))
                        ;
#ifdef WILDRAGE
                    printf(&quot;%d %d %d\n&quot;, i, j, -1);
                    print(s);
#endif
                    dfs(t + 1, s);
                    op.pop();
                }
            }
        }
    }
}
int main()
{
#ifndef WILDRAGE
    freopen(&quot;mayan.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;mayan.out&quot;, &quot;w&quot;, stdout);
#endif
    int s;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= 5; i++)
    {
        int j = 0;
        while (scanf(&quot;%d&quot;, &amp;amp;s))
        {
            if (s == 0)
                break;
            a[i][++j] = s;
        }
        //a[i][0] = j;
    }
#ifdef WILDRAGE
    print(a);
#endif
    dfs(0, a);
    printf(&quot;-1\n&quot;);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 2090 [Poi2010] Monotonicity 2</title><link>https://www.nekomio.com/posts/43/</link><guid isPermaLink="true">https://www.nekomio.com/posts/43/</guid><pubDate>Thu, 27 Jul 2017 20:51:03 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;给出N个正整数a[1..N]，再给出K个关系符号（&amp;gt;、&amp;lt;或=）s[1..k]。
选出一个长度为L的子序列（不要求连续），要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1]。
求出L的最大值。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行两个正整数，分别表示N和K (N, K &amp;lt;= 500,000)。
第二行给出N个正整数，第i个正整数表示a[i]（a[i] &amp;lt;= 10^6）。
第三行给出K个空格隔开关系符号（&amp;gt;、&amp;lt;或=），第i个表示s[i]。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;一个正整数，表示L的最大值。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;7 3&lt;br /&gt;
2 4 3 1 3 5 3&lt;br /&gt;
&amp;lt; &amp;gt; =&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;6&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;选出的子序列为2 4 3 3 5 3，相邻大小关系分别是&amp;lt; &amp;gt; = &amp;lt; &amp;gt;。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;权值树状数组优化DP&lt;br /&gt;
不会正确性证明&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
const int MaxN = 1000000;
int Max1[MaxN + 5], Max2[MaxN + 5], Max3[MaxN + 5];
#define lowbit(_) ((_) &amp;amp; (-_))
void Update1(int a, int b)
{
    for (int i = a; i &amp;lt;= MaxN; i += lowbit(i))
    {
        Max1[i] = max(b, Max1[i]);
    }
}
void Update2(int a, int b)
{
    for (int i = a; i &amp;gt; 0; i -= lowbit(i))
    {
        Max2[i] = max(b, Max2[i]);
    }
}
int MAX1(int x)
{
    int ans = 0;
    for (int i = x; i &amp;gt; 0; i -= lowbit(i))
    {
        ans = max(ans, Max1[i]);
    }
    return ans;
}
int MAX2(int x)
{
    int ans = 0;
    for (int i = x; i &amp;lt;= MaxN; i += lowbit(i))
    {
        ans = max(ans, Max2[i]);
    }
    return ans;
}
int a[500005], op[500005];
int f[500005][4], n, k;
void add(int len, int a)
{
    int W = (len - 1) % k + 1;
    switch (op[W])
    {
    case 1:
        Update1(a, len);
        break;
    case 2:
        Update2(a, len);
        break;
    case 3:
        Max3[a] = max(len, Max3[a]);
        break;
    default:
        printf(&quot;ERROR\n&quot;);
        exit(0);
        break;
    }
}
int main()
{
    //freopen(&quot;mot.in&quot;, &quot;r&quot;, stdin);
    //freopen(&quot;mot.out&quot;, &quot;w&quot;, stdout);
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;k);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
    }
    char c;
    for (int i = 1; i &amp;lt;= k; i++)
    {
        c = getchar();
        while (c != &apos;&amp;lt;&apos; &amp;amp;&amp;amp; c != &apos;&amp;gt;&apos; &amp;amp;&amp;amp; c != &apos;=&apos;)
            c = getchar();
        switch (c)
        {
        case &apos;&amp;lt;&apos;:
            op[i] = 1;
            break;
        case &apos;&amp;gt;&apos;:
            op[i] = 2;
            break;
        case &apos;=&apos;:
            op[i] = 3;
        }
    }
    int ans = 0;
    //f[1][1] = f[1][2] = f[1][3] = 1;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        f[i][1] = MAX1(a[i] - 1) + 1;
        f[i][2] = MAX2(a[i] + 1) + 1;
        f[i][3] = Max3[a[i]] + 1;
        for (int j = 1; j &amp;lt;= 3; j++)
        {
            add(f[i][j], a[i]);
            ans = max(ans, f[i][j]);
        }
    }
    //for(int i=1;i&amp;lt;=n;i++)
    //    printf(&quot;%d %d %d\n&quot;,f[i][1],f[i][2],f[i][3]);
    // while(1);
    printf(&quot;%d&quot;, ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 2438 [中山市选2011] 杀人游戏</title><link>https://www.nekomio.com/posts/42/</link><guid isPermaLink="true">https://www.nekomio.com/posts/42/</guid><pubDate>Thu, 27 Jul 2017 15:52:00 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;一位冷血的杀手潜入 Na-wiat，并假装成平民。警察希望能在 N 个人里面，
查出谁是杀手。
警察能够对每一个人进行查证，假如查证的对象是平民，他会告诉警察，他
认识的人， 谁是杀手， 谁是平民。 假如查证的对象是杀手， 杀手将会把警察干掉。
现在警察掌握了每一个人认识谁。
每一个人都有可能是杀手，可看作他们是杀手的概率是相同的。
问：根据最优的情况，保证警察自身安全并知道谁是杀手的概率最大是多
少？
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行有两个整数 N,M。
接下来有 M 行，每行两个整数 x,y，表示 x 认识 y（y 不一定认识 x,例如胡锦涛同志） 。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;仅包含一行一个实数，保留小数点后面 6 位，表示最大概率。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5 4&lt;br /&gt;
1 2&lt;br /&gt;
1 3&lt;br /&gt;
1 4&lt;br /&gt;
1 5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;0.800000&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;警察只需要查证 1。假如1是杀手，警察就会被杀。假如 1不是杀手，他会告诉警
察 2,3,4,5 谁是杀手。而 1 是杀手的概率是 0.2,所以能知道谁是杀手但没被杀的概
率是0.8。&lt;/p&gt;
&lt;p&gt;对于 100%的数据有 1≤N ≤100000,0≤M ≤300000
数据已加强！&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;Tarjan缩点
讨论一下入度出度就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;stack&amp;gt;
using namespace std;
struct edge
{
    int END, next;
} v[1000005], E[1000005];
int first[100005], Efirst[100005], p, Ep;
void add(int a, int c)
{
    v[p].END = c;
    v[p].next = first[a];
    first[a] = p++;
}
void add1(int a, int c)
{
    E[Ep].END = c;
    E[Ep].next = Efirst[a];
    Efirst[a] = Ep++;
}
int S[100005];
int low[100005], dfsn[100005], Index;
bool flag[100005];
int T;
int belong[100005];
stack&amp;lt;int&amp;gt; st;
void tarjan(int rt)
{
    low[rt] = dfsn[rt] = ++Index;
    st.push(rt);
    flag[rt] = 1;
    for (int i = first[rt]; i != -1; i = v[i].next)
    {
        if (!dfsn[v[i].END])
        {
            tarjan(v[i].END);
            low[rt] = min(low[rt], low[v[i].END]);
        }
        else if (flag[v[i].END])
            low[rt] = min(low[rt], dfsn[v[i].END]);
    }
    if (dfsn[rt] == low[rt])
    {
        T++;
        int v;
        do
        {
            v = st.top();
            st.pop();
            flag[v] = 0;
            belong[v] = T;
            S[T]++;
        } while (dfsn[v] != low[v]);
    }
}
int isnroot[100005], ithason[100005];
int main()
{
    memset(first, -1, sizeof(first));
    memset(Efirst, -1, sizeof(Efirst));
    //freopen(&quot;killer.in&quot;, &quot;r&quot;, stdin);
    //freopen(&quot;killer.out&quot;, &quot;w&quot;, stdout);
    int n, m;
    int s, e;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;s, &amp;amp;e);
        add(s, e);
    }
    for (int i = 1; i &amp;lt;= n; i++)
        if (!dfsn[i])
            tarjan(i);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        for (int j = first[i]; j != -1; j = v[j].next)
        {
            if (belong[i] != belong[v[j].END])
            {
                add1(belong[i], belong[v[j].END]);
                isnroot[belong[v[j].END]]++;
                ithason[belong[i]]++;
            }
        }
    }
    int ans = 0;
    bool flags = 0;
    for (int i = 1; i &amp;lt;= T; i++)
    {
        if (!isnroot[i])
        {
            ans++;
            if (flags)
                continue;
            //if (!ithason[i])
            //    flags = 1;
            if (S[i] == 1)
            {
                if (!ithason[i])
                    flags = 1;
                else
                {
                    bool e = 0;
                    for (int j = Efirst[i]; j != -1; j = E[j].next)
                    {
                        if (isnroot[E[j].END] == 1)
                            e = 1;
                    }
                    if (!e)
                        flags = 1;
                }
            }
        }
    }
    // if (!ans)
    //     ans = 1;
    if (flags)
        ans -= 1;
    printf(&quot;%.6lf&quot;, (double)(n - ans) / n);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>COGS 1752 [BOI2007] 摩基亚Mokia</title><link>https://www.nekomio.com/posts/41/</link><guid isPermaLink="true">https://www.nekomio.com/posts/41/</guid><pubDate>Wed, 26 Jul 2017 21:34:23 GMT</pubDate><content:encoded>&lt;h3&gt;【题目描述】&lt;/h3&gt;
&lt;p&gt;摩尔瓦多的移动电话公司摩基亚（Mokia）设计出了一种新的用户定位系统。和其他的定位系统一样，它能够迅速回答任何形如“用户C的位置在哪？”的问题，精确到毫米。但其真正高科技之处在于，它能够回答形如“给定区域内有多少名用户？”的问题。
&amp;lt;!--more--&amp;gt;
在定位系统中，世界被认为是一个W×W的正方形区域，由1×1的方格组成。每个方格都有一个坐标(x,y)，1&amp;lt;=x,y&amp;lt;=W。坐标的编号从1开始。对于一个4×4的正方形，就有1&amp;lt;=x&amp;lt;=4,1&amp;lt;=y&amp;lt;=4（如图）: &lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/6967203467051.png&quot; alt=&quot;6967203467051.png&quot; /&gt;
请帮助Mokia公司编写一个程序来计算在某个矩形区域内有多少名用户。&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;有三种命令，意义如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;命令&lt;/th&gt;
&lt;th&gt;参数&lt;/th&gt;
&lt;th&gt;意义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;W&lt;/td&gt;
&lt;td&gt;初始化一个全零矩阵。本命令仅开始时出现一次。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;x y A&lt;/td&gt;
&lt;td&gt;向方格(x,y)中添加A个用户。A是正整数。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;X1 Y1 X2 Y2&lt;/td&gt;
&lt;td&gt;查询X1&amp;lt;=x&amp;lt;=X2，Y1&amp;lt;=y&amp;lt;=Y2所规定的矩形中的用户数量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;无参数&lt;/td&gt;
&lt;td&gt;结束程序。本命令仅结束时出现一次。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;对所有命令2，输出一个一行整数，即当前询问矩形内的用户数量。&lt;/p&gt;
&lt;h3&gt;【输入样例】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;0 4&lt;br /&gt;
1 2 3 3&lt;br /&gt;
2 1 1 3 3&lt;br /&gt;
1 2 2 2&lt;br /&gt;
2 2 2 3 4&lt;br /&gt;
3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【输出样例】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;br /&gt;
5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【提示】&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;输入&lt;/th&gt;
&lt;th&gt;输出&lt;/th&gt;
&lt;th&gt;意义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0 4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;大小为4×4的全零正方形&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1 2 3 3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;向(2,3)方格加入3名用户&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 1 1 3 3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;查询矩形1&amp;lt;=x&amp;lt;=3,1&amp;lt;=y&amp;lt;=3内的用户数量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;查询结果&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1 2 2 2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;向(2,2)方格加入2名用户&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 2 2 3 4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;查询矩形2&amp;lt;=x&amp;lt;=3,2&amp;lt;=y&amp;lt;=4内的用户数量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;查询结果&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;终止程序&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;【数据规模】&lt;/p&gt;
&lt;p&gt;1&amp;lt;=W&amp;lt;=2000000&lt;br /&gt;
1&amp;lt;=X1&amp;lt;=X2&amp;lt;=W&lt;br /&gt;
1&amp;lt;=Y1&amp;lt;=Y2&amp;lt;=W&lt;br /&gt;
1&amp;lt;=x,y&amp;lt;=W&lt;br /&gt;
0&amp;lt;A&amp;lt;=10000&lt;br /&gt;
命令1不超过160000个。&lt;br /&gt;
命令2不超过10000个。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
#define MAXN 800010
#define MAXL 2000010
struct Query
{
    int x, y, val, pos, id, opt;
    bool operator&amp;lt;(const Query a) const
    {
        if (x == a.x &amp;amp;&amp;amp; y == a.y)
            return opt &amp;lt; a.opt;
        return x == a.x ? y &amp;lt; a.y : x &amp;lt; a.x;
    }
} Ask[MAXN], tmp[MAXN];
int n, m, Ans[MAXN];
class BIT
{
  public:
    int _tree[MAXL];
    BIT() { ; }
#define lowbit(_) ((_) &amp;amp; (-_))
    void Update(int i, int val)
    {
        for (; i &amp;lt;= n; i += lowbit(i))
            _tree[i] += val;
        return;
    }
    int Query(int i)
    {
        int _ans = 0;
        for (; i; i -= lowbit(i))
            _ans += _tree[i];
        return _ans;
    }
} bit;
void add()
{
    int x1, x2, y1, y2;
    scanf(&quot;%d%d%d%d&quot;, &amp;amp;x1, &amp;amp;y1, &amp;amp;x2, &amp;amp;y2);
    ++Ans[0];
    Ask[++m].pos = Ans[0], Ask[m].x = x1 - 1, Ask[m].y = y1 - 1, Ask[m].val = 1, Ask[m].opt = 1;
    Ask[++m].pos = Ans[0], Ask[m].x = x2, Ask[m].y = y2, Ask[m].val = 1, Ask[m].opt = 1;
    Ask[++m].pos = Ans[0], Ask[m].x = x1 - 1, Ask[m].y = y2, Ask[m].val = -1, Ask[m].opt = 1;
    Ask[++m].pos = Ans[0], Ask[m].x = x2, Ask[m].y = y1 - 1, Ask[m].val = -1, Ask[m].opt = 1;
    return;
}
void CDQ(int l, int r)
{
    if (l == r)
        return;
    int mid = l + r &amp;gt;&amp;gt; 1, l1 = l, l2 = mid + 1;
    for (int i = l; i &amp;lt;= r; i++)
    {
        if (Ask[i].id &amp;lt;= mid &amp;amp;&amp;amp; !Ask[i].opt)
            bit.Update(Ask[i].y, Ask[i].val);
        if (Ask[i].id &amp;gt; mid &amp;amp;&amp;amp; Ask[i].opt)
            Ans[Ask[i].pos] += Ask[i].val * bit.Query(Ask[i].y);
    }
    for (int i = l; i &amp;lt;= r; i++)
        if (Ask[i].id &amp;lt;= mid &amp;amp;&amp;amp; !Ask[i].opt)
            bit.Update(Ask[i].y, -Ask[i].val);
    for (int i = l; i &amp;lt;= r; i++)
    {
        if (Ask[i].id &amp;lt;= mid)
            tmp[l1++] = Ask[i];
        else
            tmp[l2++] = Ask[i];
    }
    for (int i = l; i &amp;lt;= r; i++)
        Ask[i] = tmp[i];
    CDQ(l, mid);
    CDQ(mid + 1, r);
    return;
}
int main()
{
    int c;
    freopen(&quot;mokia.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;mokia.out&quot;, &quot;w&quot;, stdout);
    scanf(&quot;%d%d&quot;, &amp;amp;c, &amp;amp;n);
    while (1)
    {
        int op;
        scanf(&quot;%d&quot;, &amp;amp;op);
        if (op == 1)
        {
            ++m;
            scanf(&quot;%d%d%d&quot;, &amp;amp;Ask[m].x, &amp;amp;Ask[m].y, &amp;amp;Ask[m].val);
        }
        else if (op == 2)
        {
            add();
        }
        else
            break;
    }
    for (int i = 1; i &amp;lt;= m; i++)
        Ask[i].id = i;
    sort(Ask + 1, Ask + m + 1);
    CDQ(1, m);
    for (int i = 1; i &amp;lt;= Ans[0]; i++)
        printf(&quot;%d\n&quot;, Ans[i]);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>COGS 2235 烤鸡翅</title><link>https://www.nekomio.com/posts/40/</link><guid isPermaLink="true">https://www.nekomio.com/posts/40/</guid><pubDate>Wed, 26 Jul 2017 21:13:59 GMT</pubDate><content:encoded>&lt;h3&gt;【题目描述】&lt;/h3&gt;
&lt;p&gt;在焦作太行路上，有一家烤鸡翅的生意火爆。因为好吃，所以卖的特别好。排队的人就特别多，经常有很多人买不到鸡翅。
鸡翅会在每分钟烤出Xi个，每分钟也只会卖给一个客人，第i个客人需要买Yi个。因为生意火爆，老板可以选择在这分钟不卖给这个客人鸡翅，或者卖给这个顾客他需要的鸡翅， 如果现在剩余的鸡翅不够，那就肯定不能卖给这个客人。无论这个客人能否买到鸡翅，他必须离开队伍。
现在给定N分钟，且已经知道每分钟烤出的鸡翅个数Xi，也知道每个客人需要鸡翅的Yi个数，现在老板想知道，如何合理安排卖给与拒绝，最多可以满足多少人
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;第一行一个正整数N，表示有N分钟的时间卖鸡翅
第二行N个用空格隔开的整数 X1，X2……Xn，Xi表示第i分钟会有Xi个鸡翅烤出
第三行N个用空格隔开的整数Y1，Y2……Yn，Yi表示第i分钟的顾客需要Yi个鸡翅&lt;/p&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;一个整数，表示最多可以满足买到鸡翅的人数。&lt;/p&gt;
&lt;h3&gt;【样例输入】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;6&lt;br /&gt;
2 2 1 2 1 0&lt;br /&gt;
1 2 2 3 4 4&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【样例输出】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【数据范围】&lt;/h3&gt;
&lt;p&gt;50%  数据保证 N&amp;lt;=1000
100%  1&amp;lt;=N&amp;lt;=250000   Xi,Yi都在[0,10^9]范围内&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;能卖就卖&lt;br /&gt;
卖不了了如何以前有人买的数目比他多&lt;br /&gt;
那就不卖给以前的那个人了也就是收回来&lt;br /&gt;
可后悔的贪心，长见识了。
主要使用优先队列&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;queue&amp;gt;
using namespace std;
int x[250005], y[250005];
class comp
{
  public:
    bool operator()(long long a, long long b)
    {
        return y[a] &amp;lt; y[b];
    }
};
priority_queue&amp;lt;long long, vector&amp;lt;long long&amp;gt;, comp&amp;gt; Q;
int main()
{
    freopen(&quot;wing.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;wing.out&quot;, &quot;w&quot;, stdout);
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++)
        scanf(&quot;%d&quot;, &amp;amp;x[i]);
    for (int i = 1; i &amp;lt;= n; i++)
        scanf(&quot;%d&quot;, &amp;amp;y[i]);
    long long sum = 0;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        sum += x[i];
        if (sum &amp;gt;= y[i])
            sum -= y[i], Q.push(i);
        else
        {
            if (!Q.empty())
            {
                if (y[Q.top()] &amp;gt; y[i])
                {
                    sum += y[Q.top()];
                    Q.pop();
                    sum -= y[i];
                    Q.push(i);
                }
            }
        }
    }
    printf(&quot;%d\n&quot;, Q.size());
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 3668 [NOI2014] 起床困难综合症</title><link>https://www.nekomio.com/posts/39/</link><guid isPermaLink="true">https://www.nekomio.com/posts/39/</guid><pubDate>Wed, 26 Jul 2017 21:03:23 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;21 世纪，许多人得了一种奇怪的病：起床困难综合症，其临床表现为：起床难，起床后精神不佳。作为一名青春阳光好少年，atm 一直坚持与起床困难综合症作斗争。通过研究相关文献，他找到了该病的发病原因：在深邃的太平洋海底中，出现了一条名为 drd 的巨龙，它掌握着睡眠之精髓，能随意延长大家的睡眠时间。正是由于 drd 的活动，起床困难综合症愈演愈烈，以惊人的速度在世界上传播。为了彻底消灭这种病，atm 决定前往海底，消灭这条恶龙。历经千辛万苦，atm 终于来到了 drd 所在的地方，准备与其展开艰苦卓绝的战斗。drd 有着十分特殊的技能，他的防御战线能够使用一定的运算来改变他受到的伤害。具体说来，drd 的防御战线由 n扇防御门组成。每扇防御门包括一个运算op和一个参数t，其中运算一定是OR,XOR,AND中的一种，参数则一定为非负整数。如果还未通过防御门时攻击力为x，则其通过这扇防御门后攻击力将变为x op t。最终drd 受到的伤害为对方初始攻击力x依次经过所有n扇防御门后转变得到的攻击力。由于atm水平有限，他的初始攻击力只能为0到m之间的一个整数（即他的初始攻击力只能在0,1,...,m中任选，但在通过防御门之后的攻击力不受 m的限制）。为了节省体力，他希望通过选择合适的初始攻击力使得他的攻击能让 drd 受到最大的伤害，请你帮他计算一下，他的一次攻击最多能使 drd 受到多少伤害。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第1行包含2个整数，依次为n,m，表示drd有n扇防御门，atm的初始攻击力为0到m之间的整数。接下来n行，依次表示每一扇防御门。每行包括一个字符串op和一个非负整数t，两者由一个空格隔开，且op在前，t在后，op表示该防御门所对应的操作， t表示对应的参数。n&amp;lt;=10^5&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;一行一个整数，表示atm的一次攻击最多使 drd 受到多少伤害。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3 10&lt;br /&gt;
AND 5&lt;br /&gt;
OR 6&lt;br /&gt;
XOR 7&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;h4&gt;【样例说明1】&lt;/h4&gt;
&lt;p&gt;atm可以选择的初始攻击力为0,1,...,10。&lt;/p&gt;
&lt;p&gt;假设初始攻击力为4，最终攻击力经过了如下计算&lt;/p&gt;
&lt;p&gt;4 AND 5 = 4&lt;/p&gt;
&lt;p&gt;4 OR 6 = 6&lt;/p&gt;
&lt;p&gt;6 XOR 7 = 1&lt;/p&gt;
&lt;p&gt;类似的，我们可以计算出初始攻击力为1,3,5,7,9时最终攻击力为0，初始攻击力为0,2,4,6,8,10时最终攻击力为1，因此atm的一次攻击最多使 drd 受到的伤害值为1。&lt;/p&gt;
&lt;p&gt;0&amp;lt;=m&amp;lt;=10^9&lt;/p&gt;
&lt;p&gt;0&amp;lt;=t&amp;lt;=10^9&lt;/p&gt;
&lt;p&gt;一定为OR,XOR,AND 中的一种&lt;/p&gt;
&lt;h4&gt;【运算解释】&lt;/h4&gt;
&lt;p&gt;在本题中，选手需要先将数字变换为二进制后再进行计算。如果操作的两个数二进制长度不同，则在前补0至相同长度。OR为按位或运算，处理两个长度相同的二进制数，两个相应的二进制位中只要有一个为1，则该位的结果值为1，否则为0。XOR为按位异或运算，对等长二进制模式或二进制数的每一位执行逻辑异或操作。如果两个相应的二进制位不同（相异），则该位的结果值为1，否则该位为0。 AND 为按位与运算，处理两个长度相同的二进制数，两个相应的二进制位都为1，该位的结果值才为1，否则为0。&lt;/p&gt;
&lt;p&gt;例如，我们将十进制数5与十进制数3分别进行OR，XOR 与 AND 运算，可以得到如下结果：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OR&lt;/th&gt;
&lt;th&gt;XOR&lt;/th&gt;
&lt;th&gt;AND&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0101 (十进制 5)&lt;/td&gt;
&lt;td&gt;0101 (十进制 5)&lt;/td&gt;
&lt;td&gt;0101 (十进制 5)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OR 0011 (十进制 3)&lt;/td&gt;
&lt;td&gt;XOR 0011 (十进制 3)&lt;/td&gt;
&lt;td&gt;AND 0011 (十进制 3)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;= 0111 (十进制 7)&lt;/td&gt;
&lt;td&gt;= 0110 (十进制 6)&lt;/td&gt;
&lt;td&gt;= 0001 (十进制 1)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;贪心的考虑每一位&lt;br /&gt;
如果这一位为0能使结果的这一位为1在这一位一定是0&lt;br /&gt;
如果为1的话在高位一定比在低位优&lt;br /&gt;
所以如果这一位不能为0而1可以的话能为1则为1
否则为0&lt;/p&gt;
&lt;p&gt;代码打的很傻&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
int a[100005], op[100005];
int er[31][100005];
int n, m;
void to_two(int c, int j)
{
    int i = 1;
    while (c)
    {
        er[i][j] = (c &amp;amp; 1);
        i++, c &amp;gt;&amp;gt;= 1;
    }
}
bool judge(int j, int c)
{
    int ans = c;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        if (op[i] == 1)
            ans &amp;amp;= er[j][i];
        else if (op[i] == 2)
            ans |= er[j][i];
        else if (op[i] == 3)
            ans ^= er[j][i];
    }
    return ans;
}
int main()
{
    //freopen(&quot;sleep.in&quot;,&quot;r&quot;,stdin);
    //freopen(&quot;sleep.out&quot;,&quot;w&quot;,stdout);
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    char c[10];
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%s&quot;, c);
        if (c[0] == &apos;A&apos;)
            op[i] = 1;
        else if (c[0] == &apos;O&apos;)
            op[i] = 2;
        else
            op[i] = 3;
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
        to_two(a[i], i);
    }
    int ans = 0;
    //printf(&quot;%d\n&quot;,ans);
    for (int i = 29; i &amp;gt; 0; i--)
    {
        if (judge(i, 0))
            ;
        else
        {
            if (judge(i, 1))
                if ((ans | (1 &amp;lt;&amp;lt; (i - 1))) &amp;lt;= m)
                    ans |= (1 &amp;lt;&amp;lt; (i - 1));
        }
        //printf(&quot;%d\n&quot;,ans);
    }
    //printf(&quot;%d\n&quot;,ans);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        if (op[i] == 1)
            ans &amp;amp;= a[i];
        else if (op[i] == 2)
            ans |= a[i];
        else if (op[i] == 3)
            ans ^= a[i];
    }
    printf(&quot;%d&quot;, ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>COGS 2421 简单的Treap</title><link>https://www.nekomio.com/posts/38/</link><guid isPermaLink="true">https://www.nekomio.com/posts/38/</guid><pubDate>Wed, 26 Jul 2017 20:53:01 GMT</pubDate><content:encoded>&lt;h3&gt;【题目描述】&lt;/h3&gt;
&lt;p&gt;Treap是一种平衡二叉搜索树，除二叉搜索树的基本性质外，Treap还满足一个性质：
每个节点都有一个确定的优先级，且每个节点的优先级都比它的两个儿子小(即它的优先级满足堆性质)。
不难证明在节点的优先级都事先给定且互不相同时，对应的Treap有且仅有一个。
现在，给定n个数和每个数对应的优先级，求出对应的以数的大小作为二叉搜索树比较依据的Treap的先序遍历结果。
对先序遍历的定义是：先访问根节点，再访问左子树，最后访问右子树。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;第一行一个数n表示数的个数。
第二行n个数表示每个数的大小。
第三行n个数表示每个数对应的优先级。&lt;/p&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;一行n个数，表示Treap的先序遍历结果(对于每个节点，输出对应的数)。&lt;/p&gt;
&lt;h3&gt;【样例输入】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;7&lt;br /&gt;
2 11 5 9 1 4 3&lt;br /&gt;
2 10 1 8 4 6 5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【样例输出】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5 2 1 3 4 9 11&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【样例解释】&lt;/h3&gt;
&lt;p&gt;对应的Treap如图所示，其中圈内的数是给出的数，圈外的数是节点的优先级。
&lt;img src=&quot;http://ostb19hxn.bkt.clouddn.com/17-7-26/92869378.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;【数据范围】&lt;/h3&gt;
&lt;p&gt;n&amp;lt;=500000。
所有的数和优先级都互不相同且在int(C++)/longint(Pascal)范围内。&lt;/p&gt;
&lt;h3&gt;【提示】&lt;/h3&gt;
&lt;p&gt;为了给不想用栈模拟递归的孩纸们偷懒的机会，C++选手请在main函数的开头加入以下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int __size__=128&amp;lt;&amp;lt;20;
char *__p__=(char*)malloc(__size__)+__size__;
__asm__(&quot;movl %0, %%esp\n&quot;::&quot;r&quot;(__p__));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意上述代码会占用你128MB的空间，请自行调整代码。&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;其实就是排序后用&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E7%AC%9B%E5%8D%A1%E5%B0%94%E6%A0%91&quot;&gt;笛卡尔树&lt;/a&gt;建一颗树&lt;/p&gt;
&lt;p&gt;所以这道题是一道笛卡尔树的裸题&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
class data
{
  public:
    int v, key;
    bool operator&amp;lt;(const data &amp;amp;a) const
    {
        return v &amp;lt; a.v;
    }
} a[500005];
class Node
{
  public:
    Node *ch[2];
    int key, v;
    Node(data x)
    {
        key = x.key;
        v = x.v;
        ch[0] = ch[1] = NULL;
    }
    ~Node();
} * st[500005];
Node *build(int m)
{
    Node *x, *last;
    int p = 0;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        x = new Node(a[i]);
        last = NULL;
        while (p &amp;amp;&amp;amp; st[p]-&amp;gt;key &amp;gt; x-&amp;gt;key)
        {
            last = st[p];
            st[p--] = NULL;
        }
        if (p)
            st[p]-&amp;gt;ch[1] = x;
        x-&amp;gt;ch[0] = last;
        st[++p] = x;
    }
    return st[1];
}
void dfs(Node *a)
{
    if (a)
    {
        printf(&quot;%d &quot;, a-&amp;gt;v);
        dfs(a-&amp;gt;ch[0]);
        dfs(a-&amp;gt;ch[1]);
    }
}
int main()
{
    int __size__ = 128 &amp;lt;&amp;lt; 20;
    char *__p__ = (char *)malloc(__size__) + __size__;
    __asm__(&quot;movl %0, %%esp\n&quot; ::&quot;r&quot;(__p__));
    freopen(&quot;treap.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;treap.out&quot;,&quot;w&quot;,stdout);
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++)
        scanf(&quot;%d&quot;, &amp;amp;a[i].v);
    for (int i = 1; i &amp;lt;= n; i++)
        scanf(&quot;%d&quot;, &amp;amp;a[i].key);
    sort(a + 1, a + n + 1);
    Node *rt = build(n);
    dfs(rt);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 2818 GCD</title><link>https://www.nekomio.com/posts/37/</link><guid isPermaLink="true">https://www.nekomio.com/posts/37/</guid><pubDate>Wed, 26 Jul 2017 20:21:12 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;给定整数N，求1&amp;lt;=x,y&amp;lt;=N且Gcd(x,y)为素数的
数对(x,y)有多少对.&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;一个整数N&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;如题
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;4&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;4&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;$$ \sum_{d}{\sum_{i=1}^{n}{\sum_{j=1}^{n}[gcd(i,j)=d]}} $$&lt;/p&gt;
&lt;p&gt;$$ = \sum_{d}{\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}{\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}{[gcd(i,j)=1]}}} $$&lt;/p&gt;
&lt;p&gt;$$ = \sum_{T}{\lfloor\frac{n}{T}\rfloor \lfloor\frac{n}{T}\rfloor\sum_{d|T}{\mu(\frac{n}{T})}} $$&lt;br /&gt;
令 $f[i]=\sum_{d|T}^{} \mu(\frac{T}{d})$&lt;/p&gt;
&lt;p&gt;然后线性筛&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
const int N = 10000000;
int mu[N + 5], prime[N + 5], g[N + 5];
long long sum[N + 5], cnt;
bool isnprime[N + 5];
void get_g()
{
    mu[1] = 1;
    for (int i = 2; i &amp;lt;= N; i++)
    {
        if (!isnprime[i])
        {
            prime[++cnt] = i;
            mu[i] = -1;
            g[i] = 1;
        }
        for (int j = 1; j &amp;lt;= cnt &amp;amp;&amp;amp; i * prime[j] &amp;lt;= N; j++)
        {
            isnprime[i * prime[j]] = 1;
            if (i % prime[j])
                mu[i * prime[j]] = -mu[i], g[i * prime[j]] = mu[i] - g[i];
            else
            {
                mu[i * prime[j]] = 0;
                g[i * prime[j]] = mu[i];
                break;
            }
        }
    }
    for (int i = 1; i &amp;lt;= N; i++)
    {
        sum[i] = sum[i - 1] + g[i];
    }
}
int main()
{
    get_g();
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    long long ans = 0, last;
    for (int i = 1; i &amp;lt;= n; i = last + 1)
    {
        last = n / (n / i);
        ans += (long long)(sum[last] - sum[i - 1]) * (n / i) * (n / i);
    }
    printf(&quot;%lld\n&quot;, ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 1500 [NOI2005] 维护数列 </title><link>https://www.nekomio.com/posts/36/</link><guid isPermaLink="true">https://www.nekomio.com/posts/36/</guid><pubDate>Sat, 15 Jul 2017 15:56:21 GMT</pubDate><content:encoded>&lt;h3&gt;【问题描述】&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/564239476b322.gif&quot; alt=&quot;564239476b322.gif&quot; /&gt;
题目链接
&lt;a href=&quot;http://www.lydsy.com/JudgeOnline/problem.php?id=1500&quot;&gt;BZOJ&lt;/a&gt; &lt;a href=&quot;http://cogs.pro/cogs/problem/problem.php?pid=339&quot;&gt;COGS&lt;/a&gt;
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;输入文件的第 1 行包含两个数 N 和 M，N 表示初始时数列中数的个数，M表示要进行的操作数目。第 2 行包含 N 个数字，描述初始时的数列。以下 M 行，每行一条命令，格式参见问题描述中的表格。&lt;/p&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;对于输入数据中的 GET-SUM 和 MAX-SUM 操作，向输出文件依次打印结果，每个答案（数字）占一行。&lt;/p&gt;
&lt;h3&gt;【输入样例】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;9 8&lt;br /&gt;
2 -6 3 5 1 -5 -3 6 3&lt;br /&gt;
GET-SUM 5 4&lt;br /&gt;
MAX-SUM&lt;br /&gt;
INSERT 8 3 -5 7 2&lt;br /&gt;
DELETE 12 1&lt;br /&gt;
MAKE-SAME 3 3 2&lt;br /&gt;
REVERSE 3 6&lt;br /&gt;
GET-SUM 5 4&lt;br /&gt;
MAX-SUM&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【输出样例】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;-1&lt;br /&gt;
10&lt;br /&gt;
1&lt;br /&gt;
10&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【样例说明】&lt;/h3&gt;
&lt;p&gt;初始时，我们拥有数列 2 -6 3 5 1 -5 -3 6 3
执行操作 GET-SUM 5 4，表示求出数列中从第 5 个数开始连续 4 个数字之和，1+(-5)+(-3)+6 = -1：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2     -6     3      5      1     -5    -3     6      3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;执行操作 MAX-SUM，表示要求求出当前数列中最大的一段和，应为 3+5+1+(-5)+(-3)+6+3 = 10：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2     -6     3      5      1     -5    -3     6      3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;执行操作 INSERT 8 3 -5 7 2，即在数列中第 8 个数字后插入-5 7 2，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2     -6     3      5      1     -5    -3     6     -5     7      2      3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;执行操作 DELETE 12 1，表示删除第 12 个数字，即最后一个：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2     -6     3      5      1     -5    -3     6     -5     7      2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;执行操作 MAKE-SAME 3 3 2，表示从第 3 个数开始的 3 个数字，统一修改为 2：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2	-6	3	5	1	-5	-3	6	-5	7	2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;改为&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2	-6	2	2	2	-5	-3	6	-5	7	2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;执行操作 REVERSE 3 6，表示取出数列中从第 3 个数开始的连续 6 个数：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2 -6 2 2 2 -5 -3 6 -5 7 2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如上所示的灰色部分 2 2 2 -5 -3 6，翻转后得到 6 -3 -5 2 2 2，并放回原来位置：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2 -6 6 -3 -5 2  2  2 -5 7  2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最后执行 GET-SUM 5 4 和 MAX-SUM，不难得到答案 1 和 10。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2 -6 6 -3 -5 2 2 2 -5 7 2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;BZOJ 版
&lt;img src=&quot;http://ostb19hxn.bkt.clouddn.com/17-7-15/22527878.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;本题要求维护 &lt;em&gt;动态连续最大连续和&lt;/em&gt; 和 &lt;em&gt;区间和&lt;/em&gt;&lt;br /&gt;
所以要用 Max，和 Sum 来记录&lt;br /&gt;
类似线段树我们需要Pushdown和Pushup函数&lt;br /&gt;
此外对于Max 为了更新他的值，我们还需要维护两个变量
l，r 分别记录前缀最大和&amp;amp;后缀最大和&lt;/p&gt;
&lt;hr /&gt;
&lt;h5&gt;向上传递的&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;对于一个节点更新Max时要分一下几种情况讨论&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;它的左儿子的Max&lt;/li&gt;
&lt;li&gt;它的右儿子的Max&lt;/li&gt;
&lt;li&gt;它的左儿子的r加上本节点的权值v&lt;/li&gt;
&lt;li&gt;它的右儿子的l加上本节点的权值v&lt;/li&gt;
&lt;li&gt;它的左儿子的r加上本节点的权值v加上右儿子的l&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;用一张图来表示是这样的&lt;img src=&quot;http://ostb19hxn.bkt.clouddn.com/17-7-15/11752870.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;我们还需要维护一个节点的 l  与上面相似 要分三种情况&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;它的左儿子的 l&lt;/li&gt;
&lt;li&gt;它的左儿子的 sum 加上 本节点的权值v&lt;/li&gt;
&lt;li&gt;它的左节点的 sum 加上 本节点的权值v 加上 他的右儿子的 l&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;用另一张张图来表示是这样的&lt;img src=&quot;http://ostb19hxn.bkt.clouddn.com/17-7-15/95774098.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;r与上面的相似&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;它的右儿子的 r&lt;/li&gt;
&lt;li&gt;它的右儿子的 sum 加上 本节点的权值v&lt;/li&gt;
&lt;li&gt;它的右节点的 sum 加上 本节点的权值v 加上 他的左儿子的 r&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;不想画图了╭(╯^╰)╮&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后是Sum 直接加起来就好了&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;向下传递的&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;首先是旋转标记&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;直接下传然后交换左右儿子即可&lt;/li&gt;
&lt;li&gt;注意异或的用法&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后是修改标记&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;首先你不能暴力修改 有一个点会超时，亲测&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;所以想线段树一样我们需要一个标记&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;下传时注意维护Max，sum，l，r 这些值&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对于Sum 直接乘就好&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;对于Max,l,r 要分类讨论&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;如果改变的值为负数那这三个的值都未你改变成的值&lt;/li&gt;
&lt;li&gt;否则这等于Sum&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于插入&lt;br /&gt;
直接新建一颗树插进去就可以了&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;最后一步 码代码 调程序&lt;/h4&gt;
&lt;p&gt;能Pushdown() 就Pushdown()&lt;br /&gt;
能Pushup() 就Pushup()&lt;/p&gt;
&lt;p&gt;fhq Treap 真好&lt;br /&gt;
如果打Splay 我会死的&lt;/p&gt;
&lt;p&gt;另外需要注意如果子树为空的返回值&lt;/p&gt;
&lt;h4&gt;链接们&lt;/h4&gt;
&lt;p&gt;fhq大佬 &lt;a href=&quot;http://fanhq666.blog.163.com/blog/static/819434262011021105212299/&quot;&gt;挖掘Treap的潜力 - fanhq666的日志&lt;/a&gt;&lt;br /&gt;
我的板子来源
&lt;a href=&quot;http://memphis.is-programmer.com/posts/46317.html&quot;&gt;非旋转Treap及可持久化[Merge,Split]  Memphis&apos;s Blog&lt;/a&gt;&lt;br /&gt;
附朋友的题解
&lt;a href=&quot;http://www.cnblogs.com/LadyLex/p/7182631.html&quot;&gt;[您有新的未分配科技点] 无旋treap：从单点到区间（例题 BZOJ1500&amp;amp;NOI2005 维护数列 ）&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.cnblogs.com/LadyLex/p/7182491.html&quot;&gt;[您有新的未分配科技点]无旋treap：从好奇到入门（例题：bzoj3224 普通平衡树）&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;C++ Code&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-07-15 10:32:15 
 * @Last Modified by:   WildRage 
 * @Last Modified time: 2017-07-15 15:07:46 
 */
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#define INF 0x3f3f3f3f
using namespace std;
struct Node
{
    int v, key, size, rev;
    int Max, l, r, sum, change;
    Node *ch[2];
    Node(int x)
    {
        v = x;
        key = rand();
        size = 1;
        rev = 0;
        change = -INF;
        Max = x;
        l = x;
        r = x;
        sum = x;
        ch[0] = ch[1] = NULL;
    }
#define size(_) ((_) ? (_)-&amp;gt;size : (0))
#define sum(_) ((_) ? (_)-&amp;gt;sum : (0))
#define l(_) ((_) ? (_)-&amp;gt;l : (-INF))
#define r(_) ((_) ? (_)-&amp;gt;r : (-INF))
#define Max(_) ((_) ? (_)-&amp;gt;Max : (-INF))
#define change(_) ((_) ? (_)-&amp;gt;change : (-INF))
    void Pushup()
    {
        size = 1 + size(ch[1]) + size(ch[0]);
        l = max(l(ch[0]), max(sum(ch[0]) + v, sum(ch[0]) + v + l(ch[1])));
        r = max(r(ch[1]), max(sum(ch[1]) + v, sum(ch[1]) + v + r(ch[0])));
        Max = max(Max(ch[0]), max(Max(ch[1]), max(r(ch[0]) + v, max(l(ch[1]) + v, max(r(ch[0]) + l(ch[1]) + v, v)))));
        sum = sum(ch[0]) + sum(ch[1]) + v;
    }
    void reverse()
    {
        if (!this)
            return;
        swap(ch[0], ch[1]);
        swap(l, r);
        rev ^= 1;
    }
    void Update()
    {
        if (!this)
            return;
        if (ch[1])
            ch[1]-&amp;gt;change = change;
        if (ch[0])
            ch[0]-&amp;gt;change = change;
        sum = size * change;
        v=change;
        l=r=Max=max(change,size*change);
        //change = -INF;
    }
    void Pushdown()
    {
        if (!this)
            return;
        if (rev)
        {
            ch[0]-&amp;gt;reverse();
            ch[1]-&amp;gt;reverse();
            rev = 0;
        }
        if (change != -INF)
        {
            ch[0]-&amp;gt;Update();
            ch[1]-&amp;gt;Update();
            change=-INF;
        }
    }
} * root;
typedef pair&amp;lt;Node *, Node *&amp;gt; DNode;
Node *Merge(Node *A, Node *B)
{
    if (!A)
        return B;
    if (!B)
        return A;
    if (A-&amp;gt;key &amp;lt; B-&amp;gt;key)
    {
        A-&amp;gt;Pushdown();
        A-&amp;gt;ch[1] = Merge(A-&amp;gt;ch[1], B);
        A-&amp;gt;Pushup();
        return A;
    }
    else
    {
        B-&amp;gt;Pushdown();
        B-&amp;gt;ch[0] = Merge(A, B-&amp;gt;ch[0]);
        B-&amp;gt;Pushup();
        return B;
    }
}
DNode Split(Node *rt, int k)
{
    if (!rt)
        return DNode(NULL, NULL);
    DNode o;
    rt-&amp;gt;Pushdown();
    if (size(rt-&amp;gt;ch[0]) &amp;gt;= k)
    {
        o = Split(rt-&amp;gt;ch[0], k);
        rt-&amp;gt;ch[0] = o.second;
        rt-&amp;gt;Pushup();
        o.second = rt;
    }
    else
    {
        o = Split(rt-&amp;gt;ch[1], k - size(rt-&amp;gt;ch[0]) - 1);
        rt-&amp;gt;ch[1] = o.first;
        rt-&amp;gt;Pushup();
        o.first = rt;
    }
    return o;
}
Node *st[4000005];
Node *build(int m)
{
    //memset(st, 0, sizeof(st));
    Node *x, *last;
    int p = 0;
    int a;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;a);
        x = new Node(a);
        last = NULL;
        while (p &amp;amp;&amp;amp; st[p]-&amp;gt;key &amp;gt; x-&amp;gt;key)
        {
            st[p]-&amp;gt;Pushup();
            last = st[p];
            st[p--] = NULL;
        }
        if (p)
            st[p]-&amp;gt;ch[1] = x;
        x-&amp;gt;ch[0] = last;
        st[++p] = x;
    }
    while (p)
        st[p--]-&amp;gt;Pushup();
    return st[1];
}
Node *kth(int k)
{
    DNode x = Split(root, k - 1);
    DNode y = Split(x.second, 1);
    Node *ans = y.first;
    root = Merge(Merge(x.first, ans), y.second);
    return ans;
}
int Rank(Node *rt, int x)
{
    if (!rt)
        return 0;
    return x &amp;lt;= rt-&amp;gt;v ? Rank(rt-&amp;gt;ch[0], x) : Rank(rt-&amp;gt;ch[1], x) + size(rt-&amp;gt;ch[0]) + 1;
}
void Insert(int x)
{
    int k = Rank(root, x);
    DNode y = Split(root, k);
    Node *n = new Node(x);
    root = Merge(Merge(y.first, n), y.second);
}
void remove(int x)
{
    int k = Rank(root, x);
    DNode a = Split(root, k);
    DNode b = Split(a.second, 1);
    root = Merge(a.first, b.second);
}
void flip(int i, int m)
{
    DNode x = Split(root, i - 1);
    DNode y = Split(x.second, m);
    y.first-&amp;gt;reverse();
    root = Merge(x.first, Merge(y.first, y.second));
}
void dfs(Node *rt)
{
    if (rt)
    {
        rt-&amp;gt;Pushdown();
        dfs(rt-&amp;gt;ch[0]);
        printf(&quot;%d &quot;, rt-&amp;gt;v);
        dfs(rt-&amp;gt;ch[1]);
    }
}
void Insert(int i, int tot)
{
    Node *x = build(tot);
    DNode y = Split(root, i);
    root = Merge(y.first, Merge(x, y.second));
}
void rmdfs(Node *rt)
{
    if (rt)
    {
        rmdfs(rt-&amp;gt;ch[0]);
        rmdfs(rt-&amp;gt;ch[1]);
    }
    delete rt;
}
void remove(int i, int tot)
{
    DNode x = Split(root, i - 1);
    DNode y = Split(x.second, tot);
    rmdfs(y.first);
    root = Merge(x.first, y.second);
}
void Update(int i, int tot, int c)
{
    DNode x = Split(root, i - 1);
    DNode y = Split(x.second, tot);
    y.first-&amp;gt;change = c;
    y.first-&amp;gt;Update();
    //Node *m = build(tot, c);
    //rmdfs(y.first);
    root = Merge(x.first, Merge(y.first, y.second));
}
int get_sum(int i, int tot)
{
    DNode x = Split(root, i - 1);
    DNode y = Split(x.second, tot);
    int ans = sum(y.first);
    root = Merge(x.first, Merge(y.first, y.second));
    return ans;
}
int Max_Sum()
{
    return Max(root);
}
int main()
{
    //freopen(&quot;seq2005.in&quot;, &quot;r&quot;, stdin);
    //freopen(&quot;seq2005.out&quot;, &quot;w&quot;, stdout);
    int n, m;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    root = build(n);
    //dfs(root);
    //printf(&quot;----------------------\n&quot;);
    int l, r, c;
    char s[16];
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%s&quot;, s);
        switch (s[0])
        {
        case &apos;G&apos;:
            scanf(&quot;%d%d&quot;, &amp;amp;l, &amp;amp;r);
            printf(&quot;%d\n&quot;, get_sum(l, r));
            break;
        case &apos;D&apos;:
            scanf(&quot;%d%d&quot;, &amp;amp;l, &amp;amp;r);
            remove(l, r);
            break;
        case &apos;I&apos;:
            scanf(&quot;%d%d&quot;, &amp;amp;l, &amp;amp;r);
            Insert(l, r);
            break;
        case &apos;R&apos;:
            scanf(&quot;%d%d&quot;, &amp;amp;l, &amp;amp;r);
            flip(l, r);
            break;
        case &apos;M&apos;:
            if (s[2] == &apos;K&apos;)
            {
                scanf(&quot;%d%d%d&quot;, &amp;amp;l, &amp;amp;r, &amp;amp;c);
                Update(l, r, c);
            }
            else
            {
                printf(&quot;%d\n&quot;, Max_Sum());
            }
        }
        //printf(&quot;--------------------------------\n&quot;);
        //dfs(root);
        //printf(&quot;\n-----------DONE-----------------\n&quot;);
    }
    //while (1)
    ;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 1875 [SDOI2009]HH去散步 矩阵乘</title><link>https://www.nekomio.com/posts/35/</link><guid isPermaLink="true">https://www.nekomio.com/posts/35/</guid><pubDate>Thu, 13 Jul 2017 18:00:56 GMT</pubDate><content:encoded>&lt;h1&gt;Made by WZZ&lt;/h1&gt;
&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;HH有个一成不变的习惯，喜欢饭后百步走。所谓百步走，就是散步，就是在一定的时间 内，走过一定的距离。 但
是同时HH又是个喜欢变化的人，所以他不会立刻沿着刚刚走来的路走回。 又因为HH是个喜欢变化的人，所以他每
天走过的路径都不完全一样，他想知道他究竟有多 少种散步的方法。 现在给你学校的地图（假设每条路的长度都
是一样的都是1），问长度为t，从给定地 点A走到给定地点B共有多少条符合条件的路径
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行：五个整数N，M，t，A，B。&lt;br /&gt;
N表示学校里的路口的个数&lt;br /&gt;
M表示学校里的 路的条数&lt;br /&gt;
t表示HH想要散步的距离&lt;br /&gt;
A表示散步的出发点&lt;br /&gt;
B则表示散步的终点。&lt;br /&gt;
接下来M行&lt;br /&gt;
每行一组Ai，Bi，表示从路口Ai到路口Bi有一条路。&lt;br /&gt;
数据保证Ai ！= Bi,但不保证任意两个路口之间至多只有一条路相连接。&lt;br /&gt;
路口编号从0到N -1。&lt;br /&gt;
同一行内所有数据均由一个空格隔开，行首行尾没有多余空格。没有多余空行。&lt;br /&gt;
答案模45989。&lt;br /&gt;
N ≤ 20，M ≤ 60，t ≤ 2^30，0 ≤ A,B&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;一行，表示答案。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;4 5 3 0 0&lt;br /&gt;
0 1&lt;br /&gt;
0 2&lt;br /&gt;
0 3&lt;br /&gt;
2 1&lt;br /&gt;
3 2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;4&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这道题是一道矩阵乘的题&lt;br /&gt;
通常我们用矩阵乘表示 点a 到 点b&lt;br /&gt;
$$
\begin{matrix}
1 &amp;amp; 2 &amp;amp; 3 &amp;amp; 4 &amp;amp; ..... &amp;amp; N-1 &amp;amp; N \
\end{matrix}
$$
1 2 3 4 .....N-1 N
1-1 1-2 .... N-1&lt;br /&gt;
2-1 2-2 .... N-2&lt;br /&gt;
3-1 3-2 .... N-3&lt;br /&gt;
... ... .... ...&lt;br /&gt;
N-1 N-2 .... N-N&lt;/p&gt;
&lt;p&gt;乘之后便为到 i点的方案数&lt;br /&gt;
但这道题有不能重复走边的限制&lt;br /&gt;
我们便巧妙地用矩阵储存边&lt;br /&gt;
边 i 能到达 边 j的条件为 edge[i].to==edge[j].from(即相连)&lt;br /&gt;
但 i不能到达i+1条边（i为偶数） 所以a[i][i+1]=0;&lt;br /&gt;
再循环找满足条件即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#define mod 45989
using namespace std;

int n, m, t, size, head[25], began, endd, x, y;
int a[160][160], ans[160][160], tot;
struct node
{
    int from, to, next;
} edge[400];
void add(int from, int to)
{
    edge[++size].from = from;
    edge[size].to = to;
    edge[size].next = head[from];
    head[from] = size;
}

void cheng(int a[160][160], int b[160][160], int to[160][160])
{
    int tmp[160][160] = {0};
    for (int i = 1; i &amp;lt;= size; i++)
        for (int j = 1; j &amp;lt;= size; j++)
            for (int u = 1; u &amp;lt;= size; u++)
                tmp[i][j] = (tmp[i][j] + a[i][u] * b[u][j] % mod) % mod;
    for (int i = 1; i &amp;lt;= size; i++)
        for (int j = 1; j &amp;lt;= size; j++)
            to[i][j] = tmp[i][j];
}

void dp()
{
    while (t)
    {
        if (t &amp;amp; 1)
            cheng(a, ans, ans);
        t = t &amp;gt;&amp;gt; 1;
        cheng(a, a, a);
    }
    for (int i = 1; i &amp;lt;= size; i++)
        if (edge[i].to == endd)
            for (int j = 1; j &amp;lt;= size; j++)
                if (edge[j].from == began)
                    tot = (tot + ans[j][i]) % mod;
}

int main()
{
    scanf(&quot;%d%d%d%d%d&quot;, &amp;amp;n, &amp;amp;m, &amp;amp;t, &amp;amp;began, &amp;amp;endd);
    began++, endd++;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;x, &amp;amp;y);
        x++, y++;
        add(x, y);
        add(y, x);
    }
    for (int i = 1; i &amp;lt;= size; i++)
        for (int j = 1; j &amp;lt;= size; j++)
            if (edge[i].to == edge[j].from)
                a[i][j] = 1;

    for (int i = 1; i &amp;lt;= size; i += 2)
        a[i][i + 1] = a[i + 1][i] = 0;

    for (int i = 1; i &amp;lt;= size; i++)
        ans[i][i] = 1;
    t--;
    dp();
    printf(&quot;%d&quot;, tot);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 3038 上帝造题的七分钟2 线段树</title><link>https://www.nekomio.com/posts/34/</link><guid isPermaLink="true">https://www.nekomio.com/posts/34/</guid><pubDate>Thu, 13 Jul 2017 17:31:56 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;XLk觉得《上帝造题的七分钟》不太过瘾，于是有了第二部。
&quot;第一分钟，X说，要有数列，于是便给定了一个正整数数列。
第二分钟，L说，要能修改，于是便有了对一段数中每个数都开平方(下取整)的操作。
第三分钟，k说，要能查询，于是便有了求一段数的和的操作。
第四分钟，彩虹喵说，要是noip难度，于是便有了数据范围。
第五分钟，诗人说，要有韵律，于是便有了时间限制和内存限制。
第六分钟，和雪说，要省点事，于是便有了保证运算过程中及最终结果均不超过64位有符号整数类型的表示范围的限制。
第七分钟，这道题终于造完了，然而，造题的神牛们再也不想写这道题的程序了。&quot;
——《上帝造题的七分钟·第二部》
所以这个神圣的任务就交给你了。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行一个整数n，代表数列中数的个数。
第二行n个正整数，表示初始状态下数列中的数。
第三行一个整数m，表示有m次操作。
接下来m行每行三个整数k,l,r，k=0表示给[l,r]中的每个数开平方(下取整)，k=1表示询问[l,r]中各个数的和。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;对于询问操作，每行输出一个回答。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;10&lt;br /&gt;
1 2 3 4 5 6 7 8 9 10&lt;br /&gt;
5&lt;br /&gt;
0 1 10&lt;br /&gt;
1 1 10&lt;br /&gt;
1 1 5&lt;br /&gt;
0 5 8&lt;br /&gt;
1 4 8&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;19&lt;br /&gt;
7&lt;br /&gt;
6&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;HINT&lt;/h3&gt;
&lt;p&gt;1：对于100%的数据，1&amp;lt;=n&amp;lt;=100000，1&amp;lt;=l&amp;lt;=r&amp;lt;=n，数列中的数大于0，且不超过1e12。
2：数据不保证L&amp;lt;=R 若L&amp;gt;R，请自行交换L,R，谢谢！&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;线段树 去修改就可以了&lt;br /&gt;
区间为1后就不用改了&lt;br /&gt;
很暴力的&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
using namespace std;
#define LL long long
#define lch l, m, rt &amp;lt;&amp;lt; 1
#define rch m + 1, r, rt &amp;lt;&amp;lt; 1 | 1

const int N = 100005;
LL Min[N &amp;lt;&amp;lt; 2], Max[N &amp;lt;&amp;lt; 2], Sum[N &amp;lt;&amp;lt; 2];
int Sqr[N &amp;lt;&amp;lt; 2];
void Pushup(int rt)
{
    Min[rt] = min(Min[rt &amp;lt;&amp;lt; 1], Min[rt &amp;lt;&amp;lt; 1 | 1]);
    Max[rt] = max(Max[rt &amp;lt;&amp;lt; 1], Max[rt &amp;lt;&amp;lt; 1 | 1]);
    if (Sum[rt &amp;lt;&amp;lt; 1] != -1 &amp;amp;&amp;amp; Sum[rt &amp;lt;&amp;lt; 1 | 1] != -1)
        Sum[rt] = Sum[rt &amp;lt;&amp;lt; 1] + Sum[rt &amp;lt;&amp;lt; 1 | 1];
    else
        Sum[rt] = -1;
}
void Pushdown(int rt, int s)
{
    if (Sqr[rt])
    {
        Sqr[rt &amp;lt;&amp;lt; 1] += Sqr[rt];
        Sqr[rt &amp;lt;&amp;lt; 1 | 1] += Sqr[rt];
        Sum[rt &amp;lt;&amp;lt; 1] = Sum[rt &amp;lt;&amp;lt; 1 | 1] = -1;
        if (Max[rt &amp;lt;&amp;lt; 1] &amp;gt; 1)
            for (int i = 1; i &amp;lt;= Sqr[rt]; i++)
            {
                Max[rt &amp;lt;&amp;lt; 1] = sqrt(Max[rt &amp;lt;&amp;lt; 1]);
                Min[rt &amp;lt;&amp;lt; 1] = sqrt(Min[rt &amp;lt;&amp;lt; 1]);
                if (Max[rt &amp;lt;&amp;lt; 1] == 1)
                    break;
            }
        if (Max[rt &amp;lt;&amp;lt; 1 | 1] &amp;gt; 1)
            for (int i = 1; i &amp;lt;= Sqr[rt]; i++)
            {
                Max[rt &amp;lt;&amp;lt; 1 | 1] = sqrt(Max[rt &amp;lt;&amp;lt; 1 | 1]);
                Min[rt &amp;lt;&amp;lt; 1 | 1] = sqrt(Min[rt &amp;lt;&amp;lt; 1 | 1]);
                if (Max[rt &amp;lt;&amp;lt; 1 | 1] == 1)
                    break;
            }
        if (Max[rt &amp;lt;&amp;lt; 1 | 1] == Min[rt &amp;lt;&amp;lt; 1 | 1])
            Sum[rt &amp;lt;&amp;lt; 1 | 1] = Max[rt &amp;lt;&amp;lt; 1 | 1] * (s &amp;gt;&amp;gt; 1);
        if (Max[rt &amp;lt;&amp;lt; 1] == Min[rt &amp;lt;&amp;lt; 1])
            Sum[rt &amp;lt;&amp;lt; 1] = Max[rt &amp;lt;&amp;lt; 1] * (s - (s &amp;gt;&amp;gt; 1));
        Sqr[rt] = 0;
    }
}
void buildtree(int l, int r, int rt)
{
    if (l == r)
    {
        scanf(&quot;%lld&quot;, &amp;amp;Min[rt]);
        Sum[rt] = Max[rt] = Min[rt];
        return;
    }
    int m = l + r &amp;gt;&amp;gt; 1;
    buildtree(lch);
    buildtree(rch);
    Pushup(rt);
}
void Update(int L, int R, int l, int r, int rt)
{
    if (L &amp;lt;= l &amp;amp;&amp;amp; R &amp;gt;= r)
    {
        Sqr[rt] += 1;
        Max[rt] = sqrt(Max[rt]), Min[rt] = sqrt(Min[rt]);
        Sum[rt] = -1;
        if (Max[rt] == Min[rt])
            Sum[rt] = Max[rt] * (r - l + 1);
        return;
    }
    Sum[rt] = -1;
    Pushdown(rt, r - l + 1);
    int m = l + r &amp;gt;&amp;gt; 1;
    if (L &amp;lt;= m)
        Update(L, R, lch);
    if (R &amp;gt; m)
        Update(L, R, rch);
    Pushup(rt);
}
LL Query(int L, int R, int l, int r, int rt)
{
    if (L &amp;lt;= l &amp;amp;&amp;amp; R &amp;gt;= r)
    {
        if (Max[rt] == Min[rt])
        {
            return Sum[rt] = Max[rt] * (r - l + 1);
        }
        if (Sum[rt] != -1)
            return Sum[rt];
    }
    Pushdown(rt, r - l + 1);
    LL ans = 0;
    int m = l + r &amp;gt;&amp;gt; 1;
    if (L &amp;lt;= m)
        ans += Query(L, R, lch);
    if (R &amp;gt; m)
        ans += Query(L, R, rch);
    return ans;
    Pushup(rt);
}
void print(int l, int r, int rt)
{
    printf(&quot;l=%d,r=%d,rt=%d,Sum[rt]=%lld\n&quot;, l, r, rt, Sum[rt]);
    if (l == r)
        return;
    int m = l + r &amp;gt;&amp;gt; 1;
    print(lch);
    print(rch);
}
int main()
{
    int n, m;
    //freopen(&quot;god.in&quot;, &quot;r&quot;, stdin);
   // freopen(&quot;god.out&quot;, &quot;w&quot;, stdout);
    scanf(&quot;%d&quot;, &amp;amp;n);
    buildtree(1, n, 1);
    scanf(&quot;%d&quot;, &amp;amp;m);
    int op, l, r;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d%d%d&quot;, &amp;amp;op, &amp;amp;l, &amp;amp;r);
        if (l &amp;gt; r)
            swap(l, r);
        if (op)
        {
            printf(&quot;%lld\n&quot;, Query(l, r, 1, n, 1));
        }
        else
        {
            Update(l, r, 1, n, 1);
        }
    }
#ifdef Mine
    //while (1)
        ;
#endif
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>String STL set map Trie</title><link>https://www.nekomio.com/posts/33/</link><guid isPermaLink="true">https://www.nekomio.com/posts/33/</guid><pubDate>Tue, 11 Jul 2017 16:09:42 GMT</pubDate><content:encoded>&lt;h3&gt;描述&lt;/h3&gt;
&lt;p&gt;硬盘中里面有n个文件，文件从1到n标号，每个文件可以用若干个数字序列来表示，而且每个文件存在一个重要值。现在请你完成一个搜索系统，有m
个搜索的操作，如果一个文件中有以这个数字序列为前缀的数字序列，那么这个文件会被搜索到，现在我们想知道会有多少个文件被搜索到，以及这
些文件中重要值前k小的是哪些。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第一行两个数n,m。
接下来n行是对每个文件的描述（标号依次是1到n）：
每行的前两个数字分别为描述这个文件的数字序列个数t和文件的重要值v。
接下来有t组数。
每组数先有一个数l，表示这个数字序列的长度。
接下来有l个数，表示这个序列。
接下来m行表示m个搜索操作：
每行的前两个数字分别为搜索数k和前缀长度l。
接下来l个数是这个前缀的数字序列。&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;共m行。
每行来表示搜索的结果：
首先你需要输出有多少个文件会被搜索到。
接下来你需要输出k个数，依次是重要值前k小的标号（根据重要值由小到大输出，重要值相同时，标号小的排在前面）。
如果搜索到的文件数p比k小，那么你只需要输出p个,如果没有搜索到文件就不用输出了。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5 5&lt;br /&gt;
1 1 5 1 2 3 4 5&lt;br /&gt;
1 2 5 1 2 4 5 3&lt;br /&gt;
1 8 5 2 1 4 3 2&lt;br /&gt;
1 9 5 2 1 8 5 2&lt;br /&gt;
1 1 5 1 2 3 4 5&lt;br /&gt;
2 2 1 2&lt;br /&gt;
3 2 1 2&lt;br /&gt;
4 2 1 2&lt;br /&gt;
4 2 2 1&lt;br /&gt;
1 2 2 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3 1 5&lt;br /&gt;
3 1 5 2&lt;br /&gt;
3 1 5 2&lt;br /&gt;
2 3 4&lt;br /&gt;
2 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;数据范围和约定&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;对于20%的数据&lt;br /&gt;
0&amp;lt;n,m&amp;lt;=50&lt;br /&gt;
每次询问k无限制&lt;br /&gt;
0&amp;lt;重要值&amp;lt;=10^9&lt;br /&gt;
0&amp;lt;数字序列中的数字&amp;lt;=10&lt;br /&gt;
所有文件数字序列长度之和&amp;lt;=500&lt;br /&gt;
所有询问前缀数字序列长度之和&amp;lt;=500&lt;/li&gt;
&lt;li&gt;对于另外20%的数据&lt;br /&gt;
0&amp;lt;n,m&amp;lt;=50&lt;br /&gt;
每次询问k无限制&lt;br /&gt;
0&amp;lt;重要值&amp;lt;=10^9&lt;br /&gt;
0&amp;lt;数字序列中的数字&amp;lt;=10^9&lt;br /&gt;
所有文件数字序列长度之和&amp;lt;=500&lt;br /&gt;
所有询问前缀数字序列长度之和&amp;lt;=500&lt;/li&gt;
&lt;li&gt;对于另外20%的数据&lt;br /&gt;
0&amp;lt;n,m&amp;lt;=5&lt;em&gt;10^4&lt;br /&gt;
每次询问k=1或k=2&lt;br /&gt;
0&amp;lt;重要值&amp;lt;=10^9&lt;br /&gt;
0&amp;lt;数字序列中的数字&amp;lt;=10&lt;br /&gt;
所有文件数字序列长度之和&amp;lt;=2&lt;/em&gt;10^5&lt;br /&gt;
所有询问前缀数字序列长度之和&amp;lt;=2*10^5&lt;/li&gt;
&lt;li&gt;对于剩下的数据&lt;br /&gt;
0&amp;lt;n,m&amp;lt;=5&lt;em&gt;10^4&lt;br /&gt;
每次询问k无限制&lt;br /&gt;
0&amp;lt;重要值&amp;lt;=10^9&lt;br /&gt;
0&amp;lt;数字序列中的数字&amp;lt;=10^9&lt;br /&gt;
所有文件数字序列长度之和&amp;lt;=2&lt;/em&gt;10^5&lt;br /&gt;
所有询问前缀数字序列长度之和&amp;lt;=2*10^5&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;map&amp;gt;
#include &amp;lt;set&amp;gt;
#include &amp;lt;ctime&amp;gt;
using namespace std;
vector&amp;lt;int&amp;gt; l;
struct Improtant
{
    int i, Imp;
    bool operator&amp;lt;(const Improtant &amp;amp;a) const
    {
        return Imp == a.Imp ? i &amp;lt; a.i : Imp &amp;lt; a.Imp;
    }
} number[50005];
struct Trie
{
    map&amp;lt;int, Trie *&amp;gt; mp;
    set&amp;lt;Improtant&amp;gt; mark;
} * root;
void insert(int x)
{
    Trie *rt = root;
    rt-&amp;gt;mark.insert(number[x]);
    for (int i = 0; i &amp;lt; l.size(); i++)
    {
        if (!rt-&amp;gt;mp[l[i]])
            rt-&amp;gt;mp[l[i]] = new Trie;
        rt = rt-&amp;gt;mp[l[i]];
        rt-&amp;gt;mark.insert(number[x]);
    }
}
void Query(int k)
{
    Trie *rt = root;
    for (int i = 0; i &amp;lt; l.size(); i++)
    {
        if (rt-&amp;gt;mp[l[i]] == NULL)
        {
            printf(&quot;0\n&quot;);
            return;
        }
        rt = rt-&amp;gt;mp[l[i]];
    }
    set&amp;lt;Improtant&amp;gt;::iterator it = rt-&amp;gt;mark.begin();
    printf(&quot;%d &quot;, rt-&amp;gt;mark.size());
    for (int i = 1; i &amp;lt;= k &amp;amp;&amp;amp; it != rt-&amp;gt;mark.end(); i++, it++)
    {
        printf(&quot;%d &quot;, it-&amp;gt;i);
    }
    printf(&quot;\n&quot;);
    return;
}
int main()
{
#ifdef Mine
    freopen(&quot;1.in&quot;, &quot;r&quot;, stdin);
#else
    freopen(&quot;string.in&quot;, &quot;r&quot;, stdin);
#endif
    freopen(&quot;string.out&quot;, &quot;w&quot;, stdout);
    int n, m;
    root = new Trie;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    int t, s, a;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        number[i].i = i;
        scanf(&quot;%d%d&quot;, &amp;amp;t, &amp;amp;number[i].Imp);
        while (t--)
        {
            scanf(&quot;%d&quot;, &amp;amp;s);
            l.clear();
            for (int j = 1; j &amp;lt;= s; j++)
            {
                scanf(&quot;%d&quot;, &amp;amp;a);
                l.push_back(a);
            }
            insert(i);
        }
    }
    int k;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;k, &amp;amp;s);
        l.clear();
        for (int j = 1; j &amp;lt;= s; j++)
        {
            scanf(&quot;%d&quot;, &amp;amp;a);
            l.push_back(a);
        }
        Query(k);
    }
    //printf(&quot;%lf&quot;,(double)clock()/CLOCKS_PER_SEC);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>数学</title><link>https://www.nekomio.com/posts/32/</link><guid isPermaLink="true">https://www.nekomio.com/posts/32/</guid><pubDate>Mon, 10 Jul 2017 15:52:42 GMT</pubDate><content:encoded>&lt;h2&gt;组合数&lt;/h2&gt;
&lt;p&gt;$$ C(n,k)=\frac {n!} {(n-k)!k!} $$&lt;br /&gt;
$$ 0!=1 $$&lt;/p&gt;
&lt;p&gt;$$ x^{p} mod p=x mod p $$&lt;br /&gt;
$$ x^{p-2} * x % p=1; $$&lt;/p&gt;
</content:encoded></item><item><title>BZOJ 2120 数颜色 </title><link>https://www.nekomio.com/posts/31/</link><guid isPermaLink="true">https://www.nekomio.com/posts/31/</guid><pubDate>Sun, 09 Jul 2017 20:45:16 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;墨墨购买了一套N支彩色画笔（其中有些颜色可能相同），摆成一排，你需要回答墨墨的提问。墨墨会像你发布如下指令： 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求，你知道你需要干什么了吗？
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第1行两个整数N，M，分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数，分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行，每行分别代表墨墨会做的一件事情，格式见题干部分。&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;对于每一个Query的询问，你需要在对应的行中给出一个数字，代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;6 5&lt;br /&gt;
1 2 3 4 5 5&lt;br /&gt;
Q 1 4&lt;br /&gt;
Q 2 6&lt;br /&gt;
R 1 2&lt;br /&gt;
Q 1 4&lt;br /&gt;
Q 2 6&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;p&gt;4&lt;br /&gt;
4&lt;br /&gt;
3&lt;br /&gt;
4&lt;/p&gt;
&lt;h3&gt;提示&lt;/h3&gt;
&lt;p&gt;对于100%的数据，N≤10000，M≤10000，修改操作不多于1000次，所有的输入数据中出现的所有整数均大于等于1且不超过10^6。
2016.3.2新加数据两组by Nano_Ape&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;计算出 i 的 前一个出现的位置&lt;br /&gt;
然后就和教主的魔法一样了&lt;br /&gt;
注意数组大小&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
int comp(int a, int b)
{
    return a &amp;gt; b;
}
using namespace std;
int pre[10005], front[1000005];
int in[10005];
int a[10005], b[10005];
int n, block;
void build(int x)
{
    for (int i = (x - 1) * block + 1; i &amp;lt;= min(x * block, n); i++)
    {
        pre[i] = b[i];
    }
    sort(pre + (x - 1) * block + 1, pre + min(x * block + 1, n + 1));
}
void rebuild(int k, int x)
{
    for (int i = 1; i &amp;lt;= n; i++)
        front[a[i]] = 0;
    a[k] = x;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        int ls = b[i];
        b[i] = front[a[i]];
        if (ls != b[i])
            build(in[i]);
        front[a[i]] = i;
    }
}
int query(int c, int x)
{
    int l = (x - 1) * block + 1, r = min(n, x * block);
    int head = l;
    while (l &amp;lt;= r)
    {
        int m = (l + r) &amp;gt;&amp;gt; 1;
        if (pre[m] &amp;lt; c)
            l = m + 1;
        else
            r = m - 1;
    }
    return l - head;
}
int Query(int l, int r)
{
    int ans = 0;
    if (in[l] == in[r])
    {
        for (int i = l; i &amp;lt;= r; i++)
            if (b[i] &amp;lt; l)
                ans++;
    }
    else
    {
        for (int i = l; i &amp;lt;= min(block * in[l], n); i++)
            if (b[i] &amp;lt; l)
                ans++;
        for (int i = block * (in[r] - 1) + 1; i &amp;lt;= r; i++)
            if (b[i] &amp;lt; l)
                ans++;
    }
    for (int i = in [l] + 1; i &amp;lt; in[r]; i++)
        ans += query(l, i);
    return ans;
}
int main()
{
    //freopen(&quot;nt2011_color.in&quot;,&quot;r&quot;,stdin);
    //freopen(&quot;nt2011_color.out&quot;,&quot;w&quot;,stdout);
    //freopen(&quot;1.in&quot;, &quot;r&quot;, stdin);
    int m;
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    block = sqrt(n);
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
        b[i] = front[a[i]];
        front[a[i]] = i;
        in[i] = (i - 1) / block + 1;
    }
    int tot = in[n];
    for (int i = 1; i &amp;lt;= tot; i++)
        build(i);
    char s[10];
    int l, r;
    while (m--)
    {
        scanf(&quot;%s&quot;, s);
        if (s[0] == &apos;Q&apos;)
        {
            scanf(&quot;%d%d&quot;, &amp;amp;l, &amp;amp;r);
            printf(&quot;%d\n&quot;, Query(l, r));
        }
        else
        {
            scanf(&quot;%d%d&quot;, &amp;amp;l, &amp;amp;r);
            rebuild(l, r);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 2724 [Violet 6] 蒲公英</title><link>https://www.nekomio.com/posts/30/</link><guid isPermaLink="true">https://www.nekomio.com/posts/30/</guid><pubDate>Sun, 09 Jul 2017 20:36:54 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/145076757cd1b.gif&quot; alt=&quot;145076757cd1b.gif&quot; /&gt;
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/24583944f28e6.gif&quot; alt=&quot;24583944f28e6.gif&quot; /&gt;
修正一下&lt;/p&gt;
&lt;p&gt;l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/5196304f4bf2.gif&quot; alt=&quot;5196304f4bf2.gif&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;6 3&lt;br /&gt;
1 2 3 2 1 2&lt;br /&gt;
1 5&lt;br /&gt;
3 6&lt;br /&gt;
1 5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1&lt;br /&gt;
2&lt;br /&gt;
1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://moetu.fastmirror.org/images/2017/08/02/203875813f6f9.gif&quot; alt=&quot;203875813f6f9.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;修正下：
n &amp;lt;= 40000, m &amp;lt;= 50000&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;f(i,j)表示第 i 块到第 j 块的众数。
为每一个数开vector&amp;lt;&amp;gt; 存他的位置&lt;br /&gt;
在求得时候二分就可以了&lt;br /&gt;
详见《区间众数解题报告 - 陈立杰》&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;map&amp;gt;
#include &amp;lt;cmath&amp;gt;
using namespace std;
int n, m, block, tot;
int a[40005], Index, v[40005];
int in[40005];
int f[4000][4000], num[40005];
map&amp;lt;int, int&amp;gt; mp;
vector&amp;lt;int&amp;gt; x[40005];
void Init(int u)
{
    memset(num, 0, sizeof(num));
    int Max = 0, ans = 0;
    for (int i = (u - 1) * block + 1; i &amp;lt;= n; i++)
    {
        num[a[i]]++;
        if (num[a[i]] &amp;gt; Max || (num[a[i]] == Max &amp;amp;&amp;amp; v[a[i]] &amp;lt; v[ans]))
            ans = a[i], Max = num[a[i]];
        f[u][in[i]] = ans;
    }
}
int Query(int l, int r, int u)
{
    return upper_bound(x[u].begin(), x[u].end(), r) - lower_bound(x[u].begin(), x[u].end(), l);
}
int Query(int l, int r)
{
    int ans, Max;
    ans = f[in[l] + 1][in[r] - 1];
    Max = Query(l, r, ans);
    for (int i = l; i &amp;lt;= min(in[l] * block, r); i++)
    {
        int now = Query(l, r, a[i]);
        if (now &amp;gt; Max || (now == Max &amp;amp;&amp;amp; v[a[i]] &amp;lt; v[ans]))
            ans = a[i], Max = now;
    }
    if (in[l] != in[r])
    {
        for (int i = (in[r] - 1) * block + 1; i &amp;lt;= r; i++)
        {
            int now = Query(l, r, a[i]);
            if (now &amp;gt; Max || (now == Max &amp;amp;&amp;amp; v[a[i]] &amp;lt; v[ans]))
                ans = a[i], Max = now;
        }
    }
    return ans;
}
int main()
{
    //freopen(&quot;input.in&quot;, &quot;r&quot;, stdin);
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    block = 200;
    for (int i = 1; i &amp;lt;= n; i++)
    {
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
        if (!mp[a[i]])
        {
            mp[a[i]] = ++Index;
            v[Index] = a[i];
        }
        a[i] = mp[a[i]];
        x[a[i]].push_back(i);
        in[i] = (i - 1) / block + 1;
    }
    tot = in[n];
    for (int i = 1; i &amp;lt;= tot; i++)
        Init(i);
    int l, r, ans = 0;
    for (int i = 1; i &amp;lt;= m; i++)
    {
        scanf(&quot;%d%d&quot;, &amp;amp;l, &amp;amp;r);
        l = (l + ans - 1) % n + 1, r = (r + ans - 1) % n + 1;
        if (l &amp;gt; r)
            swap(l, r);
        ans = v[Query(l, r)];
        printf(&quot;%d\n&quot;, ans);
    }
    //while (1)
    ;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;附数据生成器&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;cstdio&amp;gt;  
#include&amp;lt;ctime&amp;gt;  
#include&amp;lt;cstdlib&amp;gt;  
#include&amp;lt;iostream&amp;gt;  
using namespace std;  
int main()  
{  
    freopen(&quot;input.in&quot;,&quot;w&quot;,stdout);  
    int n,m;  
    n=40000;m=50000;  
    srand(time(0));  
    printf(&quot;%d %d\n&quot;,n,m);  
    for (int i=1;i&amp;lt;=n;i++){  
        int x=rand()*rand()%1000000000+1;  
        cout&amp;lt;&amp;lt;x&amp;lt;&amp;lt;&quot; &quot;;  
    }  
    printf(&quot;\n&quot;);  
    for (int i=1;i&amp;lt;=m;i++){  
        int l=rand()*rand()%n+1;  
        int r=rand()*rand()%n+1;  
        cout&amp;lt;&amp;lt;l&amp;lt;&amp;lt;&quot; &quot;&amp;lt;&amp;lt;r&amp;lt;&amp;lt;endl;  
    }  
    return 0;  
}  
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊</title><link>https://www.nekomio.com/posts/29/</link><guid isPermaLink="true">https://www.nekomio.com/posts/29/</guid><pubDate>Thu, 06 Jul 2017 17:16:03 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;某天，Lostmonkey发明了一种超级弹力装置，为了在他的绵羊朋友面前显摆，他邀请小绵羊一起玩个游戏。游戏一开始，Lostmonkey在地上沿着一条直线摆上n个装置，每个装置设定初始弹力系数ki，当绵羊达到第i个装置时，它会往后弹ki步，达到第i+ki个装置，若不存在第i+ki个装置，则绵羊被弹飞。绵羊想知道当它从第i个装置起步时，被弹几次后会被弹飞。为了使得游戏更有趣，Lostmonkey可以修改某个弹力装置的弹力系数，任何时候弹力系数均为正整数。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第一行包含一个整数n，表示地上有n个装置，装置的编号从0到n-1,接下来一行有n个正整数，依次为那n个装置的初始弹力系数。第三行有一个正整数m，接下来m行每行至少有两个数i、j，若i=1，你要输出从j出发被弹几次后被弹飞，若i=2则还会再输入一个正整数k，表示第j个弹力装置的系数被修改成k。对于20%的数据n,m&amp;lt;=10000，对于100%的数据n&amp;lt;=200000,m&amp;lt;=100000&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;对于每个i=1的情况，你都要输出一个需要的步数，占一行。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;4&lt;br /&gt;
1 2 1 1						&lt;br /&gt;
3&lt;br /&gt;
1 1&lt;br /&gt;
2 1 1&lt;br /&gt;
1 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;br /&gt;
3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;将每一块都处理出&lt;br /&gt;
i 跳出 这一块所用的次数和跳到的位置
然后更新时将这一块重构&lt;/p&gt;
&lt;p&gt;细节有问题的代码也能过（气）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cmath&amp;gt;
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch &amp;gt; &apos;9&apos; || ch &amp;lt; &apos;0&apos;)
    {
        if (ch == &apos;-&apos;)
            f = -1;
        ch = getchar();
    }
    while (ch &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; ch &amp;lt;= &apos;9&apos;)
    {
        x = x * 10 + ch - &apos;0&apos;;
        ch = getchar();
    }
    return x * f;
}
int n, m, k[200005], block;
int in[200005], next[200005], times[200005], l[200005];
int main()
{
    //freopen(&quot;1.in&quot;,&quot;r&quot;,stdin);
    //scanf(&quot;%d&quot;, &amp;amp;n);
    n = read();
    block = sqrt(n);
    for (int i = 0; i &amp;lt; n; i++)
    {
        k[i] = read();
        //scanf(&quot;%d&quot;, k + i);
        in[i] = i / block + 1;
        l[i] = (in[i] - 1) * block;
    }
    for (int i = n - 1; i &amp;gt;= 0; i--)
    {
        if (i + k[i] &amp;gt; n)
        {
            times[i] = 1;
            next[i] = n;
        }
        else if (in[i] == in[i + k[i]])
        {
            times[i] = times[i + k[i]] + 1;
            next[i] = next[i + k[i]];
        }
        else
        {
            times[i] = 1;
            next[i] = i + k[i];
        }
    }
    //scanf(&quot;%d&quot;, &amp;amp;m);
    m = read();
    int op, s;
    while (m--)
    {
        //scanf(&quot;%d&quot;, &amp;amp;op);
        op = read();
        if (op == 1)
        {
            //scanf(&quot;%d&quot;, &amp;amp;s);
            s = read();
            int ans = 0;
            for (int i = s; i &amp;lt; n; i = next[i])
            {
                ans += times[i];
            }
            printf(&quot;%d\n&quot;, ans);
        }
        else
        {
            //scanf(&quot;%d%d&quot;, &amp;amp;s, &amp;amp;c);
            //k[s] = c;
            s = read();
            k[s] = read();
            for (int i = s; i &amp;gt;= l[s]; i--)
            {
                if (i + k[i] &amp;gt; n)
                {
                    times[i] = 1;
                    next[i] = i + k[i];
                }
                if (in[i] == in[i + k[i]])
                {
                    times[i] = times[i + k[i]] + 1;
                    next[i] = next[i + k[i]];
                }
                else
                {
                    times[i] = 1;
                    next[i] = i + k[i];
                }
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Codeforces 743E Vladik and cards</title><link>https://www.nekomio.com/posts/27/</link><guid isPermaLink="true">https://www.nekomio.com/posts/27/</guid><pubDate>Mon, 03 Jul 2017 16:30:22 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;Vladik在回家的路上无聊，决定玩下面的游戏：他拿了n张牌在他面前排成一个序列，每张牌上都有一个不超过8的正整数，他决定找到满足以下条件的牌的最长子序列：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在这个序列中,[1,8]每个数字出现的次数之差的绝对值不超过1;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;相同的数字必须连续，输出最长子序列的长度。例如，子序列[1, 1, 2, 2]满足第2个条件，但是子序列 [1, 2, 2, 1]就不满足(注意，子序列[1, 1, 2, 2]不满足第一个条件)。
&amp;lt;!--more--&amp;gt;
请帮助Vladik找到满足这两个条件的最长子序列的长度。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第一行包含单个整数n（1≤n≤1000） - Vladik序列中的牌数。&lt;/p&gt;
&lt;p&gt;第二行包含不超过8的n个正整数的序列 - 每个数空格隔开&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;输出一个整数，即满足两个条件的子序列的最大长度&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;sample input 1:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;br /&gt;
1 1 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;sample input 2:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;8&lt;br /&gt;
8 7 6 5 4 3 2 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;sample input 3:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;24&lt;br /&gt;
1 8 1 2 8 2 3 8 3 4 8 4 5 8 5 6 8 6 7 8 7 8 8 8&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;sample output 1:&lt;br /&gt;
1&lt;br /&gt;
sample output 2:&lt;br /&gt;
8&lt;br /&gt;
sample output 3:&lt;br /&gt;
17&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;题解请参考&lt;a href=&quot;https://www.cnblogs.com/TSHugh/p/7106544.html&quot;&gt;CodeForces743E. Vladik and cards 二分+装压dp&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-07-02 16:07:15 
 * @Last Modified by: WildRage
 * @Last Modified time: 2017-07-02 17:58:06
 */
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
int a[1005], sum[10][1005],n;
int DP[1005][300];
bool had[10];
int N = (1 &amp;lt;&amp;lt; 8) - 1;
vector&amp;lt;int&amp;gt; in[10];
int get_num(int p, int len)
{
	int now = lower_bound(in[a[p]].begin(), in[a[p]].end(), p) - in[a[p]].begin();
	int ans = now + len - 1;
	if (in[a[p]].size() - 1 &amp;lt; ans)
		return -1;
	return in[a[p]][ans];
}
int Judge(int len)
{
	memset(DP, 0, sizeof(DP));
	for (int i = 0; i &amp;lt; n; i++)
	{
		int to = get_num(i + 1, len);
		if (to != -1)
			DP[to][(1 &amp;lt;&amp;lt; (a[i + 1] - 1))] = max(DP[i][0] + len, DP[to][1 &amp;lt;&amp;lt; (a[i + 1] - 1)]);
		to = get_num(i + 1, len + 1);
		if (to != -1)
			DP[to][(1 &amp;lt;&amp;lt; (a[i + 1] - 1))] = max(DP[i][0] + len + 1, DP[to][(1 &amp;lt;&amp;lt; (a[i + 1] - 1))]);
		for (int j = 1; j &amp;lt; N; j++)
		{
			if (DP[i][j])
			{
				DP[i + 1][j] = max(DP[i + 1][j], DP[i][j]);
				if (j &amp;amp; (1 &amp;lt;&amp;lt; (a[i + 1] - 1)))
					continue;
				to = get_num(i + 1, len);
				if (to != -1)
					DP[to][j | (1 &amp;lt;&amp;lt; (a[i + 1] - 1))] = max(DP[i][j] + len, DP[to][j | (1 &amp;lt;&amp;lt; (a[i + 1] - 1))]);
				to = get_num(i + 1, len + 1);
				if (to != -1)
					DP[to][j | (1 &amp;lt;&amp;lt; (a[i + 1] - 1))] = max(DP[i][j] + len + 1, DP[to][j | (1 &amp;lt;&amp;lt; (a[i + 1] - 1))]);
			}
			DP[i + 1][N] = max(DP[i + 1][N], DP[i][N]);
		}
	}
	return DP[n][N];
}
int main()
{
	scanf(&quot;%d&quot;, &amp;amp;n);
	for (int i = 1; i &amp;lt;= n; i++)
	{
		scanf(&quot;%d&quot;, a + i);
		had[a[i]] = 1;
		in[a[i]].push_back(i);
	}
	int ans = 0;
	for(int i=1;i&amp;lt;=8;i++)if(had[i])ans++;
	int l = 1, r = 256;
	while (l &amp;lt;= r)
	{
		int mid = l + r &amp;gt;&amp;gt; 1;
		int x = Judge(mid);
		ans = max(x, ans);
		if (x)
			l = mid + 1;
		else
			r = mid - 1;
	}
	printf(&quot;%d&quot;, ans);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>HDU 1166 敌兵布阵</title><link>https://www.nekomio.com/posts/28/</link><guid isPermaLink="true">https://www.nekomio.com/posts/28/</guid><pubDate>Mon, 03 Jul 2017 16:30:22 GMT</pubDate><content:encoded>&lt;h3&gt;题目描述&lt;/h3&gt;
&lt;p&gt;C国的死对头A国这段时间正在进行军事演习，所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况。由于采取了某种先进的监测手段，所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动，可能增加或减少若干人手,但这些都逃不过C国的监视。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:“Tidy,马上汇报第3个营地到第10个营地共有多少人!”Tidy就要马上开始计算这一段的总人数并汇报。但敌兵营地的人数经常变动，而Derek每次询问的段都不一样，所以Tidy不得不每次都一个一个营地的去数，很快就精疲力尽了，Derek对Tidy的计算速度越来越不满:&quot;你个死肥仔，算得这么慢，我炒你鱿鱼!”Tidy想：“你自己来算算看，这可真是一项累人的工作!我恨不得你炒我鱿鱼呢!”无奈之下，Tidy只好打电话向计算机专家Windbreaker求救,Windbreaker说：“死肥仔，叫你平时做多点acm题和看多点算法书，现在尝到苦果了吧!”Tidy说：&quot;我知错了。。。&quot;但Windbreaker已经挂掉电话了。Tidy很苦恼，这么算他真的会崩溃的，聪明的读者，你能写个程序帮他完成这项工作吗？不过如果你的程序效率不够高的话，Tidy还是会受到Derek的责骂的.&lt;/p&gt;
&lt;h3&gt;输入&lt;/h3&gt;
&lt;p&gt;第一行一个整数T，表示有T组数据。
每组数据第一行一个正整数N（N&amp;lt;=50000）,表示敌人有N个工兵营地，接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人（1&amp;lt;=ai&amp;lt;=50）。
接下来每行有一条命令，命令有4种形式：
(1) Add i j,i和j为正整数,表示第i个营地增加j个人（j不超过30）
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人（j不超过30）;
(3)Query i j ,i和j为正整数,i&amp;lt;=j，表示询问第i到第j个营地的总人数;
(4)End 表示结束，这条命令在每组数据最后出现;
每组数据最多有40000条命令&lt;/p&gt;
&lt;h3&gt;输出&lt;/h3&gt;
&lt;p&gt;对第i组数据,首先输出“Case i:”和回车,
对于每个Query询问，输出一个整数并回车,表示询问的段中的总人数,这个数保持在int以内。&lt;/p&gt;
&lt;h3&gt;样例输入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1&lt;br /&gt;
10&lt;br /&gt;
1 2 3 4 5 6 7 8 9 10&lt;br /&gt;
Query 1 3&lt;br /&gt;
Add 3 6&lt;br /&gt;
Query 2 7&lt;br /&gt;
Sub 10 2&lt;br /&gt;
Add 6 3&lt;br /&gt;
Query 3 10&lt;br /&gt;
End&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;样例输出&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Case 1:&lt;br /&gt;
6&lt;br /&gt;
33&lt;br /&gt;
59&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cmath&amp;gt;
namespace MineWorkSpace
{
int n;
class Block_Main
{
    int block, n;
    int a[50005], in[50005], sum[305];

  public:
    void Init(int N)
    {
        memset(in, 0, sizeof(in));
        memset(sum, 0, sizeof(sum));
        memset(a, 0, sizeof(a));
        n = N;
        block = sqrt(n);
        for (int i = 1; i &amp;lt;= n; i++)
        {
            scanf(&quot;%d&quot;, a + i);
            in[i] = (i - 1) / block + 1;
            sum[in[i]] += a[i];
        }
    }
    void Updata(int i, int c)
    {
        a[i] += c;
        sum[in[i]] += c;
    }
    int Query(int l, int r)
    {
        int ans = 0;
        if (in[l] == in[r])
        {
            for (int i = l; i &amp;lt;= r; i++)
                ans += a[i];
            return ans;
        }
        else
        {
            for (int i = in [l] + 1; i &amp;lt;= in[r] - 1; i++)
                ans += sum[i];
            for (int i = l; i &amp;lt;= in[l] * block; i++)
                ans += a[i];
            for (int i = (in[r] - 1) * block + 1; i &amp;lt;= r; i++)
                ans += a[i];
            return ans;
        }
    }
} Block;
class Order_run
{
    int l, r;

  public:
    void Run(char c)
    {
        if (c == &apos;Q&apos;)
        {
            scanf(&quot;%d%d&quot;, &amp;amp;l, &amp;amp;r);
            if (l &amp;gt; r)
                printf(&quot;0\n&quot;);
            else
                printf(&quot;%d\n&quot;, Block.Query(l, r));
            return;
        }
        if (c == &apos;A&apos;)
        {
            scanf(&quot;%d%d&quot;, &amp;amp;l, &amp;amp;r);
            Block.Updata(l, r);
            return;
        }
        if (c == &apos;S&apos;)
        {
            scanf(&quot;%d%d&quot;, &amp;amp;l, &amp;amp;r);
            Block.Updata(l, -r);
            return;
        }
    }
} Order;
class Main
{
  public:
    Main()
    {
        int T;
        scanf(&quot;%d&quot;, &amp;amp;T);
        for (int L = 1; L &amp;lt;= T; L++)
        {
            printf(&quot;Case %d:\n&quot;, L);
            scanf(&quot;%d&quot;, &amp;amp;n);
            Block.Init(n);
            char s[10];
            while (1)
            {
                scanf(&quot;%s&quot;, s);
                if (s[0] == &apos;E&apos;)
                    break;
                Order.Run(s[0]);
            }
        }
    }
} run;
}
int main() { ; }
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>POJ 2185 Milking Grid</title><link>https://www.nekomio.com/posts/26/</link><guid isPermaLink="true">https://www.nekomio.com/posts/26/</guid><pubDate>Mon, 03 Jul 2017 16:12:51 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;Every morning when they are milked, the Farmer John&apos;s cows form a rectangular grid that is R (1 &amp;lt;= R &amp;lt;= 10,000) rows by C (1 &amp;lt;= C &amp;lt;= 75) columns. As we all know, Farmer John is quite the expert on cow behavior, and is currently writing a book about feeding behavior in cows. He notices that if each cow is labeled with an uppercase letter indicating its breed, the two-dimensional pattern formed by his cows during milking sometimes seems to be made from smaller repeating rectangular patterns.
&amp;lt;!--more--&amp;gt;
Help FJ find the rectangular unit of smallest area that can be repetitively tiled to make up the entire milking grid. Note that the dimensions of the small rectangular unit do not necessarily need to divide evenly the dimensions of the entire milking grid, as indicated in the sample input below.&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Line 1: Two space-separated integers: R and C&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lines 2..R+1: The grid that the cows form, with an uppercase letter denoting each cow&apos;s breed. Each of the R input lines has C characters with no space or other intervening character.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Line 1: The area of the smallest unit from which the grid is formed&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2 5&lt;br /&gt;
ABABA&lt;br /&gt;
ABABA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;要求循环节，想到&lt;a href=&quot;https://wildrage.cf/2017/06/13/2/&quot;&gt;&quot;POJ 2406 Power Strings&quot;&lt;/a&gt;&lt;br /&gt;
把情况拓展到二维&lt;br /&gt;
对于每一个横行求最短循环节也就是m-next[m]&lt;br /&gt;
然后不断的求lcm&lt;br /&gt;
竖列也是一样&lt;br /&gt;
最后乘起来就可以了&lt;br /&gt;
不过在求lcm时如果大于边界就可以将他的值给为边界&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-07-01 10:17:47 
 * @Last Modified by: WildRage
 * @Last Modified time: 2017-07-01 11:08:00
 */
#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
namespace MineWorkSpace{
	char s[10005][80];
	int next[10005][80];
	int next2[80][10005];
	int gcd(int a,int b){
		return b==0? a: gcd(b,a%b);
	}
	int lcm(int a,int b){
		return a/gcd(a,b)*b;
	}
	int Main()
	{
	#ifdef Mine
	    freopen(&quot;mgrid.in&quot;,&quot;r&quot;,stdin);
	    freopen(&quot;mgrid.out&quot;,&quot;w&quot;,stdout);
	#endif
		int n,m;
		scanf(&quot;%d%d&quot;,&amp;amp;n,&amp;amp;m);
		for(int i=0;i&amp;lt;n;i++){
			scanf(&quot;%s&quot;,s[i]);
		}
		int ans1=1,ans2=1;
		for(int i=0;i&amp;lt;n;i++){
			int j=0,k=-1;
			next[i][0]=-1;
			while(j&amp;lt;m){
				if(k==-1||s[i][j]==s[i][k]){
					next[i][++j]=++k;
				}
				else k=next[i][k];
			}
			if(m-next[i][m]) ans1=lcm(ans1,m-next[i][m]);
			if(ans1&amp;gt;m)ans1=m;
		}
		for(int i=0;i&amp;lt;m;i++){
			int j=0,k=-1;
			next2[i][0]=-1;
			while(j&amp;lt;n){
				if(k==-1||s[j][i]==s[k][i]){
					next2[i][++j]=++k;
				}
				else k=next2[i][k];
			}
			if(n-next2[i][n])ans2=lcm(ans2,n-next2[i][n]);
			if(ans2&amp;gt;n)ans2=n;
		}
		return printf(&quot;%d&quot;,ans1*ans2);
	}
}
int main()
{
	MineWorkSpace::Main();
	//while(1);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 4720 [NOIP2016]换教室</title><link>https://www.nekomio.com/posts/25/</link><guid isPermaLink="true">https://www.nekomio.com/posts/25/</guid><pubDate>Sun, 25 Jun 2017 16:46:30 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程。在可以选择的课程中,有2n节
课程安排在n个时间段上。在第i(1≤i≤n)个时间段上,两节内容相同的课程同时在不同的地点进行,其中,牛牛预先
被安排在教室ci上课,而另一节课程在教室di进行。在不提交任何申请的情况下,学生们需要按时间段的顺序依次完
成所有的n节安排好的课程。如果学生想更换第i节课程的教室,则需要提出申请。若申请通过,学生就可以在第i个
&amp;lt;!--more--&amp;gt;
时间段去教室di上课,否则仍然在教室ci上课。由于更换教室的需求太多,申请不一定能获得通过。通过计算,牛牛
发现申请更换第i节课程的教室时,申请被通过的概率是一个已知的实数ki,并且对于不同课程的申请,被通过的概率
是互相独立的。学校规定,所有的申请只能在学期开始前一次性提交,并且每个人只能选择至多m节课程进行申请。
这意味着牛牛必须一次性决定是否申请更换每节课的教室,而不能根据某些课程的申请结果来决定其他课程是否申
请;牛牛可以申请自己最希望更换教室的m门课程,也可以不用完这m个申请的机会,甚至可以一门课程都不申请。因
为不同的课程可能会被安排在不同的教室进行,所以牛牛需要利用课间时间从一间教室赶到另一间教室。牛牛所在
的大学有v个教室,有e条道路。每条道路连接两间教室,并且是可以双向通行的。由于道路的长度和拥堵程度不同,
通过不同的道路耗费的体力可能会有所不同。当第i(1≤i≤n-1)节课结束后,牛牛就会从这节课的教室出发,选择一
条耗费体力最少的路径前往下一节课的教室。现在牛牛想知道,申请哪几门课程可以使他因在教室间移动耗费的体
力值的总和的期望值最小,请你帮他求出这个最小值。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;输出一行,包含一个实数,四舎五入精确到小数点后恰好2位,表示答案。你的
输出必须和标准输出完全一样才算正确。
测试数据保证四舎五入后的答案和准确答案的差的绝对值不大于4*10^-3。(如果你不知道什么是浮点误差,这段话
可以理解为:对于大多数的算法,你可以正常地使用浮点数类型而不用对它进行特殊的处理)&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3 2 3 3&lt;br /&gt;
2 1 2&lt;br /&gt;
1 2 1&lt;br /&gt;
0.8 0.2 0.5&lt;br /&gt;
1 2 5&lt;br /&gt;
1 3 3&lt;br /&gt;
2 3 1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2.80&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;这道题相比于前几道题是真水&lt;br /&gt;
先跑一下 Floyd
根据期望的可加性 只要在算DP数组的时候不断的加就可以了&lt;br /&gt;
分四种情况讨论&lt;br /&gt;
然后交上去就WA了
再一看要保留2位小数
我保留了3位&lt;br /&gt;
另外能把程序写的这么宽的人也只有我了吧&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-06-25 15:42:08 
 * @Last Modified by: WildRage
 * @Last Modified time: 2017-06-25 16:28:13
 */
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;iostream&amp;gt;
using namespace std;
namespace WorkSpace{
    class Floyd{
        int n;
        int a[305][305];
    public:
        void GetMinDis(){
            for(int i=1;i&amp;lt;=n;i++) a[i][i]=0;
            for(int k=1;k&amp;lt;=n;k++)
                for(int i=1;i&amp;lt;=n;i++)
                    for(int j=1;j&amp;lt;=n;j++)
                        a[i][j]=std::min(a[i][j],a[i][k]+a[k][j]);
        }
        void GetMap(int Number=0,int m=0){
            n=Number;
            memset(a,0x3f,sizeof(a));
            int s,e,v;
            for(int i=1;i&amp;lt;=m;i++){
                scanf(&quot;%d%d%d&quot;,&amp;amp;s,&amp;amp;e,&amp;amp;v);
                a[s][e]=std::min(v,a[s][e]);
                a[e][s]=std::min(v,a[s][e]);
            }
        }
        int MinDis(int s=0,int e=0){
            return a[s][e];
        }
    }Map;
    struct Input{
        int n,m,v,e;
    }Read;
    int ClassroomC[2005],ClassroomD[2005];
    double ChangeProbability[2005],FailedToChange[2005];
    class Init{
        void OpenFile(){
            freopen(&quot;classrooma.in&quot;,&quot;r&quot;,stdin);
            freopen(&quot;classrooma.out&quot;,&quot;w&quot;,stdout);
        }
        void ReadInput(){
            scanf(&quot;%d%d%d%d&quot;,&amp;amp;Read.n,&amp;amp;Read.m,&amp;amp;Read.v,&amp;amp;Read.e);
            for(int i=1;i&amp;lt;=Read.n;i++) scanf(&quot;%d&quot;,&amp;amp;ClassroomC[i]);
            for(int i=1;i&amp;lt;=Read.n;i++) scanf(&quot;%d&quot;,&amp;amp;ClassroomD[i]);
            for(int i=1;i&amp;lt;=Read.n;i++) scanf(&quot;%lf&quot;,&amp;amp;ChangeProbability[i]),FailedToChange[i]=1-ChangeProbability[i];
            Map.GetMap(Read.v,Read.e);
        }
    public:
        Init(){
        #ifdef MineWorkSpace
            OpenFile();
        #endif
            ReadInput();
            Map.GetMinDis();
        }
    };
    class DP{
        double MinExpectation[2010][2010][2];
    public:
        #define n Read.n
        #define m Read.m
        DP(){
            memset(MinExpectation,0x43,sizeof(MinExpectation));
            MinExpectation[1][0][0]=0;MinExpectation[1][1][1]=0;
            for(int i=2;i&amp;lt;=n;i++){
                for(int j=0;j&amp;lt;=m;j++){
                    MinExpectation[i][j][0]=std::min(MinExpectation[i-1][j][0]+Map.MinDis(ClassroomC[i-1],ClassroomC[i]),MinExpectation[i-1][j][1]+(double)Map.MinDis(ClassroomD[i-1],ClassroomC[i])*ChangeProbability[i-1]+(double)Map.MinDis(ClassroomC[i-1],ClassroomC[i])*FailedToChange[i-1]);
                    if(j&amp;gt;0)MinExpectation[i][j][1]=std::min(MinExpectation[i-1][j-1][0]+(double)Map.MinDis(ClassroomC[i-1],ClassroomD[i])*ChangeProbability[i]+(double)Map.MinDis(ClassroomC[i-1],ClassroomC[i])*FailedToChange[i],MinExpectation[i-1][j-1][1]+(double)Map.MinDis(ClassroomC[i-1],ClassroomC[i])*FailedToChange[i-1]*FailedToChange[i]+(double)Map.MinDis(ClassroomC[i-1],ClassroomD[i])*FailedToChange[i-1]*ChangeProbability[i]+(double)Map.MinDis(ClassroomD[i-1],ClassroomC[i])*ChangeProbability[i-1]*FailedToChange[i]+Map.MinDis(ClassroomD[i-1],ClassroomD[i])*ChangeProbability[i-1]*ChangeProbability[i]);
                }
            }
            double ans=1e16;
            for(int i=0;i&amp;lt;=m;i++){
                ans=std::min(MinExpectation[n][i][0],ans);
                ans=std::min(MinExpectation[n][i][1],ans);
            }
            printf(&quot;%.2lf&quot;,ans);
        }    
    };
    class Main{
    public:
        Main(){
            new Init();
            new DP();
            //while(1);
        }
    }Run;
}
int main(){;}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 1076 [SCOI2008]奖励关</title><link>https://www.nekomio.com/posts/24/</link><guid isPermaLink="true">https://www.nekomio.com/posts/24/</guid><pubDate>Sat, 24 Jun 2017 09:48:46 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;你正在玩你最喜欢的电子游戏，并且刚刚进入一个奖励关。在这个奖励关里，系统将依次随机抛出k次宝物，
每次你都可以选择吃或者不吃（必须在抛出下一个宝物之前做出选择，且现在决定不吃的宝物以后也不能再吃）。
宝物一共有n种，系统每次抛出这n种宝物的概率都相同且相互独立。也就是说，即使前k-1次系统都抛出宝物1（
这种情况是有可能出现的，尽管概率非常小），第k次抛出各个宝物的概率依然均为1/n。 获取第i种宝物将得到Pi
分，但并不是每种宝物都是可以随意获取的。第i种宝物有一个前提宝物集合Si。只有当Si中所有宝物都至少吃过
&amp;lt;!--more--&amp;gt;
一次，才能吃第i种宝物（如果系统抛出了一个目前不能吃的宝物，相当于白白的损失了一次机会）。注意，Pi可
以是负数，但如果它是很多高分宝物的前提，损失短期利益而吃掉这个负分宝物将获得更大的长期利益。 假设你
采取最优策略，平均情况你一共能在奖励关得到多少分值？&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行为两个正整数k和n，即宝物的数量和种类。以下n行分别描述一种宝物，其中第一个整数代表分值，随
后的整数依次代表该宝物的各个前提宝物（各宝物编号为1到n），以0结尾。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;输出一个实数，保留六位小数，即在最优策略下平均情况的得分。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1 2&lt;br /&gt;
1 0&lt;br /&gt;
2 0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1.500000&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;逆推即可&lt;br /&gt;
水题&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
using namespace std;
int w[16];
int p[16];
double f[105][1&amp;lt;&amp;lt;15];
int main()
{
    int n,k;
    scanf(&quot;%d%d&quot;,&amp;amp;k,&amp;amp;n);
    int a;
    for(int i=1;i&amp;lt;=n;i++){
        scanf(&quot;%d&quot;,&amp;amp;w[i]);
        while(scanf(&quot;%d&quot;,&amp;amp;a)&amp;amp;&amp;amp;a!=0) p[i]|=1&amp;lt;&amp;lt;(a-1);
    }
    int S=(1&amp;lt;&amp;lt;n)-1;
    for(int i=k;i&amp;gt;=1;i--){
        for(int j=0;j&amp;lt;=S;j++){
            for(int m=1;m&amp;lt;=n;m++)
                if((p[m]&amp;amp;j)==p[m])
                    f[i][j]+=max(f[i+1][j],f[i+1][j|(1&amp;lt;&amp;lt;(m-1))]+w[m]);
                else f[i][j]+=f[i+1][j];
            f[i][j]/=n;
        }
    }
    printf(&quot;%.6lf&quot;,f[1][0]);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 2337 [HNOI2011]XOR和路径</title><link>https://www.nekomio.com/posts/23/</link><guid isPermaLink="true">https://www.nekomio.com/posts/23/</guid><pubDate>Thu, 22 Jun 2017 17:05:22 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/22/594b88b5de2d5.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;以每一位分别分析&lt;br /&gt;
f[i]为这一位为1的概率&lt;/p&gt;
&lt;p&gt;然后高斯消元即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;cmath&amp;gt;
#include&amp;lt;algorithm&amp;gt;
using namespace std;
struct edge{
    int END,next;
    bool b[32];
}v[30005];
int first[105],p,t[105],du[105];
double f[105][35][2];
double a[105][105],x[105];
void add(int a,int b,int c){
    int i=1;
    du[a]++;
    while(c){
        v[p].b[i]=c&amp;amp;1;
        i++;c&amp;gt;&amp;gt;=1;
    }
    v[p].END=b;v[p].next=first[a];
    first[a]=p++;
}
int n,m;
void gauss(){
    int im,num=1;
    for(int k=1;k&amp;lt;=n;k++,num++){
        im=k;
        for(int i=k+1;i&amp;lt;=n;i++){
            if(fabs(a[i][k])&amp;gt;fabs(a[im][k]))
                im=i;
        }
        if(im!=k){
            for(int i=k;i&amp;lt;=n+1;i++){
                swap(a[num][i],a[im][i]);
            }
        }
        if(!a[num][k]){
            num--;continue;
        }
        for(int i=num+1;i&amp;lt;=n;i++){
            if(!a[num][k])continue;
            long double t=a[i][k]/a[num][k];
            for(int j=k;j&amp;lt;=n+1;j++){
                a[i][j]-=t*a[k][j];
            }
        }
    }
    for(int i=n;i&amp;gt;=1;i--){
        for(int j=n;j&amp;gt;=i+1;j--){
            a[i][n+1]-=a[i][j]*x[j];
        }
        x[i]=a[i][n+1]/a[i][i];
    }
}
int main()
{
    //freopen(&quot;xorpath.in&quot;, &quot;r&quot;, stdin);
    //freopen(&quot;xorpath.out&quot;, &quot;w&quot;, stdout);
    memset(first,-1,sizeof(first));
    scanf(&quot;%d%d&quot;,&amp;amp;n,&amp;amp;m);
    for(int a1,b,c,i=1;i&amp;lt;=m;i++){
        scanf(&quot;%d%d%d&quot;,&amp;amp;a1,&amp;amp;b,&amp;amp;c);
        add(a1,b,c);
        if(a1!=b) add(b,a1,c);
    }
    //for(int i=first[n];i!=-1;i=v[i].next)
     //   rdu[v[i].END]--;
    long double ans=0;
    for(int k=1;k&amp;lt;=31;k++){
        memset(a,0,sizeof(a));
        for(int i=1;i&amp;lt;n;i++){
            a[i][i]=1;
            memset(t,0,sizeof(t));
            for(int j=first[i];j!=-1;j=v[j].next){
                //if(v[j].END==n)continue;
                if(v[j].b[k]) a[i][v[j].END]+=double(1)/du[i],a[i][n+1]+=(double)1/du[i];
                else a[i][v[j].END]-=double(1)/du[i];
            }
        }
        a[n][n]=1;
        gauss();
        ans+=x[1]*(1&amp;lt;&amp;lt;(k-1));
    }
    printf(&quot;%.3lf&quot;,(double)ans);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>莫比乌斯反演的证明</title><link>https://www.nekomio.com/posts/22/</link><guid isPermaLink="true">https://www.nekomio.com/posts/22/</guid><pubDate>Wed, 21 Jun 2017 18:00:21 GMT</pubDate><content:encoded>&lt;h3&gt;莫比乌斯反演&lt;/h3&gt;
&lt;p&gt;已知
$$ F(n)=\sum_{d|n}{f(d)} $$
则&lt;br /&gt;
$$ f(n)=\sum_{d|n}{\mu(d)F(\frac {n}{d})} $$
&amp;lt;!--more--&amp;gt;
证明
$$ \sum_{d|n}{\mu(d)F(\frac {n}{d})} $$
$$ =\sum_{d|n}{\mu(d)\sum_{d&apos;|\frac {n}{d}}{f(d&apos;)}} $$&lt;/p&gt;
&lt;h2&gt;未完待续&lt;/h2&gt;
</content:encoded></item><item><title>BZOJ 1415 [Noi2005] 聪聪和可可 概率DP</title><link>https://www.nekomio.com/posts/21/</link><guid isPermaLink="true">https://www.nekomio.com/posts/21/</guid><pubDate>Wed, 21 Jun 2017 17:43:55 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/21/594a400282a59.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;数据的第1行为两个整数N和E，以空格分隔，分别表示森林中的景点数和连接相邻景点的路的条数。 第2行包含两个整数C和M，以空格分隔，分别表示初始时聪聪和可可所在的景点的编号。 接下来E行，每行两个整数，第i+2行的两个整数Ai和Bi表示景点Ai和景点Bi之间有一条路。 所有的路都是无向的，即：如果能从A走到B，就可以从B走到A。 输入保证任何两个景点之间不会有多于一条路直接相连，且聪聪和可可之间必有路直接或间接的相连。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;输出1个实数，四舍五入保留三位小数，表示平均多少个时间单位后聪聪会把可可吃掉。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;【输入样例1】&lt;br /&gt;
4 3&lt;br /&gt;
1 4&lt;br /&gt;
1 2&lt;br /&gt;
2 3&lt;br /&gt;
3 4&lt;br /&gt;
【输入样例2】&lt;br /&gt;
9 9&lt;br /&gt;
9 3&lt;br /&gt;
1 2&lt;br /&gt;
2 3&lt;br /&gt;
3 4&lt;br /&gt;
4 5&lt;br /&gt;
3 6&lt;br /&gt;
4 6&lt;br /&gt;
4 7&lt;br /&gt;
7 8&lt;br /&gt;
8 9&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;【输出样例1】&lt;br /&gt;
1.500&lt;br /&gt;
【输出样例2】&lt;br /&gt;
2.167&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;先每个点跑一遍SPFA&lt;br /&gt;
求出p[i][j]表示当可可在 j 点时，聪聪在 i 点要走的下一步&lt;br /&gt;
然后记忆化搜索&lt;br /&gt;
$$ f[s][e]=\sum_{tmp=p[p[i][e]][e],e-&amp;gt;j}{\frac{f[tmp][j]}{du[e]+1}} $$&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;algorithm&amp;gt;
#include&amp;lt;queue&amp;gt;
using namespace std;
struct edge{
    int END,next;
}v[100005];
int first[1005],Index,du[1005],n;
void add(int a,int b){
    du[a]++;
    v[Index].END=b;
    v[Index].next=first[a];
    first[a]=Index++;
}
int p[1005][1005];
double f[1005][1005];
void spfa(int x){
    queue&amp;lt;int&amp;gt; Q;
    bool flag[1005]={0};
    int dis[1005],fr[1005];
    memset(dis,0x3f,sizeof(dis));
    memset(fr,0,sizeof(fr));
    dis[x]=0;
    flag[x]=1;Q.push(x);
    while(!Q.empty()){
        int k=Q.front();
        Q.pop();flag[k]=0;
        for(int i=first[k];i!=-1;i=v[i].next){
            if(dis[v[i].END]&amp;gt;dis[k]+1||(dis[v[i].END]==dis[k]+1&amp;amp;&amp;amp;k&amp;lt;fr[v[i].END])){
                dis[v[i].END]=dis[k]+1;
                fr[v[i].END]=k;
                if(!flag[v[i].END]){
                    flag[v[i].END]=1;
                    Q.push(v[i].END);
                }
            }
        }
    }
    for(int i=1;i&amp;lt;=n;i++)
        if(i!=x)
            p[i][x]=fr[i];
}
double dfs(int s,int e){
    if(s==e)return f[s][e]=0;
    if(p[s][e]==e||p[p[s][e]][e]==e)return f[s][e]=1;
    if(f[s][e]&amp;lt;=1e9) return f[s][e];
    int tmp=p[p[s][e]][e];
    f[s][e]=1;
    for(int i=first[e];i!=-1;i=v[i].next){
        f[s][e]+=dfs(tmp,v[i].END)/(du[e]+1);
    }
    f[s][e]+=dfs(tmp,e)/(du[e]+1);
    return f[s][e];
}
int main()
{
    //freopen(&quot;cchkk.in&quot;,&quot;r&quot;,stdin);
	//freopen(&quot;cchkk.out&quot;,&quot;w&quot;,stdout);
    memset(first,-1,sizeof(first));
    memset(f,0x7f,sizeof(f));
    int m,s,e,a,b;
    scanf(&quot;%d%d%d%d&quot;,&amp;amp;n,&amp;amp;m,&amp;amp;s,&amp;amp;e);
    for(int i=1;i&amp;lt;=m;i++){
        scanf(&quot;%d%d&quot;,&amp;amp;a,&amp;amp;b);
        add(a,b);
        add(b,a);
    }
    for(int i=1;i&amp;lt;=n;i++)
        spfa(i);
    printf(&quot;%.3lf&quot;,dfs(s,e));
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 3143 [Hnoi2013]游走 高斯消元 概率DP</title><link>https://www.nekomio.com/posts/20/</link><guid isPermaLink="true">https://www.nekomio.com/posts/20/</guid><pubDate>Wed, 21 Jun 2017 15:53:46 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;一个无向连通图，顶点从1编号到N，边从1编号到M。
小Z在该图上进行随机游走，初始时小Z在1号顶点，每一步小Z以相等的概率随机选 择当前顶点的某条边，沿着这条边走到下一个顶点，获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束，总分为所有获得的分数之和。
现在，请你对这M条边进行编号，使得小Z获得的总分的期望值最小。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行是正整数N和M，分别表示该图的顶点数 和边数，接下来M行每行是整数u，v(1≤u,v≤N)，表示顶点u与顶点v之间存在一条边。 输入保证30%的数据满足N≤10，100%的数据满足2≤N≤500且是一个无向简单连通图。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;仅包含一个实数，表示最小的期望值，保留3位小数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3  3&lt;br /&gt;
2  3&lt;br /&gt;
1  2&lt;br /&gt;
1  3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3.333&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;用贪心的思想&lt;br /&gt;
要使期望最小 那么可以先求出每条边的期望经过次数&lt;br /&gt;
然后问题就转化成了求每条边的期望经过次数&lt;br /&gt;
可能从u走到v,也可能从v走到u,从u走到v的期望次数等于经过点u的次数/u的度数&lt;br /&gt;
这样就转化成了每个点的期望经过次数&lt;br /&gt;
易得&lt;br /&gt;
$$ f[1]=1+\sum_{j!=n}{f[j]/degree(j)} $$&lt;br /&gt;
$$ f[i]=\sum_{j!=n}{f[j]/degree(j)} (i!=n) $$&lt;/p&gt;
&lt;p&gt;这样就建立了一个n-1元方程组&lt;/p&gt;
&lt;p&gt;高斯消元解就可以了&lt;/p&gt;
&lt;p&gt;代码比较丑&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;cstring&amp;gt;
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;algorithm&amp;gt;
#include&amp;lt;cmath&amp;gt;
using namespace std;
struct edge{
    int END,next;
}v[500005];
int first[505],p,du[505];
void add(int a,int b){
    v[p].END=b;
    v[p].next=first[a];
    first[a]=p++;
}
template&amp;lt;typename T&amp;gt;
int cmp(const T a,const T b){
    return a &amp;gt; b;
}
double a[505][505],x[505],f[500005];
int n,m;
void gauss(){
    int im,num=1;
    for(int k=1;k&amp;lt;=n;k++,num++){
        im=k;
        for(int i=k+1;i&amp;lt;=n;i++)
            if(fabs(a[i][k])&amp;gt;fabs(a[im][k]))
                im=i;
        if(im!=k){
            for(int i=k;i&amp;lt;=n+1;i++)
                swap(a[num][i],a[im][i]);
        }
        if(!a[num][k]){
            num--;continue;
        }
        for(int i=num+1;i&amp;lt;=n;i++){
            if(!a[num][i])continue;
            double t=a[i][k]/a[num][k];
            for(int j=k;j&amp;lt;=n+1;j++){
                a[i][j]-=t*a[k][j];
            }
        }
    }
    for(int i=n;i&amp;gt;=1;i--){
        for(int j=n;j&amp;gt;=i+1;j--){
            a[i][n+1]-=a[i][j]*x[j];
        }
        x[i]=a[i][n+1]/a[i][i];
    }
}
int main()
{
    //freopen(&quot;walk.in&quot;,&quot;r&quot;,stdin);
	//freopen(&quot;walk.out&quot;,&quot;w&quot;,stdout);
    memset(first,-1,sizeof(first));
    scanf(&quot;%d%d&quot;,&amp;amp;n,&amp;amp;m);
    int s,e;
    for(int i=1;i&amp;lt;=m;i++){
        scanf(&quot;%d%d&quot;,&amp;amp;s,&amp;amp;e);
        du[s]++;du[e]++;
        add(s,e);add(e,s);
    }
    n--;
    a[1][n+1]=-1;
    for(int i=1;i&amp;lt;=n;i++){
        a[i][i]=-1;
        for(int j=first[i];j!=-1;j=v[j].next){
            if(v[j].END!=n+1)
                a[i][v[j].END]+=(double)1/(du[v[j].END]);
        }
    }
    gauss();
    for(int i=0;i&amp;lt;p;i++){
        //if(v[i].END!=n+1)
            f[i&amp;gt;&amp;gt;1]+=x[v[i].END]/du[v[i].END];
    }
    //for(int i=0;i&amp;lt;m;i++){
    //    printf(&quot;%lf\n&quot;,f[i+1]);
    //}
    //while(1);
    sort(f,f+m,cmp&amp;lt;double&amp;gt;);
    double ans=0;
    for(int i=0;i&amp;lt;m;i++){
        ans+=f[i]*(i+1);
    }
    printf(&quot;%.3lf&quot;,ans);
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 1778 [Usaco2010 Hol] Dotp 驱逐猪猡 高斯消元 概率期望</title><link>https://www.nekomio.com/posts/19/</link><guid isPermaLink="true">https://www.nekomio.com/posts/19/</guid><pubDate>Mon, 19 Jun 2017 17:12:36 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;奶牛们建立了一个随机化的臭气炸弹来驱逐猪猡。猪猡的文明包含1到N (2 &amp;lt;= N &amp;lt;= 300)一共N个猪城。这些城市由M (1 &amp;lt;= M &amp;lt;= 44,850)条由两个不同端点A_j和B_j (1 &amp;lt;= A_j&amp;lt;= N; 1 &amp;lt;= B_j &amp;lt;= N)表示的双向道路连接。保证城市1至少连接一个其它的城市。一开始臭气弹会被放在城市1。每个小时（包括第一个小时），它有P/Q (1 &amp;lt;= P &amp;lt;=1,000,000; 1 &amp;lt;= Q &amp;lt;= 1,000,000)的概率污染它所在的城市。如果这个小时内它没有污染它所在的城市，那麽它随机地选择一条道路，在这个小时内沿着这条道路走到一个新的城市。可以离开这个城市的所有道路被选择的概率均等。因为这个臭气弹的随机的性质，
&amp;lt;!--more--&amp;gt;
奶牛们很困惑哪个城市最有可能被污染。给定一个猪猡文明的地图和臭气弹在每个小时内爆炸的概率。计算每个城市最终被污染的概率。如下例，假设这个猪猡文明有两个连接在一起的城市。臭气炸弹从城市1出发，每到一个城市，它都有1/2的概率爆炸。 1--2 可知下面这些路径是炸弹可能经过的路径（最后一个城市是臭气弹爆炸的城市）： 1: 1 2: 1-2 3: 1-2-1 4: 1-2-1-2 5: 1-2-1-2-1 ... 要得到炸弹在城市1终止的概率，我们可以把上面的第1，第3，第5……条路径的概率加起来，（也就是上表奇数编号的路径）。上表中第k条路径的概率正好是(1/2)^k，也就是必须在前k-1个回合离开所在城市（每次的概率为1 - 1/2 = 1/2）并且留在最后一个城市（概率为1/2）。所以在城市1结束的概率可以表示为1/2 + (1/2)^3 + (1/2)^5 + ...。当我们无限地计算把这些项一个个加起来，我们最后会恰好得到2/3，也就是我们要求的概率，大约是0.666666667。这意味着最终停留在城市2的概率为1/3，大约为0.333333333。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第1行: 四个由空格隔开的整数: N, M, P, 和 Q * 第2到第M+1行: 第i+1行用两个由空格隔开的整数A_j和B_j表示一条道路。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;第1到第N行: 在第i行，用一个浮点数输出城市i被摧毁的概率。误差不超过10^-6的答桉会 被接受（注意这就是说你需要至少输出6位有效数字使得答桉有效）。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2 1 1 2&lt;br /&gt;
1 2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;p&gt;0.666666667&lt;br /&gt;
0.333333333&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;既可以从概率的方向思考&lt;br /&gt;
也可以从期望的角度考虑&lt;/p&gt;
&lt;h4&gt;期望&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;cmath&amp;gt;
#include&amp;lt;algorithm&amp;gt;
using namespace std;
int mp[305][305],du[305],n;
long double a[305][305],x[305],sum;
void gauss(){
    int im,num=1;
    for(int k=1;k&amp;lt;=n;k++,num++){
        im=k;
        for(int i=k+1;i&amp;lt;=n;i++){
            if(fabs(a[i][k])&amp;gt;fabs(a[im][k]))
                im=i;
        }
        if(im!=k){
            for(int i=k;i&amp;lt;=n+1;i++)
                swap(a[num][i],a[im][i]);
        }
        if(!a[num][k]){
            num--;continue;
        }
        for(int i=num+1;i&amp;lt;=n;i++){
            if(!a[num][k])continue;
            long double t=a[i][k]/a[num][k];
            for(int j=k;j&amp;lt;=n+1;j++){
                a[i][j]-=t*a[k][j];
            }
        }
    }
    for(int i=n;i&amp;gt;=1;i--){
        for(int j=n;j&amp;gt;=i+1;j--){
            a[i][n+1]-=a[i][j]*x[j];
        }
        x[i]=a[i][n+1]/a[i][i];
        sum+=x[i];
    }
}
int main()
{
    freopen(&quot;dotp.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;dotp.out&quot;,&quot;w&quot;,stdout);
    int m,p,q,s,e;
    scanf(&quot;%d%d%d%d&quot;,&amp;amp;n,&amp;amp;m,&amp;amp;p,&amp;amp;q);
    for(int i=1;i&amp;lt;=m;i++){
        scanf(&quot;%d%d&quot;,&amp;amp;s,&amp;amp;e);
        mp[s][e]++;mp[e][s]++;
        du[s]++;du[e]++;
    }
    a[1][n+1]=1;
    for(int i=1;i&amp;lt;=n;i++){
        a[i][i]=1;
        for(int j=1;j&amp;lt;=n;j++){
            if(mp[i][j]){
                a[i][j]+=((long double)p/q-1)/du[j]*mp[i][j];
            }
        }
    }
    gauss();
    for(int i=1;i&amp;lt;=n;i++){
        printf(&quot;%.9lf\n&quot;,(double)(x[i]/sum));
    }
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;概率&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;cmath&amp;gt;
#include&amp;lt;algorithm&amp;gt;
using namespace std;
int mp[305][305],du[305],n;
long double a[305][305],x[305];
void gauss(){
    int im,num=1;
    for(int k=1;k&amp;lt;=n;k++,num++){
        im=k;
        for(int i=k+1;i&amp;lt;=n;i++){
            if(fabs(a[i][k])&amp;gt;fabs(a[im][k]))
                im=i;
        }
        if(im!=k){
            for(int i=k;i&amp;lt;=n+1;i++)
                swap(a[num][i],a[im][i]);
        }
        if(!a[num][k]){
            num--;continue;
        }
        for(int i=num+1;i&amp;lt;=n;i++){
            if(!a[num][k])continue;
            long double t=a[i][k]/a[num][k];
            for(int j=k;j&amp;lt;=n+1;j++){
                a[i][j]-=t*a[k][j];
            }
        }
    }
    for(int i=n;i&amp;gt;=1;i--){
        for(int j=n;j&amp;gt;=i+1;j--){
            a[i][n+1]-=a[i][j]*x[j];
        }
        x[i]=a[i][n+1]/a[i][i];
    }
}
int main()
{
    freopen(&quot;dotp.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;dotp.out&quot;,&quot;w&quot;,stdout);
    int m,p,q,s,e;
    scanf(&quot;%d%d%d%d&quot;,&amp;amp;n,&amp;amp;m,&amp;amp;p,&amp;amp;q);
    for(int i=1;i&amp;lt;=m;i++){
        scanf(&quot;%d%d&quot;,&amp;amp;s,&amp;amp;e);
        mp[s][e]++;mp[e][s]++;
        du[s]++;du[e]++;
    }
    a[1][n+1]=1;
    for(int i=1;i&amp;lt;=n;i++){
        a[i][i]=1;
        for(int j=1;j&amp;lt;=n;j++){
            if(mp[i][j]){
                a[i][j]+=((long double)p/q-1)/du[j]*mp[i][j];
            }
        }
    }
    gauss();
    for(int i=1;i&amp;lt;=n;i++){
        printf(&quot;%.9lf\n&quot;,(double)x[i]);
    }
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 1013 [JSOI2008]球形空间产生器sphere 高斯消元</title><link>https://www.nekomio.com/posts/18/</link><guid isPermaLink="true">https://www.nekomio.com/posts/18/</guid><pubDate>Mon, 19 Jun 2017 16:28:40 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。现在，你被困在了这个n维球体中，你只知道球
面上n+1个点的坐标，你需要以最快的速度确定这个n维球体的球心坐标，以便于摧毁这个球形空间产生器。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行是一个整数n(1&amp;lt;=N=10)。接下来的n+1行，每行有n个实数，表示球面上一点的n维坐标。每一个实数精确到小数点
后6位，且其绝对值都不超过20000。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;有且只有一行，依次给出球心的n维坐标（n个实数），两个实数之间用一个空格隔开。每个实数精确到小数点
后3位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;br /&gt;
0.0 0.0&lt;br /&gt;
-1.0 1.0&lt;br /&gt;
1.0 0.0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;0.500 1.500&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;直接列方程 到每个点距离相等&lt;br /&gt;
手动化简一下 就出来了&lt;/p&gt;
&lt;p&gt;BZOJ 竟然不能多输出一个空格（气）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;cmath&amp;gt;
using namespace std;
double c[20],a[15][15],b[15],x[15],d;
int n;
void gauss(){
    int im,num=1;
    for(int k=1;k&amp;lt;=n;k++,num++){
        im=k;
        for(int i=k+1;i&amp;lt;=n;i++)
            if(fabs(a[i][k])&amp;gt;fabs(a[im][k]))
                im=i;
        if(im!=k){
            for(int i=k;i&amp;lt;=n;i++)
                swap(a[num][i],a[im][i]);
            swap(b[num],b[im]);
        }
        if(!a[num][k]){num--;continue;}
        for(int i=num+1;i&amp;lt;=n;i++){
            if(!a[num][k])continue;
            double t=a[i][k]/a[num][k];
            for(int j=k;j&amp;lt;=n+1;j++){
                a[i][j]-=t*a[k][j];
            }
            b[i]-=t*b[k];
        }
    }
    for(int i=n;i&amp;gt;=1;i--){
        for(int j=n;j&amp;gt;=i+1;j--)
            b[i]-=a[i][j]*x[j];
        x[i]=b[i]/a[i][i];
    }
}
int main()
{
    scanf(&quot;%d&quot;,&amp;amp;n);
    for(int i=1;i&amp;lt;=n;i++)scanf(&quot;%lf&quot;,&amp;amp;c[i]);
    for(int i=1;i&amp;lt;=n;i++){
        for(int j=1;j&amp;lt;=n;j++){
            scanf(&quot;%lf&quot;,&amp;amp;d);
            a[i][j]=d-c[j];
            b[i]+=d*d-c[j]*c[j];
        }
        b[i]/=2;
    }
    gauss();
    for(int i=1;i&amp;lt;n;i++){
        printf(&quot;%.3lf &quot;,x[i]);
    }
    printf(&quot;%.3lf&quot;,x[n]);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[SDOI2007] 线性方程组 高斯消元模板</title><link>https://www.nekomio.com/posts/17/</link><guid isPermaLink="true">https://www.nekomio.com/posts/17/</guid><pubDate>Mon, 19 Jun 2017 16:06:31 GMT</pubDate><content:encoded>&lt;h3&gt;【问题描述】&lt;/h3&gt;
&lt;p&gt;已知 n 元线性一次方程组。&lt;br /&gt;
$$ a_{1,1}x_1+a_{1,2}x_2+…+a_{1,n}x_n=b_1 $$&lt;br /&gt;
$$ a_{2,1}x_1+a_{2,2}x_2+…+a_{2,n}x_n=b_2 $$&lt;br /&gt;
$$…………$$
$$ a_{n,1}x_1+a_{n,2}x_2+…+a_{n,n}x_n=b_n $$&lt;br /&gt;
其中： n&amp;lt;=50．系数是整数，绝对值&amp;lt;=100 , bi的值都是正整数且&amp;lt;300。
编程任务：
根据输入的数据，编程输出方程组的解的情况。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;【输入】&lt;/h3&gt;
&lt;p&gt;第一行，未知数的个数。以下n行n+1列：分别表示每一格方程的系数及方程右边的值。
$$ n $$
$$ a_{1,1} a_{1,2} … a_{1,n} b_1 $$
$$ a_{2,1} a_{2,2} … a_{2,n} b_2 $$
$$…………$$
$$ a_{n,1} a_{n,2} … a_{n,n} b_n $$&lt;/p&gt;
&lt;h3&gt;【输出】&lt;/h3&gt;
&lt;p&gt;如果方程组无实数解输出−1&lt;br /&gt;
如果有无穷多实数解，输出 0&lt;br /&gt;
如果有唯一解,则输出解（小数点后保留两位小数，如果解是0,则不保留小数）&lt;/p&gt;
&lt;h3&gt;【样例输入】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;br /&gt;
2 -1 1 1&lt;br /&gt;
4 1 -1 5&lt;br /&gt;
1 1 1 0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【样例输出】&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;x1=1.00&lt;br /&gt;
x2=0&lt;br /&gt;
x3=-1.00&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;高斯消元板子&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;algorithm&amp;gt;
#include&amp;lt;cmath&amp;gt;
using namespace std;
int n;
double a[200][200],b[200],x[200];
int gauss(){
    int im,num=1;
    for(int k=1;k&amp;lt;=n;k++,num++){
        im=k;
        for(int i=k+1;i&amp;lt;=n;i++){
            if(fabs(a[i][k])&amp;gt;fabs(a[im][k]))
                im=i;
        }
        if(im!=k){
            for(int i=k;i&amp;lt;=n;i++)
                swap(a[num][i],a[im][i]);
            swap(b[num],b[im]);
        }
        if(!a[num][k]) {num--;continue;}
        for(int i=num+1;i&amp;lt;=n;i++){
            if(!a[num][k]) continue;
            double t=a[i][k]/a[num][k];
            for(int j=k;j&amp;lt;=n+1;j++)
                a[i][j]-=t*a[k][j];
            b[i]-=t*b[k];
        }
    }
    for(int i=num;i&amp;lt;=n;i++)
        if(!a[i][n]&amp;amp;&amp;amp;b[i])
            return -1;
    for(int i=n;i&amp;gt;=1;i--){
        for(int j=n;j&amp;gt;=i+1;j--)
            b[i]-=a[i][j]*x[j];
        if(!a[i][i]&amp;amp;&amp;amp;b[i]!=0)
            return -1;
        if(!a[i][i]&amp;amp;&amp;amp;!b[i])
            return 0;
        x[i]=b[i]/a[i][i];
    }
    return 1;
}
int main()
{
    //freopen(&quot;gaess.in&quot;,&quot;r&quot;,stdin);
    //freopen(&quot;gaess.out&quot;,&quot;w&quot;,stdout);
    scanf(&quot;%d&quot;,&amp;amp;n);
    for(int i=1;i&amp;lt;=n;i++){
        for(int j=1;j&amp;lt;=n;j++){
            scanf(&quot;%lf&quot;,&amp;amp;a[i][j]);
        }
        scanf(&quot;%lf&quot;,&amp;amp;b[i]);
    }
    int s=gauss();
    if(s!=1)
        printf(&quot;%d&quot;,s);
    else {
        for(int i=1;i&amp;lt;=n;i++){
            if(x[i]==0)
                printf(&quot;x%d=0\n&quot;,i);
            else{
                printf(&quot;x%d=%.2lf\n&quot;,i,x[i]);
            }
        }
    }
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 2097 [Usaco2010 Dec]Exercise 奶牛健美操 题解 二分答案 树贪心 dfs</title><link>https://www.nekomio.com/posts/16/</link><guid isPermaLink="true">https://www.nekomio.com/posts/16/</guid><pubDate>Sun, 18 Jun 2017 17:14:36 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;Farmer John为了保持奶牛们的健康，让可怜的奶牛们不停在牧场之间 的小路上奔跑。这些奶牛的路径集合可以被表示成一个点集和一些连接 两个顶点的双向路，使得每对点之间恰好有一条简单路径。简单的说来， 这些点的布局就是一棵树，且每条边等长，都为1。 对于给定的一个奶牛路径集合，精明的奶牛们会计算出任意点对路径的最大值， 我们称之为这个路径集合的直径。如果直径太大，奶牛们就会拒绝锻炼。 Farmer John把每个点标记为1..V (2 &amp;lt;= V &amp;lt;= 100,000)。为了获得更加短 的直径，他可以选择封锁一些已经存在的道路，这样就可以得到更多的路径集合， 从而减小一些路径集合的直径。 我们从一棵树开始，FJ可以选择封锁S (1 &amp;lt;= S &amp;lt;= V-1)条双向路，从而获得 S+1个路径集合。你要做的是计算出最佳的封锁方案，使得他得到的所有路径集合 直径的最大值尽可能小。 Farmer John告诉你所有V-1条双向道路，每条表述为：顶点A_i (1 &amp;lt;= A_i &amp;lt;= V) 和 B_i (1 &amp;lt;= B_i &amp;lt;= V; A_i!= B_i)连接。 我们来看看如下的例子：线性的路径集合(7个顶点的树) 1---2---3---4---5---6---7 如果FJ可以封锁两条道路，他可能的选择如下： 1---2 | 3---4 | 5---6---7 这样最长的直径是2，即是最优答案(当然不是唯一的)。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第1行： 两个空格分隔的整数V和S * 第2...V行： 两个空格分隔的整数A_i和B_i&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;第1行：一个整数，表示FJ可以获得的最大的直径。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;7 2&lt;br /&gt;
6 7&lt;br /&gt;
3 4&lt;br /&gt;
6 5&lt;br /&gt;
1 2&lt;br /&gt;
3 2&lt;br /&gt;
4 5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;二分答案
贪心验证&lt;br /&gt;
每次dfs时将子节点到他的dis记录一直删边直到小于mid&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;algorithm&amp;gt;
using namespace std;
int son[100005],mid;
struct edge{
    int END,next;
}v[200005];
int first[100005],p,f[100005],q[100005],tot;
void add(int a,int b){
    v[p].END=b;v[p].next=first[a];first[a]=p++;
    v[p].END=a;v[p].next=first[b];first[b]=p++;
}
int cmp(const int a,const int b){
    return b&amp;lt;a;
}
void dfs(int rt,int fa){
    f[rt]=0;
    for(int i=first[rt];i!=-1;i=v[i].next)
        if(v[i].END!=fa) dfs(v[i].END,rt);
    int cnt=0;q[0]=0;
    for(int i=first[rt];i!=-1;i=v[i].next)
        if(v[i].END!=fa) q[++cnt]=f[v[i].END]+1;
    sort(q+1,q+cnt+1,cmp);
    if(!cnt) return;
    if(cnt==1){
        if(q[1]&amp;gt;mid){
            tot++;
            return;
        }
        else {f[rt]=q[1];return;}
    }
    int i=2;
    while(q[i-1]+q[i]&amp;gt;mid&amp;amp;&amp;amp;i&amp;lt;=cnt){
        tot++;
        i++;
    }
    if(i==cnt+1&amp;amp;&amp;amp;q[i-1]&amp;gt;mid)tot++;
    f[rt]=q[i-1];
}
int main()
{
    memset(first,-1,sizeof(first));
    int n,m;
    scanf(&quot;%d%d&quot;,&amp;amp;n,&amp;amp;m);
    int a,b;
    for(int i=1;i&amp;lt;n;i++){
        scanf(&quot;%d%d&quot;,&amp;amp;a,&amp;amp;b);
        add(a,b);
    }
    //int ans=0;
    int l=1,r=n;
    while(l&amp;lt;r){
        mid=l+r&amp;gt;&amp;gt;1;tot=0;
        dfs(1,0);
        if(tot&amp;lt;=m)r=mid;
        else l=mid+1;
    }
    printf(&quot;%d&quot;,l);
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 3507 [Cqoi2014]通配符匹配 hash 题解</title><link>https://www.nekomio.com/posts/15/</link><guid isPermaLink="true">https://www.nekomio.com/posts/15/</guid><pubDate>Sun, 18 Jun 2017 16:21:32 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户。最常见的通配符有两个，一个
是星号(“”’)，可以匹配0个及以上的任意字符：另一个是问号(“？”)，可以匹配恰好一个任意字符。
现在需要你编写一个程序，对于给定的文件名列表和一个包含通配符的字符串，判断哪些文件可以被匹配。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行是一个由小写字母和上述通配符组成的字符串。&lt;br /&gt;
第二行包含一个整数n，表示文件个数。&lt;br /&gt;
接下来n行，每行为一个仅包含小写字母字符串，表示文件名列表。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;输出n行，每行为“YES”或“NO”，表示对应文件能否被通配符匹配。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;*aca?ctc&lt;br /&gt;
6&lt;br /&gt;
acaacatctc&lt;br /&gt;
acatctc&lt;br /&gt;
aacacatctc&lt;br /&gt;
aggggcaacacctc&lt;br /&gt;
aggggcaacatctc&lt;br /&gt;
aggggcaacctct&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;YES&lt;br /&gt;
YES&lt;br /&gt;
YES&lt;br /&gt;
YES&lt;br /&gt;
YES&lt;br /&gt;
NO&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;将原字符串由&apos;*&apos;分成若干段&lt;br /&gt;
记录每一个&apos;?&apos;的位置&lt;br /&gt;
分段hash
将文件首尾先匹配然后在中间贪心的匹配&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-06-17 10:45:09 
 * @Last Modified by: WildRage
 * @Last Modified time: 2017-06-17 11:09:39
 */
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;algorithm&amp;gt;
#include&amp;lt;vector&amp;gt;
#include&amp;lt;stack&amp;gt;
using namespace std;
#define ULL unsigned long long
const ULL base=31; 
ULL pw[100005],f[15][15],HASH[100005];
int pos[15],cnt,num[15],s[15][15],n,lenth;
char S[100005],a[100005];
ULL get_hash(int l,int r){
    return HASH[r]-HASH[l-1]*pw[r-l+1];
}
bool OK(int i,int k){
    for(int j=0;j&amp;lt;=num[k];j++){
        if(s[k][j]==0){i++;continue;}
        if(f[k][j]!=get_hash(i,i+s[k][j]-1))return 0;
        i+=s[k][j]+1;
    }
    return 1;
}
bool work(char *b){
    int len=strlen(b+1);
    if(!cnt){
        if(lenth!=len)return 0;
        for(int i=1;i&amp;lt;=lenth;i++)
            if(S[i]!=b[i]&amp;amp;&amp;amp;S[i]!=&apos;?&apos;)return 0;
        return 1;
    }
    if(len&amp;lt;(pos[1]-1)+(lenth-pos[cnt]))return 0;
    for(int i=1;i&amp;lt;pos[1];i++)if(S[i]!=b[i]&amp;amp;&amp;amp;S[i]!=&apos;?&apos;)return 0;
    for(int i=lenth,j=len;i&amp;gt;pos[cnt];i--,j--)
        if(S[i]!=b[j]&amp;amp;&amp;amp;S[i]!=&apos;?&apos;)return 0;
    for(int i=1;i&amp;lt;=len;i++) HASH[i]=HASH[i-1]*base+b[i];
    int MAX=len-(lenth-pos[cnt])+1;
    int i=pos[1];
    for(int k=2;k&amp;lt;=cnt;k++){
        while(i&amp;lt;=MAX){
            if(OK(i,k))break;
            i++;
        }
        i+=pos[k]-pos[k-1]-1;
        if(i&amp;gt;MAX) return 0;
    }
    return 1;
}
int main()
{
    //freopen(&quot;match.in&quot;,&quot;r&quot;,stdin);
    //freopen(&quot;match.out&quot;,&quot;w&quot;,stdout);
    scanf(&quot;%s&quot;,S+1);
    lenth=strlen(S+1);
    pw[0]=1;
    cnt=0;
    for(int i=1;i&amp;lt;=100000;i++)pw[i]=pw[i-1]*base;
    for(int i=1;i&amp;lt;=lenth;i++)
        if(S[i]==&apos;*&apos;) 
            pos[++cnt]=i;
    for(int i=2;i&amp;lt;=cnt;i++){
        num[i]=0;
        for(int j=pos[i-1]+1;j&amp;lt;pos[i];j++){
            if(S[j]==&apos;?&apos;){
                num[i]++;
                continue;
            }
            s[i][num[i]]++;
            f[i][num[i]]=f[i][num[i]]*base+S[j];
        }
    }
    scanf(&quot;%d&quot;,&amp;amp;n);
    while(n--){
        scanf(&quot;%s&quot;,a+1);
        if(work(a))puts(&quot;YES&quot;);
        else puts(&quot;NO&quot;);
    }
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 4027 [HEOI2015]兔子与樱花 贪心 dfs</title><link>https://www.nekomio.com/posts/14/</link><guid isPermaLink="true">https://www.nekomio.com/posts/14/</guid><pubDate>Sat, 17 Jun 2017 10:10:22 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;很久很久之前，森林里住着一群兔子。有一天，兔子们突然决定要去看樱花。兔子们所在森林里的樱花树很特殊。樱花树由n个树枝分叉点组成，编号从0到n-1，这n个分叉点由n-1个树枝连接，我们可以把它看成一个有根树结构，其中0号节点是根节点。这个树的每个节点上都会有一些樱花，其中第i个节点有c_i朵樱花。樱花树的每一个节点都有最大的载重m，对于每一个节点i，它的儿子节点的个数和i节点上樱花个数之和不能超过m，即son(i) + c_i &amp;lt;= m，其中son(i)表示i的儿子的个数，如果i为叶子节点，则son(i) = 0
现在兔子们觉得樱花树上节点太多，希望去掉一些节点。当一个节点被去掉之后，这个节点上的樱花和它的儿子节点都被连到删掉节点的父节点上。如果父节点也被删除，那么就会继续向上连接，直到第一个没有被删除的节点为止。
&amp;lt;!--more--&amp;gt;
现在兔子们希望计算在不违背最大载重的情况下，最多能删除多少节点。
注意根节点不能被删除，被删除的节点不被计入载重。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行输入两个正整数，n和m分别表示节点个数和最大载重
第二行n个整数c_i，表示第i个节点上的樱花个数
接下来n行，每行第一个数k_i表示这个节点的儿子个数，接下来k_i个整数表示这个节点儿子的编号&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;一行一个整数，表示最多能删除多少节点。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;10 4&lt;br /&gt;
0 2 2 2 4 1 0 4 1 1&lt;br /&gt;
3 6 2 3&lt;br /&gt;
1 9&lt;br /&gt;
1 8&lt;br /&gt;
1 1&lt;br /&gt;
0&lt;br /&gt;
0&lt;br /&gt;
2 7 4&lt;br /&gt;
0&lt;br /&gt;
1 5&lt;br /&gt;
0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;跑一遍dfs由下到上贪心就好&lt;br /&gt;
选最小的&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;vector&amp;gt;
#include&amp;lt;algorithm&amp;gt;
using namespace std;
vector&amp;lt;int&amp;gt; ch[2000005];
struct Tree{
    int v;
}tree[2000005];
int m,ans;
int cmp(const int a,const int b){
    return tree[a].v&amp;lt;tree[b].v;
}
void dfs(int rt){
    for(int i=0;i&amp;lt;ch[rt].size();i++) dfs(ch[rt][i]);
    sort(ch[rt].begin(),ch[rt].end(),cmp);
    int i;
    for(i=0;i&amp;lt;ch[rt].size();i++){
        if(tree[rt].v+tree[ch[rt][i]].v-1&amp;lt;=m){
            tree[rt].v+=tree[ch[rt][i]].v-1;
            ans++;            
        }
        else break;        
    }
}
int main()
{
    //freopen(&quot;sakura.in&quot;,&quot;r&quot;,stdin);
    //freopen(&quot;sakura.out&quot;,&quot;w&quot;,stdout);
    int n,t,s;
    scanf(&quot;%d%d&quot;,&amp;amp;n,&amp;amp;m);
    for(int i=0;i&amp;lt;n;i++)scanf(&quot;%d&quot;,&amp;amp;tree[i].v);
    for(int i=0;i&amp;lt;n;i++){
        scanf(&quot;%d&quot;,&amp;amp;t);
        tree[i].v+=t;
        while(t--){
            scanf(&quot;%d&quot;,&amp;amp;s);
            ch[i].push_back(s);
        }
    }
    dfs(0);
    printf(&quot;%d\n&quot;,ans);
    //while(1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 4873 [Shoi2017]寿司餐厅 网络流</title><link>https://www.nekomio.com/posts/11/</link><guid isPermaLink="true">https://www.nekomio.com/posts/11/</guid><pubDate>Wed, 14 Jun 2017 16:18:56 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;Kiana最近喜欢到一家非常美味的寿司餐厅用餐。每天晚上，这家餐厅都会按顺序提供n种寿司，第i种寿司有一个
代号ai和美味度di,i，不同种类的寿司有可能使用相同的代号。每种寿司的份数都是无限的，Kiana也可以无限次
取寿司来吃，但每种寿司每次只能取一份，且每次取走的寿司必须是按餐厅提供寿司的顺序连续的一段，即Kiana
可以一次取走第1,2种寿司各一份，也可以一次取走第2,3种寿司各一份，但不可以一次取走第1,3种寿司。由于餐
厅提供的寿司种类繁多，而不同种类的寿司之间相互会有影响：三文鱼寿司和鱿鱼寿司一起吃或许会很棒，但和水
&amp;lt;!--more--&amp;gt;
果寿司一起吃就可能会肚子痛。因此，Kiana定义了一个综合美味度d(i,j)(i&amp;lt;j)，表示在一次取的寿司中，如果包含
了餐厅提供的从第i份到第j份的所有寿司，吃掉这次取的所有寿司后将获得的额外美味度。由于取寿司需要花费一
些时间，所以我们认为分两次取来的寿司之间相互不会影响。注意在吃一次取的寿司时，不止一个综合美味度会被
累加，比如若Kiana一次取走了第1,2,3种寿司各一份，除了d(1,3)以外，d(1,2),d(2,3)也会被累加进总美味度中。神奇
的是，Kiana的美食评判标准是有记忆性的，无论是单种寿司的美味度，还是多种寿司组合起来的综合美味度，在
计入Kiana的总美味度时都只会被累加一次。比如，若Kiana某一次取走了第1,2种寿司各一份，另一次取走了第2,3
种寿司各一份，那么这两次取寿司的总美味度为d(1,1)+d(2,2)+d(3,3)+d(1,2)+d(2,3)，其中d(2,2)只会计算一次。奇怪的是，
这家寿司餐厅的收费标准很不同寻常。具体来说，如果Kiana一共吃过了c(c&amp;gt;0)种代号为x的寿司，则她需要为这些
寿司付出mx^2+cx元钱，其中m是餐厅给出的一个常数。现在Kiana想知道，在这家餐厅吃寿司，自己能获得的总美
味度（包括所有吃掉的单种寿司的美味度和所有被累加的综合美味度）减去花费的总钱数的最大值是多少。由于她
不会算，所以希望由你告诉她&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行包含两个正整数n,m，分别表示这家餐厅提供的寿司总数和计算寿司价格中使用的常数。
第二行包含n个正整数，其中第k个数ak表示第k份寿司的代号。
接下来n行，第i行包含n-i+1个整数，其中第j个数d(i,i+j-1)表示吃掉寿司能
获得的相应的美味度，具体含义见问题描述。
N&amp;lt;=100,Ai&amp;lt;=1000&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;输出共一行包含一个正整数，表示Kiana能获得的总美味度减去花费的总钱数的最大值。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3 1&lt;br /&gt;
2 3 2&lt;br /&gt;
5 -10 15&lt;br /&gt;
-10 15&lt;br /&gt;
15&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;12&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;将区间看做点
每个[i,j]区间只要向[i+1,j],[i,j-1]连边&lt;br /&gt;
转换为最大权闭合子图&lt;br /&gt;
现在最麻烦的是解决每个点的权值&lt;br /&gt;
将单个的点即[i,j] (i==j)每个点的美味度减去它的代号(解决cm)向 Idx[a[i]]连边 Idx[]用来限制第一次吃的额外的花费&lt;/p&gt;
&lt;p&gt;剩下的就和标准的最大权闭合子图一样了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;iostream&amp;gt;
#include&amp;lt;queue&amp;gt;
using namespace std;
const int INF=0x7fffffff;
int idIndex;
int read(){
    int res=0;
    static char ch;int flag=1;
	while((ch=getchar())&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;)if(ch==&apos;-&apos;)flag=-1;res=ch-48;
	while((ch=getchar())&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;)res=(res&amp;lt;&amp;lt;1)+(res&amp;lt;&amp;lt;3)+ch-48;
    return res*flag;
}
struct edge{
    int END,next,cap;
}v[1000005];
int first[10005],p;
void add(int a,int b,int c){
    v[p].END=b;v[p].next=first[a];v[p].cap=c;first[a]=p++;
    v[p].END=a;v[p].next=first[b];v[p].cap=0;first[b]=p++;
}
int a[150];
int Idx[1005],id[150][150];
int dis[10005],cur[10005];
bool vis[10005];
bool BFS(int S,int E){
    memset(dis,-1,sizeof(dis));
    memset(vis,0,sizeof(vis));
    vis[S]=1;dis[S]=0;
    queue&amp;lt;int&amp;gt; Q;
    Q.push(S);
    while(!Q.empty()){
        int u=Q.front();Q.pop();
        for(int i=first[u];i!=-1;i=v[i].next){
            if(!vis[v[i].END]&amp;amp;&amp;amp;v[i].cap&amp;gt;0){
                vis[v[i].END]=1;
                dis[v[i].END]=dis[u]+1;
                if(v[i].END==E)return 1;
                Q.push(v[i].END);
            }
        }
    }
    return 0;
}
int DFS(int S,int E,int a){
    if(S==E||a==0)return a;
    int flow=0,f;
    for(int &amp;amp;i=cur[S];i!=-1;i=v[i].next){
        if(dis[v[i].END]==dis[S]+1&amp;amp;&amp;amp;(f=DFS(v[i].END,E,min(a,v[i].cap)))&amp;gt;0){
            v[i].cap-=f;
            v[i^1].cap+=f;
            a-=f;
            flow+=f;
            if(f==0)break;
        }
    }
    //
    if(!flow) dis[S]=-1;
    return flow; 
}
int Dinic(int S,int E){
    int ans=0;
    while(BFS(S,E)){
        memcpy(cur,first,sizeof(first));
        ans+=DFS(S,E,INF);
    }
    return ans;
}
int main()
{
    int n,m;
    memset(first,-1,sizeof(first));
    scanf(&quot;%d%d&quot;,&amp;amp;n,&amp;amp;m);
    int S=++idIndex,T=++idIndex;
    int maxn=0;
    for(int i=1;i&amp;lt;=n;i++) maxn=max(maxn,a[i]=read());
    for(int i=1;i&amp;lt;=maxn;i++){
        Idx[i]=++idIndex;
        add(Idx[i],T,m*i*i);
    }
    for(int i=1;i&amp;lt;=n;i++)for(int j=i;j&amp;lt;=n;j++)id[i][j]=++idIndex;
    int x;
    int ans=0;
    for(int i=1;i&amp;lt;=n;i++){
        for(int j=i;j&amp;lt;=n;j++){
            x=read();
            if(i==j)x-=a[i],add(id[i][j],Idx[a[i]],INF);
            else {
                if(id[i+1][j])add(id[i][j],id[i+1][j],INF);
                if(id[i][j-1])add(id[i][j],id[i][j-1],INF);
            }
            if(x&amp;gt;0) ans+=x,add(S,id[i][j],x);
            else add(id[i][j],T,-x);
        }
    }
    ans-=Dinic(S,T);
    printf(&quot;%d\n&quot;,ans);
    getchar();
    getchar();
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 1901 Dynamic Rankings 线段树套Treap</title><link>https://www.nekomio.com/posts/12/</link><guid isPermaLink="true">https://www.nekomio.com/posts/12/</guid><pubDate>Wed, 14 Jun 2017 16:18:56 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;给定一个含有n个数的序列a[1],a[2],a[3]……a[n]，程序必须回答这样的询问：对于给定的i,j,k，在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1)，并且，你可以改变一些a[i]的值，改变后，程序还能针对改变后的a继续回答上面的问题。你需要编一个这样的程序，从输入文件中读入序列a，然后读入一系列的指令，包括询问指令和修改指令。对于每一个询问指令，你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000)，m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数，表示a[1],a[2]……a[n]，这些数都小于10^9。接下来的m行描述每条指令，每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k （i,j,k是数字，1≤i≤j≤n, 1≤k≤j-i+1）表示询问指令，询问a[i]，a[i+1]……a[j]中第k小的数。C i t (1≤i≤n，0≤t≤10^9)表示把a[i]改变成为t。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;对于每一次询问，你都需要输出他的答案，每一个输出占单独的一行。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;5 3&lt;br /&gt;
3 2 1 4 7&lt;br /&gt;
Q 1 4 3&lt;br /&gt;
C 2 6&lt;br /&gt;
Q 2 5 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;br /&gt;
6&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;区间k大+修改&lt;br /&gt;
直接树套树&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;algorithm&amp;gt;
using namespace std;
int a[10005],n;
class Treap{
    class Node{
    public:
        int size,v,key;
        Node *ch[2];
        Node(int x){
            key=rand();v=x;size=1;
            ch[0]=ch[1]=NULL;
        }
        #define size(_) ((_)?(_)-&amp;gt;size:0)
        void Pushup(){
            size=size(ch[0])+size(ch[1])+1;
        }
    }*root;
    Node *Merge(Node *A,Node *B){
        if(!A)return B;
        if(!B)return A;
        if(A-&amp;gt;key&amp;gt;B-&amp;gt;key){
            A-&amp;gt;ch[1]=Merge(A-&amp;gt;ch[1],B);
            A-&amp;gt;Pushup();
            return A;
        }
        else {
            B-&amp;gt;ch[0]=Merge(A,B-&amp;gt;ch[0]);
            B-&amp;gt;Pushup();
            return B;
        }
    }
    typedef pair&amp;lt;Node*,Node*&amp;gt; DNode;
    DNode Split(Node *rt,int k){
        if(!rt)return DNode(NULL,NULL);
        DNode o;
        if(size(rt-&amp;gt;ch[0])&amp;gt;=k){
            o=Split(rt-&amp;gt;ch[0],k);
            rt-&amp;gt;ch[0]=o.second;
            rt-&amp;gt;Pushup();
            o.second=rt;
        }
        else{
            o=Split(rt-&amp;gt;ch[1],k-size(rt-&amp;gt;ch[0])-1);
            rt-&amp;gt;ch[1]=o.first;
            rt-&amp;gt;Pushup();
            o.first=rt;
        }
        return o;
    }
public:
    Treap(){
        root=NULL;
    }
    int kth(int k){
        DNode x=Split(root,k-1);
        DNode y=Split(x.second,1);
        Node *ans=y.first;
        root=Merge(x.first,Merge(y.first,y.second));
        return ans-&amp;gt;v;
    }
    int rank(int x){
        return rank(root,x);
    }
    int rank(Node *rt,int x){
        if(!rt)return 0;
        return x&amp;lt;=rt-&amp;gt;v?rank(rt-&amp;gt;ch[0],x):rank(rt-&amp;gt;ch[1],x)+size(rt-&amp;gt;ch[0])+1;
    }
    void Insert(int x){
        int k=rank(root,x);
        DNode y=Split(root,k);
        Node *n=new Node(x);
        root=Merge(Merge(y.first,n),y.second);
    }
    void remove(int x){
        int k=rank(root,x);
        DNode a=Split(root,k);
        DNode b=Split(a.second,1);
        root=Merge(a.first,b.second);
    }
}root[40000];
#define lch l,m,rt&amp;lt;&amp;lt;1
#define rch m+1,r,rt&amp;lt;&amp;lt;1|1 

void build(int l,int r,int rt){
    for(int i=l;i&amp;lt;=r;i++) root[rt].Insert(a[i]);
}
void buildtree(int l,int r,int rt){
    build(l,r,rt);
    if(l==r)return;
    int m=l+r&amp;gt;&amp;gt;1;
    buildtree(lch);
    buildtree(rch);
}
void updata(int k,int x,int y,int l,int r,int rt){
    root[rt].remove(y);
    root[rt].Insert(x);
    if(l==r)return;
    int m=l+r&amp;gt;&amp;gt;1;
    if(k&amp;lt;=m) updata(k,x,y,lch);
    else updata(k,x,y,rch);
}
int rank(int L,int R,int x,int l,int r,int rt){
    if(L&amp;lt;=l&amp;amp;&amp;amp;R&amp;gt;=r)return root[rt].rank(x);
    int m=l+r&amp;gt;&amp;gt;1;
    if(R&amp;lt;=m)return rank(L,R,x,lch);
    if(L&amp;gt;m) return rank(L,R,x,rch);
    return rank(L,R,x,lch)+rank(L,R,x,rch);
}
int kth(int L,int R,int k){
    int l=-1e10,r=1e10;
    while(l&amp;lt;=r){
        int m=l+r&amp;gt;&amp;gt;1;
        int num=rank(L,R,m,1,n,1)+1;
        if(num&amp;lt;=k)l=m+1;
        else r=m-1;
    }
    return r;
}
int main()
{   
    int m;
    scanf(&quot;%d%d&quot;,&amp;amp;n,&amp;amp;m);
    for(int i=1;i&amp;lt;=n;i++)scanf(&quot;%d&quot;,&amp;amp;a[i]);
    buildtree(1,n,1);
    char s[5];int i,j,k,t;
    while(m--){
        scanf(&quot;%s&quot;,s);
        if(s[0]==&apos;Q&apos;){
            scanf(&quot;%d%d%d&quot;,&amp;amp;i,&amp;amp;j,&amp;amp;k);
            printf(&quot;%d\n&quot;,kth(i,j,k));
        }
        else{
            scanf(&quot;%d%d&quot;,&amp;amp;i,&amp;amp;t);
            updata(i,t,a[i],1,n,1);
            a[i]=t;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 3172 [Tjoi2013]单词 fail tree</title><link>https://www.nekomio.com/posts/13/</link><guid isPermaLink="true">https://www.nekomio.com/posts/13/</guid><pubDate>Wed, 14 Jun 2017 16:18:56 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;某人读论文，一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次，现在想知道每个单词分别在论文中出现多少次。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一个一个整数N,表示有多少个单词，接下来N行每行一个单词。每个单词由小写字母组成，N&amp;lt;=200,单词长度不超过10^6&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;输出N个整数，第i行的数字表示第i个单词在文章中出现了多少次。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;br /&gt;
a&lt;br /&gt;
aa&lt;br /&gt;
aaa&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;6&lt;br /&gt;
3&lt;br /&gt;
1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;fail 树
照着打个板子&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;queue&amp;gt;
using namespace std;
char S[1000005];
int Index;
struct Trie{
    Trie *ch[26];
    Trie *fail;
    int id,num;
    Trie(){memset(ch,0,sizeof(ch));fail=NULL;fail=0;num=0;id=++Index;}
}*root,*word[220];
void insert(char *s,int x){
    int len=strlen(s);
    Trie *now=root;
    for(int i=0;i&amp;lt;len;i++){
        if(!now-&amp;gt;ch[s[i]-&apos;a&apos;])now-&amp;gt;ch[s[i]-&apos;a&apos;]=new Trie();
        now=now-&amp;gt;ch[s[i]-&apos;a&apos;];
        now-&amp;gt;num++;
    }
    word[x]=now;
}
struct edge{
    Trie *END;edge *next;
}*first[26000500];
void add(Trie *a,Trie *b){
    edge *k=new edge;
    k-&amp;gt;END=b;
    k-&amp;gt;next=first[a-&amp;gt;id];
    first[a-&amp;gt;id]=k;
}
void get_fail(){
    queue&amp;lt;Trie*&amp;gt; Q;
    Trie *now=root,*temp;
    Q.push(now);
    while(!Q.empty()){
        temp=Q.front();Q.pop();
        for(int i=0;i&amp;lt;26;i++){
            if(temp-&amp;gt;ch[i]){
                if(temp==root){
                    temp-&amp;gt;ch[i]-&amp;gt;fail=root;
                    add(root,temp-&amp;gt;ch[i]);
                }
                else{
                    now=temp-&amp;gt;fail;
                    while(now&amp;amp;&amp;amp;now-&amp;gt;ch[i]==NULL) now=now-&amp;gt;fail;
                    if(now==NULL)add(root,temp-&amp;gt;ch[i]),temp-&amp;gt;ch[i]-&amp;gt;fail=root;
                    else add(now-&amp;gt;ch[i],temp-&amp;gt;ch[i]),temp-&amp;gt;ch[i]-&amp;gt;fail=now-&amp;gt;ch[i];
                }
                Q.push(temp-&amp;gt;ch[i]);
            }
        }
    }
}
void dfs(Trie *rt){
    for(edge *now=first[rt-&amp;gt;id];now;now=now-&amp;gt;next){
        dfs(now-&amp;gt;END);
        rt-&amp;gt;num+=now-&amp;gt;END-&amp;gt;num;
    }
}
int main()
{
    int n;
    root=new Trie();
    scanf(&quot;%d&quot;,&amp;amp;n);
    for(int i=1;i&amp;lt;=n;i++){
        scanf(&quot;%s&quot;,S);
        insert(S,i);
    }
    get_fail();
    dfs(root);
    for(int i=1;i&amp;lt;=n;i++){
        printf(&quot;%d\n&quot;,word[i]-&amp;gt;num);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 4318 OSU! 概率DP</title><link>https://www.nekomio.com/posts/10/</link><guid isPermaLink="true">https://www.nekomio.com/posts/10/</guid><pubDate>Wed, 14 Jun 2017 08:22:14 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;osu 是一款群众喜闻乐见的休闲软件。
我们可以把osu的规则简化与改编成以下的样子:
一共有n次操作，每次操作只有成功与失败之分，成功对应1，失败对应0，n次操作对应为1个长度为n的01串。在这个串中连续的 X个1可以贡献X^3 的分数，这x个1不能被其他连续的1所包含（也就是极长的一串1，具体见样例解释）
现在给出n，以及每个操作的成功率，请你输出期望分数，输出四舍五入后保留1位小数。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行有一个正整数n,表示操作个数。接下去n行每行有一个[0,1]之间的实数，表示每个操作的成功率。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;只有一个实数，表示答案。答案四舍五入后保留1位小数。&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;br /&gt;
0.5&lt;br /&gt;
0.5&lt;br /&gt;
0.5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;6.0&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【样例说明】&lt;/h3&gt;
&lt;p&gt;000分数为0，001分数为1，010分数为1，100分数为1，101分数为2，110分数为8，011分数为8，111分数为27，总和为48，期望为48/8=6.0&lt;br /&gt;
N&amp;lt;=100000&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;考虑前面以确定，第i位如果为1则贡献为 $$(x+1)^3-x^3=3&lt;em&gt;x^2+3&lt;/em&gt;x+1$$&lt;br /&gt;
维护$$x^2,x$$就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
using namespace std;
double x[100005],x2[100005],f[100005];
int main()
{
    int n;
    double a;
    scanf(&quot;%d&quot;,&amp;amp;n);
    for(int i=1;i&amp;lt;=n;i++){
        scanf(&quot;%lf&quot;,&amp;amp;a);
        x[i]=(x[i-1]+1)*a;
        x2[i]=(x2[i-1]+2*x[i-1]+1)*a;
        f[i]=f[i-1]+(3*x2[i-1]+3*x[i-1]+1)*a;
    }
    printf(&quot;%.1f&quot;,f[n]);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>BZOJ 1426 收集邮票</title><link>https://www.nekomio.com/posts/9/</link><guid isPermaLink="true">https://www.nekomio.com/posts/9/</guid><pubDate>Wed, 14 Jun 2017 08:22:14 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;有n种不同的邮票，皮皮想收集所有种类的邮票。唯一的收集方法是到同学凡凡那里购买，每次只能买一张，并且买到的邮票究竟是n种邮票中的哪一种是等概率的，概率均为1/n。但是由于凡凡也很喜欢邮票，所以皮皮购买第k张邮票需要支付k元钱。 现在皮皮手中没有邮票，皮皮想知道自己得到所有种类的邮票需要花费的钱数目的期望。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;一行,一个数字N N&amp;lt;=10000&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;要付出多少钱. 保留二位小数&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;21.25&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;首先考虑每张邮票1元钱，f[i]为当前有i张邮票，要集齐n种邮票的期望花费.
$$f[i]=i/n&lt;em&gt;f[i]+(n-i)/n&lt;/em&gt;f[i+1]+1$$当花费为k时
g[i]为当前有i张邮票,要集齐n种邮票的期望花费。&lt;br /&gt;
我们可以认为买的最后一张邮票的花费为1,倒数第k张的花费为k。
这样
$$g[i]=i/n*(g[i]+f[i]+1)+(n-i)/n*(g[i+1]+f[i+1]+1)$$化简后就可以O(n)递推了.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-06-14 08:15:56 
 * @Last Modified by: WildRage
 * @Last Modified time: 2017-06-14 08:19:55
 */
#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
using namespace std;
double f[10005],g[10005];
int main()
{
    int n;
    scanf(&quot;%d&quot;,&amp;amp;n);
    for(int i=n-1;i&amp;gt;=0;i--)f[i]=f[i+1]+(double)n/(n-i);
    for(int i=n-1;i&amp;gt;=0;i--)g[i]=(double)i/(n-i)*f[i]+g[i+1]+f[i+1]+(double)n/(n-i);
    printf(&quot;%.2f&quot;,g[0]);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>网络流24题 太空飞行计划</title><link>https://www.nekomio.com/posts/8/</link><guid isPermaLink="true">https://www.nekomio.com/posts/8/</guid><pubDate>Wed, 14 Jun 2017 07:10:14 GMT</pubDate><content:encoded>&lt;h3&gt;【问题描述】&lt;/h3&gt;
&lt;p&gt;W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em}，和进行这些实验需要使用的全部仪器的集合I={ I1, I2,…,In }。实验Ej 需要用到的仪器是I的子集Rj∈I。配置仪器Ik 的费用为ck 美元。实验Ej 的赞助商已同意为该实验结果支付pj 美元。W教授的任务是找出一个有效算法，确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;【编程任务】&lt;/h3&gt;
&lt;p&gt;对于给定的实验和仪器配置情况，编程找出净收益最大的试验计划。&lt;/p&gt;
&lt;h3&gt;【数据输入】&lt;/h3&gt;
&lt;p&gt;第1行有2个正整数m和n(m,n &amp;lt;= 100)。m是实验数，n是仪器数。接下来的m行，每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费用；接着是该实验需要用到的若干仪器的编号。最后一行的n个数是配置每个仪器的费用。&lt;/p&gt;
&lt;h3&gt;【结果输出】&lt;/h3&gt;
&lt;p&gt;第1行是实验编号；第2行是仪器编号；最后一行是净收益。&lt;/p&gt;
&lt;h3&gt;【输入文件示例】shuttle.in&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2 3&lt;br /&gt;
10 1 2&lt;br /&gt;
25 2 3&lt;br /&gt;
5 6 7&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;【输出文件示例】shuttle.out&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;1 2&lt;br /&gt;
1 2 3&lt;br /&gt;
17&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;最大权闭合子图
很裸的题，复习一下板子&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-06-13 21:23:24 
 * @Last Modified by: WildRage
 * @Last Modified time: 2017-06-13 21:48:22
 */
#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;queue&amp;gt;
using namespace std;
const int INF=0x7fffffff;
struct edge{
    int END,next,cap;
}v[100005];
int first[1005],p;
void add(int a,int b,int c){
    v[p].END=b;v[p].next=first[a];v[p].cap=c;first[a]=p++;
    v[p].END=a;v[p].next=first[b];v[p].cap=0;first[b]=p++;
}
int cur[1005],dis[1005];
bool vis[1005];
bool BFS(int S,int E){
    memset(vis,0,sizeof(vis));
    memset(dis,-1,sizeof(dis));
    queue&amp;lt;int&amp;gt; Q;
    Q.push(S);
    dis[S]=0;vis[S]=1;
    while(!Q.empty()){
        int u=Q.front();Q.pop();
        for(int i=first[u];i!=-1;i=v[i].next){
            if(!vis[v[i].END]&amp;amp;&amp;amp;v[i].cap&amp;gt;0){
                vis[v[i].END]=1;
                dis[v[i].END]=dis[u]+1;
                if(v[i].END==E)return 1;
                Q.push(v[i].END);
            }
        }
    }
    return 0;
}
int DFS(int S,int E,int a){
    if(S==E||a==0)return a;
    int flow=0,f;
    for(int i=first[S];i!=-1;i=v[i].next){
        if(dis[S]+1==dis[v[i].END]&amp;amp;&amp;amp;(f=DFS(v[i].END,E,min(a,v[i].cap)))&amp;gt;0){
            v[i].cap-=f;
            v[i^1].cap+=f;
            flow+=f;
            a-=f;
        }
    }
    if(!flow)dis[S]=-1;
    return flow;
}
int Dinic(int S,int E){
    int ans=0;
    while(BFS(S,E)){
        ans+=DFS(S,E,INF);
    }
    //printf(&quot;%d\n&quot;,ans);
    //while(1);
    return ans;
}
int Main()
{
    memset(first,-1,sizeof(first));
    int n,m;
    freopen(&quot;shuttle.in&quot;,&quot;r&quot;,stdin);
	freopen(&quot;shuttle.out&quot;,&quot;w&quot;,stdout);
    scanf(&quot;%d%d&quot;,&amp;amp;n,&amp;amp;m);
    int ans=0;
    char ch;
    for(int x,i=1;i&amp;lt;=n;i++){
        scanf(&quot;%d&quot;,&amp;amp;x);ans+=x;
        add(0,i,x);
        while(1){
            while((ch=getchar())==&apos; &apos;);
            ungetc(ch,stdin);
            if(ch==&apos;\n&apos;||ch==&apos;\r&apos;)break;
            scanf(&quot;%d&quot;,&amp;amp;x);
            add(i,x+n,INF);
        }
    }
    for(int x,i=1;i&amp;lt;=m;i++){
        scanf(&quot;%d&quot;,&amp;amp;x);
        add(i+n,m+n+1,x);
    }
    ans=ans-Dinic(0,n+m+1);
    for(int i=1;i&amp;lt;=n;i++)
        if(dis[i]&amp;gt;=0)
            printf(&quot;%d &quot;,i);
    puts(&quot;&quot;);
    for(int i=1;i&amp;lt;=m;i++)
        if(dis[i+n]&amp;gt;=0)
            printf(&quot;%d &quot;,i);
    puts(&quot;&quot;);
    printf(&quot;%d\n&quot;,ans);
    return 0;
}
int Wild=Main();
int main(){;}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[COGS 2248] 情书 AC自动机模板</title><link>https://www.nekomio.com/posts/7/</link><guid isPermaLink="true">https://www.nekomio.com/posts/7/</guid><pubDate>Tue, 13 Jun 2017 19:45:56 GMT</pubDate><content:encoded>&lt;h3&gt;【题目描述】&lt;/h3&gt;
&lt;p&gt;John平静的生活最近有了波澜：他已经连续n天受到陌生人的情书了。小小的心中充满了憧憬，但是某些人觉得有乐子可以找，决定伪造情书。John总结出了那个陌生人写信的习惯，也就是某些关键的字符串。如果一封信中这若干个关键字符串都出现，他就认为这是那个陌生人写的，否则就是他同学的恶作剧。注意，John可能收到多封情书。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;第一行一个整数n，表示关键字符串的个数，n&amp;lt;=100。&lt;br /&gt;
接下来n行，每行为一个长度不超过100的字符串。
最后是若干段文本，每段文本以 $ 结尾。&lt;br /&gt;
由于写情书的人太疯狂，每封情书最长可以达到1350000个字符，但情书的个数不超过10。&lt;/p&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;对于每一段文本对应一行输出。&lt;br /&gt;
‘Yes’表示是陌生人的来信，‘No’表示不是。&lt;br /&gt;
请注意大小写。&lt;/p&gt;
&lt;h3&gt;【样例输入】&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;3
i
love
wzk
ilovewzk$
lovewzk$
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;【样例输出】&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Yes
No
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;AC自动机板子&lt;br /&gt;
感谢&lt;a href=&quot;http://www.cnblogs.com/TSHugh/&quot;&gt;TS_Hugh&lt;/a&gt;
,
&lt;a href=&quot;http://www.cnblogs.com/LadyLex/&quot;&gt;LadyLex&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;vector&amp;gt;
using namespace std;
char text[1350005];
int n;
struct Trie{
    vector&amp;lt;int&amp;gt; Q;
    Trie *ch[26],*fail;
    Trie(){
        Q.clear();memset(ch,0,sizeof(ch));fail=NULL;
    }
    void* operator new(size_t size);
}*root,*C,*num,*Q[100005];
void* Trie::operator new(size_t size){
    if(C==num){
        C=new Trie[1&amp;lt;&amp;lt;15];
        num=C+(1&amp;lt;&amp;lt;15);
    }
    return C++;
}
void insert(char *s,int x){
    int len=strlen(s);
    Trie *now=root;
    for(int i=0;i&amp;lt;len;i++){
        if(now-&amp;gt;ch[s[i]-&apos;a&apos;]==NULL)now-&amp;gt;ch[s[i]-&apos;a&apos;]=new Trie();
        now=now-&amp;gt;ch[s[i]-&apos;a&apos;];
    }
    now-&amp;gt;Q.push_back(x);
}
void build()
{
    root-&amp;gt;fail=NULL;
    Q[0]=root;
    for(int i=0,j=0;i&amp;lt;=j;i++){
        for(int l=0;l&amp;lt;26;l++){
            if(Q[i]-&amp;gt;ch[l]){
                Trie *now=Q[i]-&amp;gt;fail;
                while(now&amp;amp;&amp;amp;!now-&amp;gt;ch[l])now=now-&amp;gt;fail;
                Q[i]-&amp;gt;ch[l]-&amp;gt;fail=now?now-&amp;gt;ch[l]:root;
                Q[++j]=Q[i]-&amp;gt;ch[l];
            }
        }
    }
}
bool read(){
    char c;
    int head=0;
    if(cin&amp;gt;&amp;gt;c){
        while(c!=&apos;$&apos;){
            if(c==&apos;\n&apos;||c==&apos; &apos;){c=getchar();continue;}
            text[head++]=c;c=getchar();
        }
        text[head++]=&apos;$&apos;;
        return 1;
    }
    return 0;
}
bool via[105];
void work(){
    memset(via,0,sizeof(via));
    Trie *now=root;
    for(int i=0;text[i]!=&apos;$&apos;;i++){
        while(now&amp;amp;&amp;amp;!now-&amp;gt;ch[text[i]-&apos;a&apos;])now=now-&amp;gt;fail;
        now=now?now-&amp;gt;ch[text[i]-&apos;a&apos;]:root;
        for(Trie *i=now;i;i=i-&amp;gt;fail){
            if(!i-&amp;gt;Q.empty()){
                int l=i-&amp;gt;Q.size();
                for(int j=0;j&amp;lt;l;j++)via[i-&amp;gt;Q[j]]=1;
            }
        }
    }
    int ans=0;
    for(int i=1;i&amp;lt;=n;i++)if(via[i])ans++;
    if(ans==n)puts(&quot;Yes&quot;);
    else puts(&quot;No&quot;);
}
int main()
{
    freopen(&quot;lettera.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;lettera.out&quot;,&quot;w&quot;,stdout);
    root=new Trie();
    char s[1000];
    scanf(&quot;%d&quot;,&amp;amp;n);
    for(int i=1;i&amp;lt;=n;i++){
        scanf(&quot;%s&quot;,s);
        insert(s,i);
    }
    build();
    while(read()) work();
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BZOJ 4523][Cqoi2016]路由表 Trie树 单调栈</title><link>https://www.nekomio.com/posts/6/</link><guid isPermaLink="true">https://www.nekomio.com/posts/6/</guid><pubDate>Tue, 13 Jun 2017 17:35:35 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;路由表查找是路由器在转发IP报文时的重要环节。通常路由表中的表项由目的地址、掩码、下一跳（Next Hop）地址和其他辅助信息组成。例如：
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593fb6d8c246d.png&quot; alt=&quot;&quot; /&gt;
当路由器收到一个IP报文时，会将报文中的目的IP地址与路由表中的表项逐条进行比较，选
择匹配且最明确的表项，将报文转发给该表项中指定的下一跳。
&amp;lt;!--more--&amp;gt;
匹配的过程是将报文中的目的地址和表项中的目的地址分别转为二进制串，再查看表项中的掩
码长度，若掩码长度为x，则将两个二进制串的前x位进行比较，如果相同则认为匹配。
所谓最明确是指在有多个表项匹配时，总是掩码长度最大的表项。也可以理解为匹配的二进制
位最多的项。
IP地址转为二进制串的操作是把地址中4个整数（一定在y到255的范围内）分别转为8位
二进制数，再顺序拼接起来，得到一个32位的二进制串。例如，192.168.1.253转为二进制串后为
11000000 10101000 00000001 11111101
我们以报文的目的地址为8.8.8.8为例，说明其在上述路由表的匹配过程。
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593fb701c18ab.png&quot; alt=&quot;&quot; /&gt;
上表将地址均转为二进制串，并用红色标记出待比较的位（由掩码长度决定）。将红色部分与
报文中的目的地址比较，可知0.0.0.0/1、8.8.8.0/24、8.8.8.8、32均能够匹配。路由器从中选取掩
码长度最长（/32）的表项8.8.8.8/32，将报文转发给其对应的下一跳地址192.168.1.253。
在实际的核心路由器中，路由表通常较大（现在互联网的全局路由表已经接60万条记录），
并且会随着新接入设备不断扩张。为了分析路由表变化对转发产生的影响，网络工程师想要知道
一段时间内某个IP地址的路由表项选择发生了多少次变化（变化是指由于最明确匹配等因素选择
了不同的表项，不考虑下一跳地址）。&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;第一行为整数M，表示共有M次操作。接下来M行，每行描述一次操作。操作有两种：&lt;br /&gt;
A D/L&lt;br /&gt;
其中.为一个IP地址，G为整数（1≤L≤32）。添加一条表项至路由表，其目的地址为  D掩码长度为L。下一跳地址由于没有用到，故省略。&lt;br /&gt;
Q D a b&lt;br /&gt;
其中D为一个IP地址，a,b为正整数（a≤b）。查询从第a次至第b次添加表项期间（含a、b），&lt;br /&gt;
目的地址D的路由表项选择发生了多少次变化。保证查询时表中至少有b个表项。&lt;br /&gt;
N&amp;lt;=10^6数据保证不会重复添加目的地址和掩码长度都相同的表项。&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;包含若干行，每行仅有一个整数，依次对应每个查询操作。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.lydsy.com/JudgeOnline/problem.php?id=4523&quot;&gt;题面&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;以要查询的IP建一颗Trie树在终止节点打一个时间标记&lt;br /&gt;
每次查询用单调栈维护&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-06-13 17:54:04 
 * @Last Modified by:   WildRage 
 * @Last Modified time: 2017-06-13 17:54:04 
 */
#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;cstdio&amp;gt;
using namespace std;
struct Trie{
    int T;
    Trie *ch[2];
    void *operator new (size_t size);
}*root,*num,*C;
void* Trie::operator new(size_t size){
    if(C==num){
        C=new Trie[1&amp;lt;&amp;lt;10];
        memset(C,0,sizeof(Trie)*(1&amp;lt;&amp;lt;10));
        num=C+(1&amp;lt;&amp;lt;10);
    }
    return C++;
}
int Index=0,cnt;
void insert(char *s){
    Trie *now=root;
    for(int i=0;i&amp;lt;cnt;i++){
        if(now-&amp;gt;ch[s[i]-&apos;0&apos;]==NULL)now-&amp;gt;ch[s[i]-&apos;0&apos;]=new Trie;
        now=now-&amp;gt;ch[s[i]-&apos;0&apos;];
    }
    now-&amp;gt;T=++Index;
}
int st[10005];
int query(char *s,int l,int r){
    int h=0;
    Trie *now=root;
    for(int i=0;i&amp;lt;cnt;i++){
        if(now-&amp;gt;ch[s[i]-&apos;0&apos;]==NULL)break;
        now=now-&amp;gt;ch[s[i]-&apos;0&apos;];
        if(!now-&amp;gt;T)continue;
        if(now-&amp;gt;T&amp;gt;r)continue;
        if(now-&amp;gt;T&amp;lt;l)while(h&amp;gt;=1)h--;
        if(now-&amp;gt;T&amp;gt;=l&amp;amp;&amp;amp;now-&amp;gt;T&amp;lt;=r){
            while(h&amp;gt;=1&amp;amp;&amp;amp;now-&amp;gt;T&amp;lt;st[h])h--;
            st[++h]=now-&amp;gt;T;
        }
    }
    return h;
}
int main()
{
    int m;
    scanf(&quot;%d&quot;,&amp;amp;m);
    char S[2],s[105];
    int a[5],b,l,r;
    root=new Trie;
    for(int i=1;i&amp;lt;=m;i++){
        scanf(&quot;%s&quot;,S);
        if(S[0]==&apos;A&apos;){
            cnt=0;
            scanf(&quot;%d.%d.%d.%d/%d&quot;,&amp;amp;a[1],&amp;amp;a[2],&amp;amp;a[3],&amp;amp;a[4],&amp;amp;b);
            for(int i=1;i&amp;lt;=4;i++){
                for(int j=7;j&amp;gt;=0;j--){
                    if(cnt+1&amp;gt;b)break;
                    if((a[i]&amp;gt;&amp;gt;j)&amp;amp;1)s[cnt]=&apos;1&apos;;
                    else s[cnt]=&apos;0&apos;;
                    cnt++;
                }
            }
            insert(s);
        }
        else{
            cnt=0;
            scanf(&quot;%d.%d.%d.%d %d %d&quot;,&amp;amp;a[1],&amp;amp;a[2],&amp;amp;a[3],&amp;amp;a[4],&amp;amp;l,&amp;amp;r);
            for(int i=1;i&amp;lt;=4;i++){
                for(int j=7;j&amp;gt;=0;j--){
                    if((a[i]&amp;gt;&amp;gt;j)&amp;amp;1)s[cnt]=&apos;1&apos;;
                    else s[cnt]=&apos;0&apos;;
                    cnt++;
                }
            }
            printf(&quot;%d\n&quot;,query(s,l,r));
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[COGS 2051] 王者之剑 题解 网络流最大权闭合子图</title><link>https://www.nekomio.com/posts/5/</link><guid isPermaLink="true">https://www.nekomio.com/posts/5/</guid><pubDate>Tue, 13 Jun 2017 15:35:35 GMT</pubDate><content:encoded>&lt;h3&gt;【题目描述】&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593fa2607488e.jpg&quot; alt=&quot;saber&quot; /&gt;
这是在阿尔托利亚·潘德拉贡成为英灵前的事情，她正要去拔出石中剑成为亚瑟王，在这之前她要去收集一些宝石。&lt;br /&gt;
宝石排列在一个n*m的网格中，每个网格中有一块价值为v(i,j)的宝石，阿尔托利亚·潘德拉贡可以选择自己的起点。&lt;br /&gt;
开始时刻为0秒。以下操作，每秒按顺序执行&lt;br /&gt;
1.在第i秒开始的时候，阿尔托利亚·潘德拉贡在方格（x,y）上，她可以拿走（x，y）中的宝石。&lt;br /&gt;
2.在偶数秒，阿尔托利亚·潘德拉贡周围四格的宝石会消失&lt;br /&gt;
3.若阿尔托利亚·潘德拉贡第i秒开始时在方格（x，y）上，则在第i+1秒可以立即移动到（x+1，y），（x，y+1），（x-1，y）或（x，y-1）上，也可以停留在（x,y)上。&lt;br /&gt;
求阿尔托利亚·潘德拉贡最多可以获得多少价值的宝石
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;第一行给出数字N,M代表行列数.N,M均小于等于100，宝石的价值不会超过10000.下面N行M列用于描述数字矩阵&lt;/p&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;输出最多可以拿到多少价值宝石&lt;/p&gt;
&lt;h3&gt;【样例输入】&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;2 2
1 2
2 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;【样例输出】&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;与网络流24题中方格取数相同&lt;br /&gt;
最大权闭合子图&lt;br /&gt;
黑白染色&lt;br /&gt;
相邻连INF的边&lt;br /&gt;
源点向白格子连格子权值的边&lt;br /&gt;
黑格子想汇点连权值的边&lt;/p&gt;
&lt;p&gt;跑一遍最小割也就是最大流
Dinic解决&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-06-13 16:37:09 
 * @Last Modified by:   WildRage 
 * @Last Modified time: 2017-06-13 16:37:09 
 */
#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
#include&amp;lt;queue&amp;gt;
using namespace std;
const int INF=0x7fffffff;
struct edge{
    int END,cap,next;
}v[500000];
int first[10005],p;
void add(int a,int b,int c){
    v[p].END=b;v[p].next=first[a];v[p].cap=c;first[a]=p++;
    v[p].END=a;v[p].next=first[b];v[p].cap=0;first[b]=p++;
}
int dis[10005];
bool vis[10005];
bool BFS(int S,int E){
    memset(vis,0,sizeof(vis));
    memset(dis,-1,sizeof(dis));
    queue&amp;lt;int&amp;gt; Q;
    Q.push(S);
    dis[S]=0;vis[S]=1;
    while(!Q.empty()){
        int u=Q.front();Q.pop();
        for(int i=first[u];i!=-1;i=v[i].next){
            if(!vis[v[i].END]&amp;amp;&amp;amp;v[i].cap&amp;gt;0){
                vis[v[i].END]=1;
                dis[v[i].END]=dis[u]+1;
                if(v[i].END==E)return 1;
                Q.push(v[i].END);
            }
        }
    }
    return 0;
}
int DFS(int x,int a,int E){
    if(x==E||a==0)return a;
    int flow=0,f;
    for(int i=first[x];i!=-1;i=v[i].next){
        if(dis[x]+1==dis[v[i].END]&amp;amp;&amp;amp;(f=DFS(v[i].END,min(a,v[i].cap),E))&amp;gt;0){
            v[i].cap-=f;
            v[i^1].cap+=f;
            flow+=f;
            a-=f;
            if(a==0)break;
        }
    }
    if(!flow)dis[x]=-1;
    return flow;
}
int Dinic(int S,int E){
    int flow=0;
    while(BFS(S,E)){
        flow+=DFS(S,INF,E);
    }
    return flow;
}
int a[105][105];
template&amp;lt;class T&amp;gt;inline void read(T &amp;amp;res){
	static char ch;T flag=1;
	while((ch=getchar())&amp;lt;&apos;0&apos;||ch&amp;gt;&apos;9&apos;)if(ch==&apos;-&apos;)flag=-1;res=ch-48;
	while((ch=getchar())&amp;gt;=&apos;0&apos;&amp;amp;&amp;amp;ch&amp;lt;=&apos;9&apos;)res=(res&amp;lt;&amp;lt;1)+(res&amp;lt;&amp;lt;3)+ch-48;res*=flag;
}
int Main(){
    freopen(&quot;Excalibur.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;Excalibur.out&quot;,&quot;w&quot;,stdout);
    memset(first,-1,sizeof(first));
    int m,n;
    int sum=0;
    read(m),read(n);
    for(int i=1;i&amp;lt;=m;i++)
        for(int j=1;j&amp;lt;=n;j++){
            read(a[i][j]);
            sum+=a[i][j];
    	}
    for(int i=1;i&amp;lt;=m;i++){
        for(int j=1;j&amp;lt;=n;j++){
            if((i&amp;amp;1)^(j&amp;amp;1)){
                add(0,n*(i-1)+j,a[i][j]);
                if(j-1&amp;gt;=1)add(n*(i-1)+j,n*(i-1)+j-1,INF);
				if(i-1&amp;gt;=1)add(n*(i-1)+j,n*(i-2)+j,INF);
				if(i+1&amp;lt;=m)add(n*(i-1)+j,n*(i)+j,INF);
				if(j+1&amp;lt;=n)add(n*(i-1)+j,n*(i-1)+j+1,INF);
            }
            else{
                add(n*(i-1)+j,n*m+1,a[i][j]);
            }
            
        }
    }
    return printf(&quot;%d&quot;,sum-Dinic(0,m*n+1));
}
int A=Main();
int main(){;}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>图库</title><link>https://www.nekomio.com/posts/0/</link><guid isPermaLink="true">https://www.nekomio.com/posts/0/</guid><pubDate>Tue, 13 Jun 2017 15:30:32 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f619eef17b.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f619e20c1e.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f6196d31e1.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f61947192d.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f61946edff.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f61647dad8.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f616459d33.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f6147eecef.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f619eef17b.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f61637d06d.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f6162d88e0.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f6162a7ed8.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f616230fd7.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f6161eac11.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f61480c26d.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f6147eecef.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f6147db6cd.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f6147b0f6d.jpg&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f6147c0379.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>[BZOJ 1954] The xor-longest Path Trie树 贪心</title><link>https://www.nekomio.com/posts/3/</link><guid isPermaLink="true">https://www.nekomio.com/posts/3/</guid><pubDate>Tue, 13 Jun 2017 14:30:32 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f91a517d9c.jpg&quot; alt=&quot;题面&quot; /&gt;
给定一棵n个点的带权树，求树上最长的异或和路径
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;The input contains several test cases. The first line of each test case contains an integer n(1&amp;lt;=n&amp;lt;=100000), The following n-1 lines each contains three integers u(0 &amp;lt;= u &amp;lt; n),v(0 &amp;lt;= v &amp;lt; n),w(0 &amp;lt;= w &amp;lt; 2^31), which means there is an edge between node u and v of length w.&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;For each test case output the xor-length of the xor-longest path.&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;4

1 2 3

2 3 4

2 4 6
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;7
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;本题是要求树上的路径异或
只要先预处理出每个点到根的路径的异或值又因为异或两次会抵消所以结果一定是对的&lt;/p&gt;
&lt;p&gt;然后将所有点的异或值都插入一块Trie二进制由高到低&lt;/p&gt;
&lt;p&gt;枚举每一个点 贪心的在Trie树中找就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-06-13 10:24:04 
 * @Last Modified by:   WildRage 
 * @Last Modified time: 2017-06-13 10:24:04 
 */
#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
using namespace std;
struct Trie_Node{
    Trie_Node *ch[27];
    Trie_Node(){
        memset(ch,0,sizeof(ch));
    }
}*root;
int ans;
inline void insert(char *s){
    int len=strlen(s);
    Trie_Node *now=root;
    for(int i=0;i&amp;lt;len;i++){
        if(now-&amp;gt;ch[s[i]-&apos;A&apos;]==NULL)
            now-&amp;gt;ch[s[i]-&apos;A&apos;]=new Trie_Node,ans++;
        now=now-&amp;gt;ch[s[i]-&apos;A&apos;];
    }
}
int main()
{
    freopen(&quot;trie.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;trie.out&quot;,&quot;w&quot;,stdout);
    char s[105];
    root=new Trie_Node;ans++;
    while(scanf(&quot;%s&quot;,s)!=EOF) insert(s);
    printf(&quot;%d&quot;,ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[NOI2000] 单词查找树</title><link>https://www.nekomio.com/posts/4/</link><guid isPermaLink="true">https://www.nekomio.com/posts/4/</guid><pubDate>Tue, 13 Jun 2017 14:20:10 GMT</pubDate><content:encoded>&lt;h3&gt;[题目描述]&lt;/h3&gt;
&lt;p&gt;在进行文法分析的时候，通常需要检测一个单词是否在我们的单词列表里。为了提高查找和定位的速度，通常都要画出与单词列表所对应的单词查找树，其特点如下：
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;根节点不包含字母，除根节点外每一个节点都仅包含一个大写英文字母；&lt;/li&gt;
&lt;li&gt;从根节点到某一节点，路径上经过的字母依次连起来所构成的字母序列，称为该节点对应的单词。单词列表中的每个词，都是该单词查找树某个节点所对应的单词；&lt;/li&gt;
&lt;li&gt;在满足上述条件下，该单词查找树的节点数最少。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;单词列表对应的单词查找树&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
AN  
ASP  
AS  
ASC  
ASCII  
BAS  
BASIC
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://ooo.0o0.ooo/2017/06/13/593f972d8be0a.gif&quot; alt=&quot;图二&quot; /&gt;&lt;/p&gt;
&lt;p&gt;对一个确定的单词列表，请统计对应的单词查找树的节点数（包括根节点）&lt;/p&gt;
&lt;h3&gt;[输入文件]&lt;/h3&gt;
&lt;p&gt;该文件为一个单词列表，每一行仅包含一个单词和一个换行/回车符。每个单词仅由大写的英文字符组成，长度不超过63个字符。文件总长度不超过32K，至少有一行数据。&lt;/p&gt;
&lt;h3&gt;[输出文件]&lt;/h3&gt;
&lt;p&gt;该文件中仅包含一个整数和一个换行/回车符。该整数为单词列表对应的单词查找树的节点数。&lt;/p&gt;
&lt;h3&gt;[输入输出文件样例]&lt;/h3&gt;
&lt;h4&gt;Input&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;A
AN
ASP
AS
ASC
ASCII
BAS
BASIC
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Output&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;13
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;裸的Trie树&lt;br /&gt;
直接套板子&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-06-13 10:24:04 
 * @Last Modified by:   WildRage 
 * @Last Modified time: 2017-06-13 10:24:04 
 */
#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
using namespace std;
struct Trie_Node{
    Trie_Node *ch[27];
    Trie_Node(){
        memset(ch,0,sizeof(ch));
    }
}*root;
int ans;
inline void insert(char *s){
    int len=strlen(s);
    Trie_Node *now=root;
    for(int i=0;i&amp;lt;len;i++){
        if(now-&amp;gt;ch[s[i]-&apos;A&apos;]==NULL)
            now-&amp;gt;ch[s[i]-&apos;A&apos;]=new Trie_Node,ans++;
        now=now-&amp;gt;ch[s[i]-&apos;A&apos;];
    }
}
int main()
{
    freopen(&quot;trie.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;trie.out&quot;,&quot;w&quot;,stdout);
    char s[105];
    root=new Trie_Node;ans++;
    while(scanf(&quot;%s&quot;,s)!=EOF) insert(s);
    printf(&quot;%d&quot;,ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>POJ 2406 Power Strings 题解 KMP 适配函数</title><link>https://www.nekomio.com/posts/2/</link><guid isPermaLink="true">https://www.nekomio.com/posts/2/</guid><pubDate>Tue, 13 Jun 2017 13:50:32 GMT</pubDate><content:encoded>&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;Given two strings a and b we define a&lt;em&gt;b to be their concatenation. For example, if a = &quot;abc&quot; and b = &quot;def&quot; then a&lt;/em&gt;b = &quot;abcdef&quot; . If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = &quot;&quot; (the empty string) and a^(n+1) = a*(a^n) .
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Input&lt;/h3&gt;
&lt;p&gt;Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.&lt;/p&gt;
&lt;h3&gt;Output&lt;/h3&gt;
&lt;p&gt;For each s you should print the largest n such that $$s = a^n$$ for some string a.&lt;/p&gt;
&lt;h3&gt;Sample Input&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;abcd
aaaa
ababab
.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sample Output&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;1
4
3
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;题解&lt;/h2&gt;
&lt;p&gt;主要考虑 KMP 中失陪函数的意义&lt;br /&gt;
因为整个串是会重复的&lt;br /&gt;
所以整个串的长度一定是串长减最后一个字符的fail的倍数&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
using namespace std;
const int N=1000005;
char S[N];
int next[N],len;
void get_next(){
    next[0]=-1;next[1]=0;
    for(int i=2,j=0;i&amp;lt;=len;i++){
        while(~j&amp;amp;&amp;amp;S[j+1]!=S[i])j=next[j];
        next[i]=++j;
    }
}
int main()
{
    while(1){
        memset(S,0,sizeof(S));
        scanf(&quot;%s&quot;,S);
        len=strlen(S)-1;
        if(S[0]==&apos;.&apos;)break;
        get_next();
        //for(int i=1;i&amp;lt;=len;i++)printf(&quot;%d &quot;,next[i]);
        //puts(&quot;&quot;);
        if((len+1)%(len-next[len])==0)printf(&quot;%d\n&quot;,(len+1)/(len-next[len]));
        else puts(&quot;1&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[POJ3461] 乌力波 MP 题解 板子</title><link>https://www.nekomio.com/posts/1/</link><guid isPermaLink="true">https://www.nekomio.com/posts/1/</guid><pubDate>Tue, 13 Jun 2017 11:20:00 GMT</pubDate><content:encoded>&lt;h3&gt;【题目描述】&lt;/h3&gt;
&lt;p&gt;法国作家乔治·佩雷克(Georges Perec，1936-1982)曾经写过一本书，《敏感字母》（La disparition），全篇没有一个字母‘e’。他是乌力波小组（Oulipo Group）的一员。下面是他书中的一段话：
&amp;lt;!--more--&amp;gt;
Tout avait Pair normal, mais tout s’affirmait faux. Tout avait Fair normal, d’abord, puis surgissait l’inhumain, l’affolant. Il aurait voulu savoir où s’articulait l’association qui l’unissait au roman : stir son tapis, assaillant à tout instant son imagination, l’intuition d’un tabou, la vision d’un mal obscur, d’un quoi vacant, d’un non-dit : la vision, l’avision d’un oubli commandant tout, où s’abolissait la raison : tout avait l’air normal mais…&lt;/p&gt;
&lt;p&gt;佩雷克很可能在下面的比赛中得到高分（当然，也有可能是低分）。在这个比赛中，人们被要求针对一个主题写出甚至是意味深长的文章，并且让一个给定的“单词”出现次数尽量少。我们的任务是给评委会编写一个程序来数单词出现了几次，用以得出参赛者最终的排名。参赛者经常会写一长串废话，例如500000个连续的‘T’。并且他们不用空格。
因此我们想要尽快找到一个单词出现的频数，即一个给定的字符串在文章中出现了几次。更加正式地，给出字母表{‘A’,’B’,’C’,…,’Z’}和两个仅有字母表中字母组成的有限字符串：单词W和文章T，找到W在T中出现的次数。这里“出现”意味着W中所有的连续字符都必须对应T中的连续字符。T中出现的两个W可能会部分重叠。&lt;/p&gt;
&lt;h3&gt;【输入格式】&lt;/h3&gt;
&lt;p&gt;输入包含多组数据。
输入文件的第一行有一个整数，代表数据组数。接下来是这些数据，以如下格式给出：
第一行是单词W，一个由{‘A’,’B’,’C’,…,’Z’}中字母组成的字符串，保证1&amp;lt;=|W|&amp;lt;=10000（|W|代表字符串W的长度）
第二行是文章T，一个由{‘A’,’B’,’C’,…,’Z’}中字母组成的字符串，保证|W|&amp;lt;=|T|&amp;lt;=1000000。&lt;/p&gt;
&lt;h3&gt;【输出格式】&lt;/h3&gt;
&lt;p&gt;对每组数据输出一行一个整数，即W在T中出现的次数。&lt;/p&gt;
&lt;h3&gt;【样例输入】&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;【样例输出】&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;1
3
0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;题解&lt;/h3&gt;
&lt;p&gt;就是MP板子&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @Author: WildRage 
 * @Date: 2017-06-12 17:26:02 
 * @Last Modified by: WildRage
 * @Last Modified time: 2017-06-12 19:01:45
 */
#include&amp;lt;cstdio&amp;gt;
#include&amp;lt;cstring&amp;gt;
using namespace std;
char S[1000005],T[1000005];
int next[1000005];
int len;
void get_next(char *a,int n){
    int j=0,k=-1;
    next[0]=-1;
    while(j&amp;lt;n){
        if(k==-1||T[j]==T[k]){
            next[++j]=++k;
        }
        else k=next[k];
    }
}
int main()
{
    freopen(&quot;oulipo.in&quot;,&quot;r&quot;,stdin);
    freopen(&quot;oulipo.out&quot;,&quot;w&quot;,stdout);
    int t;
    scanf(&quot;%d&quot;,&amp;amp;t);
    while(t--){
        int ans=0;
        scanf(&quot;%s&quot;,T);scanf(&quot;%s&quot;,S);
        int n=strlen(S);
        int m=strlen(T);
        get_next(T,m);
        int i=0,j=0;
        for(int i=0;i&amp;lt;n;i++){
            while(j&amp;gt;0&amp;amp;&amp;amp;S[i]!=T[j]) j=next[j];
            if(S[i]==T[j])j++;
            if(j==m)ans++,j=next[j];
        }
        printf(&quot;%d\n&quot;,ans);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>网络流笔记</title><link>https://www.nekomio.com/posts/%E7%BD%91%E7%BB%9C%E6%B5%81/</link><guid isPermaLink="true">https://www.nekomio.com/posts/%E7%BD%91%E7%BB%9C%E6%B5%81/</guid><pubDate>Tue, 13 Jun 2017 09:41:05 GMT</pubDate><content:encoded>&lt;h1&gt;网络流&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;是指在一个每条边都有容量（capacity）的有向图分配流，使一条边的流量不会超过它的容量。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;最大流&lt;/h3&gt;
&lt;h2&gt;Dinic&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Dinic算法（又称Dinitz算法）是一个在网络流中计算最大流的强多项式复杂度的算法，设想由以色列（前苏联）的计算机科学家Yefim (Chaim) A. Dinitz在1970年提出。
&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;最大流例题&lt;/h2&gt;
&lt;p&gt;[Usaco 2007 Open] Dining吃饭&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;题意：
有N头牛，F种食物和D种饮料，每头牛有多种喜欢的食物和饮料，每头牛只可以吃一种食物和饮料，且每种食物和饮料都只能被一头牛吃掉。一头牛满意当且仅当它吃到满意的食物并且喝到想喝的饮料，问最多可能让多少头牛满意。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;最小割&lt;/h2&gt;
&lt;h3&gt;最大权闭合子图&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;现在有一个有向图，每个点有点权，点权可正可负。对于任意一条有向边i和j，选择了点i就必须选择点j，你需要选择一些点使得得到权值最大。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;解题&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;将由源点S向权值为正的点连流量为i的边，将权值为负的点向汇点连边
限制关系连流量为INF的图
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;[NOI2006 最大获利]&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;建权值为Ci的一个图像Ai与Bi建图
转化为最大权闭合子图&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;其他&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;二分图最大点权匹配
二分图最大点权独立集
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;费用流&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;最大费用流&lt;/li&gt;
&lt;li&gt;最小费用最大流&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;连续最短路算法&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;贪心思想&lt;/li&gt;
&lt;li&gt;从源点开始每次寻找总费用最小的增广路&lt;/li&gt;
&lt;li&gt;直到不能增广为止&lt;/li&gt;
&lt;/ul&gt;
&lt;h6&gt;[SDOI2009]晨跑&lt;/h6&gt;
&lt;blockquote&gt;
&lt;p&gt;Elaxia最近迷恋上了空手道，他为自己设定了一套健身计划，比如俯卧撑、仰卧起坐等 等，不过到目前为止，他坚持下来的只有晨跑。 现在给出一张学校附近的地图，这张地图中包含N个十字路口和M条街道，Elaxia只能从 一个十字路口跑向另外一个十字路口，街道之间只在十字路口处相交。Elaxia每天从寝室出发 跑到学校，保证寝室编号为1，学校编号为N。 Elaxia的晨跑计划是按周期（包含若干天）进行的，由于他不喜欢走重复的路线，所以 在一个周期内，每天的晨跑路线都不会相交（在十字路口处），寝室和学校不算十字路 口。Elaxia耐力不太好，他希望在一个周期内跑的路程尽量短，但是又希望训练周期包含的天 数尽量长。 除了练空手道，Elaxia其他时间都花在了学习和找MM上面，所有他想请你帮忙为他设计 一套满足他要求的晨跑计划。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h6&gt;[SDOI2007]修车&lt;/h6&gt;
&lt;blockquote&gt;
&lt;p&gt;同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员，不同的技术人员对不同的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序，使得顾客平均等待的时间最小。 说明：顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;将每个人拆成n个点
第i个点代表这个人修的车中倒数第i辆
将每辆车向这些点连边，流量为1
的费用为f[i][j]*i
源点连向车，工作人员向汇点连边
&lt;/code&gt;&lt;/pre&gt;
&lt;h6&gt;[SDOI2016]数字匹配&lt;/h6&gt;
&lt;blockquote&gt;
&lt;p&gt;有 n 种数字，第 i 种数字是 ai、有 bi 个，权值是 ci。
若两个数字 ai、aj 满足，ai 是 aj 的倍数，且 ai/aj 是一个质数，
那么这两个数字可以配对，并获得 ci×cj 的价值。
一个数字只能参与一次配对，可以不参与配对。
在获得的价值总和不小于 0 的前提下，求最多进行多少次配对。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;以奇数和偶数因子建二分图
&lt;/code&gt;&lt;/pre&gt;
&lt;h6&gt;[SDOI2013]费用流&lt;/h6&gt;
&lt;blockquote&gt;
&lt;p&gt;Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识。&lt;br /&gt;
最大流问题：给定一张有向图表示运输网络，一个源点S和一个汇点T，每条边都有最大流量。&lt;br /&gt;
一个合法的网络流方案必须满足：&lt;br /&gt;
(1)每条边的实际流量都不超过其最大流量且非负；&lt;br /&gt;
(2)除了源点S和汇点T之外，对于其余所有点，都满足该点总流入流量等于该点总流出流量；而S点的净流出流量等于T点的净流入流量，这个值也即该网络流方案的总运输量。最大流问题就是对于给定的运输网络，求总运输量最大的网络流方案。&lt;br /&gt;
上图表示了一个最大流问题。&lt;br /&gt;
对于每条边，右边的数代表该边的最大流量，左边的数代表在最优解中，该边的实际流量。需要注意到，一个最大流问题的解可能不是唯一的。    对于一张给定的运输网络，Alice先确定一个最大流，如果有多种解，Alice可以任选一种；之后Bob在每条边上分配单位花费（单位花费必须是非负实数），要求所有边的单位花费之和等于P。总费用等于每一条边的实际流量乘以该边的单位花费。需要注意到，Bob在分配单位花费之前，已经知道Alice所给出的最大流方案。现茌Alice希望总费用尽量小，而Bob希望总费用尽量大。我们想知道，如果两个人都执行最优策略，最大流的值和总费用分别为多少。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h6&gt;[codevs 1227]方格取数2&lt;/h6&gt;
&lt;blockquote&gt;
&lt;p&gt;给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij &amp;lt;= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h6&gt;[BZOJ 3438]小M的作物&lt;/h6&gt;
&lt;blockquote&gt;
&lt;p&gt;小M在MC里开辟了两块巨大的耕地A和B（你可以认为容量是无穷），现在，小P有n中作物的种子，每种作物的种子
有1个（就是可以种一棵作物）（用1...n编号），现在，第i种作物种植在A中种植可以获得ai的收益，在B中种植
可以获得bi的收益，而且，现在还有这么一种神奇的现象，就是某些作物共同种在一块耕地中可以获得额外的收益
，小M找到了规则中共有m种作物组合，第i个组合中的作物共同种在A中可以获得c1i的额外收益，共同总在B中可以
获得c2i的额外收益，所以，小M很快的算出了种植的最大收益，但是他想要考考你，你能回答他这个问题么？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h6&gt;[BZOJ1283] 序列&lt;/h6&gt;
&lt;blockquote&gt;
&lt;p&gt;给出一个长度为 的正整数序列Ci，求一个子序列，使得原序列中任意长度为M的子串中被选出的元素不超过K(K,M&amp;lt;=100) 个，并且选出的元素之和最大。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h6&gt;[JLOI2014]镜面通道&lt;/h6&gt;
&lt;h2&gt;&lt;a href=&quot;http://www.lydsy.com/JudgeOnline/problem.php?id=3630&quot;&gt;题面&lt;/a&gt;&lt;/h2&gt;
</content:encoded></item></channel></rss>