计蒜客NOIP2018模拟1
https://www.jisuanke.com/contest/1152
T1:最失败的一道题,其实就是道水题,好几种写法,一种都没想出来。
题意转化后就是:每个数可以选a[i]和a[i]-k,最后求使1,2,3,...,T都存在的最大的T+1和最多能让多少个数小于等于T。
为什么第一问可以转化成求有多少个数小于等于T呢?首先不大于k的怪物可以直接杀死,然后大于k的怪物显然当且仅当血量小于等于T时才可能被用第二种操作杀死,所以当T最大一定是第二问最优的情况。所以第二问做完后直接扫一边就是第一问的答案。
考虑第二问怎么求:
方法一:二分答案。二分T判断可行性即可,没有任何坑点。$O(n\log n)$
方法二:直接循环。c[]记录每个数有多少个。从1枚举,若 c[i]>0 则 c[i]-- 否则 c[i+k]--,某个数小于0了就终止循环。$O(n)$
方法三:若a[i]>k则连无向边<a[i],a[i]-k>否则连自环<a[i],a[i]>。考虑这个图的每个连通块,如果边数等于点数-1(也就是一棵树),则必然有一个数取不到(显然这个数要选最大的那个),否则块内所有数都能取到。并查集维护连通块即可。$O(n\alpha(n))$
方法四:继续方法三的思想,每个块dfs一遍就可以求出块内的点数和边数了。$O(n)$
前两种简直是无脑方法我竟然都没想到,后面两种应该是一个常用套路,以后发现数的范围也是$O(n)$级别的话就要从数的角度考虑了(比如说建图或生成函数做FFT)
方法一:
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
using namespace std; const int N=;
int n,k,a[N],ans;
bool b[N]; int jud(int mid){
rep(i,,mid+) b[i]=;
rep(i,,n){
if (a[i]<=k) { b[a[i]]=; continue; }
if (a[i]>mid) { b[a[i]-k]=; continue; }
if (!b[a[i]-k]) b[a[i]-k]=; else b[a[i]]=;
}
rep(i,,mid) if (!b[i]) return ;
return ;
} int main(){
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
scanf("%d%d",&n,&k);
rep(i,,n) scanf("%d",&a[i]);
sort(a+,a+n+);
if (!jud()){
int s=;
for (; s<n && a[s+]<=k; s++);
printf("%d %d\n",s,);
return ;
}
int L=,R=a[n]; ans=;
while (L<=R){
int mid=(L+R)>>;
if (jud(mid)) ans=mid,L=mid+; else R=mid-;
}
int s=;
for (; s<n && (a[s+]<=k || a[s+]-k<=ans); s++);
printf("%d %d\n",s,min(n,ans+));
return ;
}
方法二:
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
using namespace std; const int N=;
int n,k,ans,a[N],c[N]; int main(){
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
scanf("%d%d",&n,&k); int s=;
rep(i,,n) scanf("%d",&a[i]),c[a[i]]++;
while (){
if (c[s]) c[s]--;
else if (c[s+k]) c[s+k]--;
else break;
s++;
}
rep(i,,n) if (a[i]<=k || a[i]-k<=s-) ans++;
printf("%d %d\n",ans,min(n,s));
return ;
}
方法四:
#include<cstdio>
#include<vector>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
using namespace std; const int N=;
int n,k,ans,mx,cnt,tot,b[N],vis[N],bel[N],a[N],pe[N],pv[N],to[N],nxt[N],h[N];
vector<int>V[N]; void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } void dfs(int x,int fa,int co){
V[co].push_back(x); bel[x]=co; vis[x]=; pv[co]++;
For(i,x) if ((k=to[i])!=fa && k!=x && !vis[k]) dfs(k,x,co);
} int main(){
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
scanf("%d%d",&n,&k); int s=;
rep(i,,n) scanf("%d",&a[i]),mx=max(mx,a[i]);
rep(i,,n) if (a[i]>k) add(a[i],a[i]-k),add(a[i]-k,a[i]); else add(a[i],a[i]),add(a[i],a[i]);
rep(i,,mx) if (!vis[i]) tot++,dfs(i,,tot);
rep(i,,tot) sort(V[i].begin(),V[i].end());
for (int i=; i<=cnt; i+=) pe[bel[to[i]]]++;
rep(i,,tot) if (pe[i]<pv[i]) b[V[i][V[i].size()-]]=;
for (; !b[s]; s++);
rep(i,,n) if (a[i]<=k || a[i]-k<=s-) ans++;
printf("%d %d\n",ans,min(min(mx+,n),s));
return ;
}
T2:
首先参考[JSOI2017]原力,这是一个套路,但是只有80分。
考虑一种做法:先求出图的一棵生成树。假设三角形有至少一条边在树上,那么枚举一条非树边<u,v>,直接看fa[u]是否和v相邻即可。如果没有满足条件的边则说明这棵树上没有边在三角形上,删去所有树边。重复以上操作即可,复杂度$O(\frac{m^2}{n})$。
这个做法当n在4000左右时显然会很大,但这个时候直接bitset搞一下就可以了,复杂度$O(mn/64)$。
综合以上两种方法即可拿到满分。
80分:
#include<map>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; const int N=,p=,p1=;
int n,m,u,v,cnt,tot,d[N],id[N],to[N<<],nxt[N<<],h[N],hash1[p1+],hash2[p1+],S[][];
void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
void Hash(int u,int v){ int i=(u*p+v)%p1; for (; hash1[i]; i=(i+)%p1); if (!hash1[i]) hash1[i]=u,hash2[i]=v; }
int find(int u,int v){
int i=(u*p+v)%p1;
for (; hash1[i] && (hash1[i]!=u || hash2[i]!=v); i=(i+)%p1);
if (!hash1[i]) return ; else return i;
} int main(){
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
scanf("%d%d",&n,&m); int si=(int)sqrt(n);
if (n<=){
rep(i,,m) scanf("%d%d",&u,&v),S[u][v]=,S[v][u]=;
rep(i,,n-) rep(j,i+,n-) if (S[i][j]) rep(k,j+,n) if (S[j][k] && S[i][k])
{ printf("%d %d %d\n",i,j,k); return ; }
}
rep(i,,m) scanf("%d%d",&u,&v),add(u,v),add(v,u),d[u]++,d[v]++,Hash(min(u,v),max(u,v));
rep(i,,n) if (d[i]>=si) id[++tot]=i;
rep(i,,tot-) rep(j,i+,tot-) rep(k,j+,tot)
if (find(id[i],id[j]) && find(id[j],id[k]) && find(id[i],id[k])){
printf("%d %d %d\n",id[i],id[j],id[k]); return ;
}
rep(i,,n) if (d[i]<si){
for (int j=h[i]; j; j=nxt[j])
for (int k=nxt[j]; k; k=nxt[k]) if (find(to[j],to[k]) || find(to[k],to[j])){
int x=i,y=to[j],z=to[k];
if (x>y) swap(x,y);
if (y>z) swap(y,z);
if (x>y) swap(x,y);
printf("%d %d %d\n",x,y,z); return ;
}
}
return ;
}
方法二(bitset):
#include<cstdio>
#include<bitset>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
using namespace std; const int N=;
int n,m,u,v,U[N],V[N];
bitset<>a[]; int main(){
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
scanf("%d%d",&n,&m);
rep(i,,m) scanf("%d%d",&u,&v),a[u].set(v),a[v].set(u),U[i]=u,V[i]=v;
if (n<=){
rep(i,,m){
bitset<>C=a[U[i]]&a[V[i]];
if (C.none()) continue;
int s1=U[i],s2=V[i];
rep(j,,n) if (C[j]){
int s3=j;
if (s1>s2) swap(s1,s2);
if (s2>s3) swap(s2,s3);
if (s1>s2) swap(s1,s2);
printf("%d %d %d\n",s1,s2,s3);
return ;
}
}
}
return ;
}
满分:
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=,M=;
int n,m,tot,a[][],h[M],x[M],y[M],h1[M],nxt1[M],fa[N],nxt[N],used[N],que[N]; int add(int a, int b){
x[++tot] = a; y[tot] = b; h[tot] = nxt[a]; nxt[a] = tot;
int h = (a * + b) % ; nxt1[tot] = h1[h]; h1[h] = tot;
return ;
} int findh(int a, int b){
int h = (a * + b) % ;
int i = h1[h];
while (i != ) {
if ((a == x[i]) && (b == y[i])) return ;
else i=nxt1[i];
}
return ;
} void fin(int i, int j, int k){
if (j > k) swap(j,k);
if (i > j) swap(i,j);
if (j > k) swap(j,k);
printf("%d %d %d\n", i, j, k);
} int alg1(){
for (int i = ; i <= m; i++) {
for (int j = ; j <= n / ; j++)
if ((a[x[ * i - ]][j] & a[y[ * i - ]][j]) != ) {
int s = a[x[ * i - ]][j] & a[y[ * i - ]][j];
int k = ;
while (s > ) s = s / ,k++;
fin(x[ * i - ], y[ * i - ], j * + k - );
return ;
}
}
return ;
} int alg2(){
int round = ;
while ( != ) {
round++; int p = ,q = ;
for (int i = ; i <= n; i++) {
if (used[i] != round) que[++q] = i,fa[i] = i;
while (p <= q) {
int ptr = nxt[que[p]];
while (ptr != ) {
if (used[y[ptr]] != round) {
que[++q] = y[ptr];
used[y[ptr]] = round;
fa[y[ptr]] = que[p];
}
ptr = h[ptr];
}
p++;
}
}
for (int i = ; i <= tot; i++)
if ((x[i] != fa[x[i]]) && (y[i] != fa[x[i]]) && (findh(y[i], fa[x[i]]) == )) {
fin(x[i], fa[x[i]], y[i]); return ;
}
}
return ;
} int main(){
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
scanf("%d%d", &n, &m); tot = ;
for (int i = ; i <= m; i++) {
int p, q;
scanf("%d%d", &p, &q);
add(p, q); add(q, p);
if (n <= ) {
int c = q / ,d = q % ;
a[p][c] += ( << d);
c=p/,d=p%;
a[q][c] += (<<d);
}
}
if (n <= ) alg1(); else alg2();
return ;
}
T3:考虑只有第一种概率模型的情况,从角的角度考虑。设同色三角形个数为$a$,异色为$b$,同色角个数x,异色$y$。则有$x=3a+b,y=2b$,解得$a=\frac{2x-y}{6}$
计蒜客NOIP2018模拟1的更多相关文章
- 计蒜客NOIP模拟赛6 D1T1Diamond-square
Diamond-square 算法是一种能够用于生成噪声的算法,现在我们考虑这个算法的一个变种. 你有一个 2^n\times 2^n2n×2n 的网格,一共有 (2^n+1)^2(2n ...
- 计蒜客NOIP模拟赛4 D2T1 鬼脚图
鬼脚图,又称画鬼脚,在日本称作阿弥陀签,是一种经典游戏,也是一种简易的决策方法,常常用来抽签或决定分配组合. 下图就是一张鬼脚图,其包含若干条竖线和若干条横线.请注意,横线只能水平连接相邻的两条竖线, ...
- 计蒜客 NOIP模拟赛(3) D1T1火山喷发
火山喷发对所有附近的生物具有毁灭性的影响.在本题中,我们希望用数值来模拟这一过程. 在环境里有 nnn 个生物分别具有 A1,A2,⋯,An点生命值,一次火山喷发总计 M轮,每轮造成 1点伤害,等 ...
- 计蒜客NOIP模拟赛(2) D1T1邻家男孩
凡是一个具有领导力的孩子.现实生活中他特别喜欢玩一个叫做 UNO 的纸牌游戏,他也总是带着其他小朋友一起玩,然后战胜他们.慢慢地,他厌倦了胜利,于是准备发明一种新的双人纸牌游戏. 初始时,每个人手中都 ...
- 计蒜客 时间复杂度 (模拟) & 洛谷 P3952 时间复杂度
链接 : Here! 思路 : 这是一道大模拟, 区分好情况就没问题了 循环构成部分 : $F , x , i , j$ 和 $E$ , 需要注意的是 $i , j$, - 分析 $i, j$ 的情况 ...
- 计蒜客NOIP模拟赛5 D1T1 机智的 AmyZhi
那年一个雨季,AmyZhi 在校门外弯身买参考书. 这时 SiriusRen 走过来,一言不合甩给她一道“自认为”很难的题: --------------- 给你一个数字 NN(NN 的范围是 11 ...
- 计蒜客NOIP模拟赛4 D2T2 跑步爱天天
YOUSIKI 在 noip2016 的一道<天天爱跑步>的题爆零后,潜心研究树上问题,成为了一代大师,于是皮皮妖为了测验他,出了一道题,名曰<跑步爱天天>. 有一个以 1 为 ...
- 计蒜客NOIP模拟赛4 D1T3 小X的佛光
小 X 是远近闻名的学佛,平日里最喜欢做的事就是蒸发学水. 小 X 所在的城市 X 城是一个含有 N 个节点的无向图,同时,由于 X 国是一个发展中国家,为了节约城市建设的经费,X 国首相在建造 X ...
- 计蒜客NOIP模拟赛4 D1T2小X的密室
小 X 正困在一个密室里,他希望尽快逃出密室. 密室中有 N 个房间,初始时,小 X 在 1 号房间,而出口在 N 号房间. 密室的每一个房间中可能有着一些钥匙和一些传送门,一个传送门会单向地创造一条 ...
随机推荐
- UOJ#179. 线性规划[模板]
传送门 http://uoj.ac/problem/179 震惊,博主竟然还不会线性规划! 单纯形实在学不会啊……背个板子当黑盒用…… 学(chao)了NanoApe dalao的板子 #includ ...
- 【51NOD-0】1018 排序
[算法]排序 #include<cstdio> #include<algorithm> using namespace std; ]; int main() { scanf(& ...
- Linux while 和 read 的用法
Reference: [ linux man doc ] [ CSDN roler_ ] [ Reads from the file descriptor] read 命令说明 SYNTAX : re ...
- vue_真机调试页面
使用vue开发也有一段时间,是说我太懒了,还是说太懒了.得总结总结的. 之前在开发的时候都是,npm run build把页面打包后再上传到代码库上线用手机看页面效果.样式调整,嗯,很麻烦很傻的. 今 ...
- mysql中的时间year/date/time/datetime
year: mysql> create table y(y year); Query OK, 0 rows affected (0.03 sec) mysql> desc y; +---- ...
- 哈希表(一):解决hash冲突的几种方法
(一)线性探测法 线性探测法是最简单的处理冲突的方法. (1)插入元素:插入元素时,如果发生冲突,算法将从该槽位向后遍历哈希表,直到找到表中的下一个空槽,并将该值放入到空槽当中. (2)查找元素:查找 ...
- python基础===self的理解
self是类的实例 self有点类似java中的this,无实际意义.但是约定俗成的都是用self表示类的实例 class A: def func(self): print(self) #指向的是类的 ...
- FineReport——登录不到决策系统
在不断的测试过程中,可能会造成缓存数据的累积,所以在登录过程中可能会出现登录不到决策系统,而是跳转到某一模板页面 解决方法就是清理缓存或者换一个浏览器测试.
- 如何让Footer无论页面长短都在最底部, 并和正文保持固定高度?
html结构: <div id="container"> <div id="content">页面正文</div> < ...
- NOI openjudge 1792.迷宫
一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由n * n的格点组成,每个格点只有2种状态,.和#,前者表示可以通行后者表示不能通行.同时当Extense处在某个格点时,他只 ...