今天写了NOI2016Day1的题,来写一发题解。

T2 网格

题目传送门

Description

\(T\) 次询问,每次给出一个 \(n\times m\) 的传送门,上面有 \(c\) 个位置是蛐蛐,其余位置都是跳蚤,问至少要把多少个跳蚤换成蛐蛐才能使存在两只跳蚤不连通。

\(n,m\le 10^9,\sum c\le 10^5\)

Solution

可以想到的是答案一定是 \(-1,0,1,2\) 中的一个。

考虑如何判断。\(0\) 的话一定是存在两个及以上的跳蚤连通块,\(1\) 的话是只存在一个跳蚤连通块且存在一个割点,\(-1\) 就不用说了。\(2\) 就是除了这些情况的其他情况。

考虑如何快速判断。首先我们可以发现有用的其实只有在蛐蛐周围 \(5\times 5\) 的这些格子。

然后我们可以发现如果存在两个及以上的连通块,那么一定存在一个蛐蛐连通块使得周围有属于不同的跳蚤联通块的跳蚤。

于是我们就可以做到 \(\Theta(\sum c)\) 了。注意因为常数较大所以需要使用 \(\text{hash}\) 表。

Code

#include <bits/stdc++.h>
using namespace std; #define pii pair<int,int>
#define Int register int
#define mp make_pair
#define MAXN 2500005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} int kase,n,m,c; struct Hash{//实现hash表
private:
#define mod 1000007
#define int long long
int siz,sx[MAXN],sy[MAXN],nxt[MAXN],ind[MAXN],head[mod + 5];
public:
void clear(){siz = 0,memset (head,0,sizeof (head));}
void ins (int x,int y,int id){
int pos = (1ll * (x - 1) * m + y) % mod;
sx[++ siz] = x,sy[siz] = y,ind[siz] = id,nxt[siz] = head[pos],head[pos] = siz;
}
int query (int x,int y){
int pos = (1ll * (x - 1) * m + y) % mod;
for (Int i = head[pos];i;i = nxt[i]) if (sx[i] == x && sy[i] == y) return ind[i];
return 0;
}
#undef int
}h,bel,vis; struct edge{
int v,nxt;
}e[MAXN * 4];
int toop = 1,head[MAXN]; void link (int u,int v){
e[++ toop] = edge {v,head[u]},head[u] = toop;
e[++ toop] = edge {u,head[v]},head[v] = toop;
} bool cut[MAXN];
int ind,dfn[MAXN],low[MAXN];
void Tarjan (int u,int fa){
dfn[u] = low[u] = ++ ind;int son = 0;
for (Int i = head[u];i;i = e[i].nxt){
int v = e[i].v;
if (!dfn[v]) son ++,Tarjan (v,u),low[u] = min (low[u],low[v]),cut[u] |= (low[v] >= dfn[u]);
else low[u] = min (low[u],dfn[v]);
}
if (!fa && son == 1) cut[u] = 0;
} pii t[MAXN]; int dx[8] = {1,-1,0,0,1,1,-1,-1},dy[8] = {0,0,1,-1,1,-1,1,-1};
bool inside (int x,int y){return x >= 1 && x <= n && y >= 1 && y <= m;} bool checkit (){//判断唯二的两个点是否联通
for (Int x = 1;x <= n;++ x)
for (Int y = 1;y <= m;++ y) if (!h.query (x,y)){
for (Int i = 0;i < 4;++ i){
int tx = x + dx[i],ty = y + dy[i];
if (inside (tx,ty) && !h.query (tx,ty)) return 0;
}
}
return 1;
}
bool ner[MAXN];
int Abs (int x){return x < 0 ? -x : x;} queue <pii> Q,q;
void BFS (int sx,int sy,int col){
Q.push (mp (sx,sy)),bel.ins (sx,sy,col);
while (!Q.empty()){
int x = Q.front().first,y = Q.front().second;Q.pop ();
for (Int i = 0;i < 4;++ i){
int tx = x + dx[i],ty = y + dy[i];
if (inside (tx,ty) && h.query (tx,ty) > 0 && !bel.query (tx,ty))
bel.ins (tx,ty,col),Q.push (mp (tx,ty));
}
}
} int tot;
pii pnt[MAXN];
bool BFS1 (int sx,int sy){
tot = 0;Q.push (mp (sx,sy)),vis.ins (sx,sy,-1);
while (!Q.empty()){
int x = Q.front().first,y = Q.front().second;Q.pop ();
for (Int i = 0;i < 8;++ i){
int tx = x + dx[i],ty = y + dy[i];
if (inside (tx,ty) && h.query (tx,ty) == -1 && !vis.query (tx,ty))
vis.ins (tx,ty,-1),Q.push (mp (tx,ty));
else if (inside (tx,ty) && h.query (tx,ty) > 0 && !vis.query (tx,ty)) pnt[++ tot] = mp (tx,ty);
}
}
if (!tot) return 0;
for (Int i = 2,tmp = bel.query (pnt[1].first,pnt[1].second);i <= tot;++ i)
if (bel.query (pnt[i].first,pnt[i].second) != tmp) return 1;
return 0;
}
bool fuckit(){
int fuc = 0;bel.clear ();
while (!q.empty()){
int x = q.front().first,y = q.front().second;q.pop ();
if (bel.query (x,y)) continue;
BFS (x,y,++ fuc);
}
vis.clear ();
for (Int i = 1;i <= c;++ i)
if (!vis.query (t[i].first,t[i].second))
if (BFS1 (t[i].first,t[i].second)) return 1;
return 0;
} signed main(){
read (kase);
while (kase --> 0){
while (!q.empty()) q.pop();
read (n,m,c);int cnt = 0;h.clear ();
for (Int i = 1;i <= c;++ i) read (t[i].first,t[i].second),h.ins (t[i].first,t[i].second,-1);
if (c >= 1ll * n * m - 1){puts ("-1");continue;}
else if (c == 1ll * n * m - 2){puts (checkit () ? "0" : "-1");continue;}
toop = 1,memset (head,0,sizeof (head));
for (Int z = 1;z <= c;++ z){
int x = t[z].first,y = t[z].second;
for (Int tx = max (1,x - 2);tx <= min (n,x + 2);++ tx)
for (Int ty = max (1,y - 2);ty <= min (m,y + 2);++ ty){
if (!h.query (tx,ty)){
h.ins (tx,ty,++ cnt),ner[cnt] = max (Abs (tx - x),Abs (ty - y)) <= 1,q.push (mp (tx,ty));
for (Int i = 0;i < 4;++ i){
int x1 = tx + dx[i],y1 = ty + dy[i];
if (inside (x1,y1) && h.query (x1,y1) > 0) link (cnt,h.query (x1,y1));
}
}
else if (h.query (tx,ty) > 0 && max (Abs (tx - x),Abs (ty - y)) <= 1) ner[h.query (tx,ty)] = 1;
}
}
if (fuckit ()){puts ("0");continue;}
if (n == 1 || m == 1){puts ("1");continue;}
ind = 0;for (Int i = 1;i <= cnt;++ i) cut[i] = dfn[i] = 0;
for (Int i = 1;i <= cnt;++ i) if (!dfn[i]) Tarjan (i,0);
for (Int i = 1;i <= cnt;++ i) if (cut[i] && ner[i]){puts ("1");goto there;}
puts ("2");
there:;
}
return 0;
}

T3 循环之美

题目传送门

Description

给出 \(n,m,k\),求出 \(a,b\) 满足 \(1\le a\le n,1\le b\le m\) 且 \(a/b\) 在 \(k\) 进制下小数部分纯循环的本质不同个数。

\(n,m\le 10^9,k\le 2000\)

Solution

首先可以观察到的是,当 \(\gcd(a,b)=1\) 且 \(\gcd(b,k)=1\)的时候会产生贡献。

然后就是莫反推式子了:

\[\sum_{a=1}^{n}\sum_{b=1}^{m}[\gcd(a,b)=1][\gcd(b,k)=1]
\]
\[=\sum_{b=1}^{m} [\gcd(b,k)=1]\sum_{d|b} \mu(d)\times \lfloor\frac{n}{d}\rfloor
\]
\[=\sum_{d=1}^{\min(n,m)} \mu(d)\times \lfloor\frac{n}{d}\rfloor\sum_{b=1}^{\lfloor\frac{m}{d}\rfloor} [\gcd(k,db)=1]
\]
\[=\sum_{d=1}^{n} \mu(d)\times \lfloor\frac{n}{d}\rfloor\times [\gcd(d,k)=1] \sum_{b=1}^{\lfloor\frac{m}{d}\rfloor} [\gcd(b,k)=1]
\]

然后你发现后面那一坨可以直接 \(\Theta(k\log k)\) 预处理,然后考虑前面怎么弄。

设 \(g(N,K)=\sum_{d=1}^{N} \mu(d)[\gcd(d,K)=1]\)

那么可以得到 \(g(N,K)=\sum_{d=1}^{N} \mu(d)\sum_{h|d\wedge h|k} \mu(h)\)

\[=\sum_{h|k} \mu^2(h)\sum_{d=1}^{\lfloor\frac{N}{h}\rfloor} \mu(d)[\gcd(d,h)=1]
\]
\[=\sum_{h|k} \mu^2(h)g(\lfloor\frac{N}{h}\rfloor,h)
\]

边界条件就是 \(g(N,0)=0,g(N,1)=\sum_{i=1}^{N} \mu(i)\),这个可以直接杜教筛。

总的复杂度我不是很会算,据说是 \(\Theta(k\log k+n^{2/3}+d(k)\times \sqrt n)\) 的,其中 \(d(k)\) 表示 \(k\) 的质因子个数。

Code

#include <unordered_map>
#include <bits/stdc++.h>
using namespace std; #define Int register int
#define int long long
#define MAXN 1000005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} int n,m,k;
int gcd (int a,int b){return !b ? a : gcd (b,a % b);} bool vis[MAXN];
int tot,mu[MAXN],pre[MAXN],prime[MAXN]; void Euler (int up){
mu[1] = pre[1] = 1;
for (Int i = 2;i <= up;++ i){
if (!vis[i]) prime[++ tot] = i,mu[i] = -1;
for (Int j = 1;j <= tot && i * prime[j] <= up;++ j){
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
else mu[i * prime[j]] = -mu[i];
}
pre[i] = pre[i - 1] + mu[i];
}
} unordered_map <int,int> mp;
int Getmu (int N){
if (N <= 1e6) return pre[N];
if (mp.find(N) != mp.end()) return mp[N];
int res = N >= 1;
for (Int l = 2,r;l <= N;l = r + 1)
r = N / (N / l),res -= (r - l + 1) * Getmu (N / l);
return mp[N] = res;
} #define MAXM 2005
vector <int> vic[MAXM];
unordered_map <int,int> g[MAXM];
int getit (int N,int K){
if (K == 0 || N <= 0) return 0;
if (g[K].find (N) != g[K].end()) return g[K][N];
if (K == 1) return g[K][N] = Getmu (N);
int res = 0;
for (Int h : vic[K]) res += mu[h] * mu[h] * getit (N / h,h);
return g[K][N] = res;
} int f[MAXM];
int getf (int N){
return (N / k) * f[k] + f[N % k];
} signed main(){
read (n,m,k),Euler (1e6);
for (Int d = 1;d <= k;++ d) f[d] = f[d - 1] + (gcd (d,k) == 1);
for (Int d = 1;d <= k;++ d) if (mu[d]) for (Int K = d;K <= k;K += d) vic[K].push_back (d);
int tot = 0;
for (Int l = 1,r,las = 0,tmp;l <= min (n,m);l = r + 1)
r = min (n / (n / l),m / (m / l)),tmp = getit (r,k),
tot += (tmp - las) * getf (m / l) * (n / l),las = tmp;
write (tot),putchar ('\n');
return 0;
}

NOI 2016 Day1 题解的更多相关文章

  1. Noip 2016 Day1 题解

    老师让我们刷历年真题, 然后漫不经心的说了一句:“你们就先做做noip2016 day1 吧” ...... 我还能说什么,,,,,老师你这是明摆着伤害我们啊2333333333 预计分数:100+2 ...

  2. NOI 2017 Day1 题解

    被虐爆了... T1 整数 题目传送门 Description 有一个整数 \(x\),有 \(n\) 此操作,每次操作为以下两种情况: 给出 \(a,b\),将 \(x\) 加上 \(a\times ...

  3. [LOJ 2083][UOJ 219][BZOJ 4650][NOI 2016]优秀的拆分

    [LOJ 2083][UOJ 219][BZOJ 4650][NOI 2016]优秀的拆分 题意 给定一个字符串 \(S\), 求有多少种将 \(S\) 的子串拆分为形如 AABB 的拆分方案 \(| ...

  4. THUSC2017 Day1题解

    THUSC2017 Day1题解 巧克力 题目描述 "人生就像一盒巧克力,你永远不知道吃到的下一块是什么味道." 明明收到了一大块巧克力,里面有若干小块,排成n行m列.每一小块都有 ...

  5. https://docs.huihoo.com/infoq/qconbeijing/2016/day1/工程效率提升专题/2-2-支持百度万人开发的工具装备及百度工程能力建设-夏仲璞.pdf

    https://docs.huihoo.com/infoq/qconbeijing/2016/day1/工程效率提升专题/2-2-支持百度万人开发的工具装备及百度工程能力建设-夏仲璞.pdf http ...

  6. NOI 2016 优秀的拆分 (后缀数组+差分)

    题目大意:给你一个字符串,求所有子串的所有优秀拆分总和,优秀的拆分被定义为一个字符串可以被拆分成4个子串,形如$AABB$,其中$AA$相同,$BB$相同,$AB$也可以相同 作为一道国赛题,95分竟 ...

  7. Noi 2016

    考砸只能说自己弱 Noi不是生活的全部, 人们也不会永远止步于失败. 大家加油 可以+我的qq:582744883

  8. 字符串(后缀自动机):NOI 2016 优秀的拆分

    [问题描述] 如果一个字符串可以被拆分为 AABB 的形式,其中 A 和 B 是任意非空字符串, 则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 aabaabaa,如果令 A = aab, B ...

  9. 数据结构(线段树):NOI 2016 区间

    [问题描述] [输入格式] [输出格式] [样例输入] 6 3 3 5 1 2 3 4 2 2 1 5 1 4 [样例输出] 2 [样例说明] [更多样例] 下载 [样例 2 输入输出] 见目录下的 ...

随机推荐

  1. 解决Openstack Dashboard无法获取实例故障

    在部署配置完openstack基础服务以及dashboard后.登录页面发现很多功能都不正常,无法获取实例,也无法获取镜像. 查看日志 [root@openstack-controller-dev ~ ...

  2. vue+vant实现购物车的全选和反选业务,带你研究购物车的那些细节!

    前言 喜欢购物的小伙伴看过来,你们期待已久的购物车来啦!相信小伙伴逛淘宝时最擅长的就是加入购物车了,那购物车是如何实现商品全选反选的呢?今天就带你们研究购物车的源码,以vue+vant为例. 正文 首 ...

  3. RabitMq过期时间TTL

    第一种:给消息设置过期时间 启动一个插件 @Bean public DirectExchange DirectExchange() { return new DirectExchange(" ...

  4. MFC中L, _T(),TEXT,_TEXT区别以及含义

    字符串前面加L表示该字符串是Unicode字符串. _T是一个宏,如果项目使用了Unicode字符集(定义了UNICODE宏),则自动在字符串前面加上L,否则字符串不变.因此,Visual C++里边 ...

  5. vue 引用省市区三级联动(element-ui Cascader)

    npm 下载 npm install element-china-area-data -S main.js import {provinceAndCityData,regionData,provinc ...

  6. vue 引用高德地图

    vue 引用地图之傻瓜式教程(复制粘贴即可用) npm 下载 npm install vue-amap --save main.js 代码 import AMap from 'vue-amap'; V ...

  7. 史上最全git命令集

    配置化命令 git config --global user.name "Your Name" git config --global user.email "email ...

  8. Apache Hudi内核之文件标记机制深入解析

    1. 摘要 Hudi 支持在写入时自动清理未成功提交的数据.Apache Hudi 在写入时引入标记机制来有效跟踪写入存储的数据文件. 在本博客中,我们将深入探讨现有直接标记文件机制的设计,并解释了其 ...

  9. Identity角色管理三(编辑角色)

    因只有角色名能修改故继续使用创建角色的视图模型 using System.ComponentModel; using System.ComponentModel.DataAnnotations; na ...

  10. 前端--jstree--异步加载数据

    利用回调来处理服务器返回的数据, 默认只能解析固定格式的返回值 <div class=""> <div id="div-jstree"> ...