NOIP2017提高组 模拟赛13(总结)

第一题 函数

【题目描述】



【输入格式】

  三个整数。

  1≤t<109+7,2≤l≤r≤5*106

【输出格式】

  一个整数。

【输出样例】

2 2 4

【输出样例】

19

【解题思路】

  证明:对于n个人,分解成质因数,按质数个人分为一组(从小到大)。

  例如:30可以分成2 * 3 * 5,那么一开始2人为一组,共有15组。再分成3人为一组,然后有5组。再分成5人一组,有1组。

  为什么这是最优的?



  a,b是n的质因数

  设\(\frac{n}{ab}=x\)

  \(bx\frac{a(a-1)}{2}+x\frac{b(b-1)}{2}=\frac{bx}{2}(a²-a+b-1)\)



  \(x\frac{ab(ab-1)}{2}=\frac{bx}{2}(a²b-a)\)

  ∵a,b>=2

  ∴(a²b-a)>(a²-a+b-1)

  由(a²-a+b-1)可得,a<b会比a>b优。

  证毕。

【代码】

#include<cstdio>
#include<algorithm> using namespace std; typedef long long ll; const ll mods=1e9+7;
const int N=7000000;
int pr[N],lp,n,L,R,t;
bool inp[N],re[N];
ll F[N],ans,tl; void getpr()
{
inp[1]=1;
for(int i=2;i<=n;i++)
{
if(!inp[i]) { pr[++lp]=i; F[i]=(((ll)i*(i-1))>>1)%mods; re[i]=1; }
for(int j=1;(ll)i*pr[j]<=n && j<=lp;j++)
{
F[pr[j]*i]=(F[pr[j]]*i%mods+F[i])%mods;
inp[pr[j]*i]=1;
if(!(i%pr[j])) break;
}
}
} int main()
{
freopen("2233.in","r",stdin);
freopen("2233.out","w",stdout);
scanf("%d%d%d",&t,&L,&R);
n=R; getpr(); tl=1ll; ans=0ll;
for(int i=L;i<=R;i++)
{
ll k=F[i];
ans=(ans+tl*k%mods)%mods;
tl=tl*t%mods;
}
printf("%lld\n",ans);
return 0;
}

第二题 部落

【题目描述】

  部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏。

  现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。

同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。

  如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。

你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。

【输入格式】

  第一行一个整数N

  接下来N行每行两个整数T1,T2,表示修该建筑需要T1秒,要在T2秒之前修完。

【输出格式】

  一个整数表示最多能抢救的建筑数量。

【输入样例】

4

100 200

200 1300

1000 1250

2000 3200

【输出样例】

3

【数据规模】

  对于40%的数据,T2<=1000000

  对于100%的数据,N <= 150,000; T1 < T2 < maxlongint

【解题思路】

  一个简单的推论:假若建筑i的T2<建筑j的T2,而且建筑i的T1≥建筑j的T1,总时间+T1<建筑j的T2,那么将i替换成j,答案会更优。(贪心)

  所以,用大根堆维护最大值,每次将最大值判断一下,是否需要替换掉即可。

【代码】

#include<cstdio>
#include<algorithm> using namespace std; typedef long long ll; const ll mods=1e9+7;
const int N=150500;
struct data { int a,b,id; } d[N];
int n,ans,h[N],cnt; bool cmp(data A,data B) { return (A.b<B.b); } void add(int x)
{
cnt++; h[cnt]=x;
int now=cnt;
while((now>1) && (d[h[now>>1]].a<d[h[now]].a))
{
swap(h[now>>1],h[now]);
now>>=1;
}
} void down()
{
h[1]=h[cnt]; cnt--;
int now=1;
while((now<<1)<=cnt)
{
int uw;
if((now<<1|1)>cnt) uw=now<<1; else uw=(d[h[now<<1]].a>d[h[now<<1|1]].a)?(now<<1):(now<<1|1);
if(d[h[now]].a<d[h[uw]].a) swap(h[now],h[uw]); else break;
now=uw;
}
} int main()
{
freopen("2234.in","r",stdin);
freopen("2234.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&d[i].a,&d[i].b),d[i].id=i;
sort(d+1,d+1+n,cmp);
int tim=0;
for(int i=1;i<=n;i++)
{
if(tim+d[i].a<=d[i].b)
{
tim+=d[i].a;
ans++; add(i);
} else
{
int yu=h[1];
if(d[yu].a>d[i].a)
{
tim+=d[i].a-d[yu].a;
down(); add(i);
}
}
}
printf("%d\n",ans);
return 0;
}

第三题 sunny图(原题 codeforces 603E)

【题目描述】



【输入格式】

  第一行两个整数n和m。

  接下来m行每行三个整数。ai,bi,li。

【输出格式】

  共m行,每行一个整数表示每次操作的答案。

【输入样例】

4 4

1 3 4

2 4 8

1 2 2

3 4 3

【输出样例】

-1

8

8

3

【数据规模】

  1≤ai,bi≤n,1≤li≤10^9

  对于20%的数据,2≤n小于等于15,1≤m≤15。

  对于40%的数据,2≤n小于等于100,1≤m≤100。

  对于60%的数据,2≤n小于等于500,1≤m≤2000。

  对于100%的数据,2≤n小于等于100000,1≤m≤300000。

【解题思路】

  一个重要的推论(然而并没有推出来):

  将图分成若干个联通块,每个联通块的点数均为偶数,那么就是sunny图。

  为什么?(分类讨论)

  假如有一个偶数点的图,一定可以划分成一棵树。

  那么设根节点为father,father的点数为奇数的儿子sonY一定为奇数个,奇 * 奇+偶 * (偶 或 奇)+1=偶。那么将sonX与father的边cut掉,就满足了father的度数为奇数(奇数条与儿子的边)的情况。

  那么点数为奇数的儿子sonY,仍保留与father的边。那么sonY的点数为奇数的儿子Y一定有偶数个,奇 * 偶+偶 * (偶 或 奇)+1=奇。那么将X与sonY的边cut掉,就满足了sonY的度数为奇数(偶数条与儿子的边+与父亲的边)的情况。

  点数为偶数的儿子sonX的情况与第一种类似(是完全一样好吧)。

  那么,树是自己造的,边随便搞,加入一条x->y的边,若x,y之前已经连通,就把路径上的最大边删了,加入新边(在新边小于最大边的情况下)

  至于联通块分成两个偶数块,判断删除最大边L后,剩下的两个联通块点数是否为偶数就行了。

  需要用LCT维护子树大小。

  具体应该是这样:

  多个splay树通过parent边相连。

  在每个splay树记录一个sub,表示整棵splay树的奇偶(仅仅是splay树)

  再记一个all,表示整个子树i包括相连的splay树的奇偶(在splay树合并或断开的时候更新)

【代码】

//codeforce 603E
#include<cstdio>
#include<algorithm>
#include<set> #define imax(a,b) ((a>b)?(a):(b))
#define imin(a,b) ((a<b)?(a):(b)) using namespace std; const int N=400010;
struct tree { int mx,val,sub,all,zi; } s[N];
int c[N][2],fa[N],rev[N];
int H[N],ht,W[N];
int n,m,odd,cnt;
int stack[N];
//int F[N];
struct godD { int a,b,l; } d[N];
//set <pair<int,int> > hp; bool gd(int x) { return (c[fa[x]][1]==x); } bool isroot(int x) { return (c[fa[x]][0]!=x && c[fa[x]][1]!=x); } int MAX(int x,int y)
{
if(!x || !y) return x+y;
return ((s[x].val>s[y].val)?(x):(y));
} void up(int x)
{
s[x].all=s[x].sub^s[x].zi;
s[x].mx=x;
if(c[x][0]) s[x].all^=s[c[x][0]].all;
if(c[x][1]) s[x].all^=s[c[x][1]].all;
s[x].mx=MAX(s[x].mx,s[c[x][0]].mx);
s[x].mx=MAX(s[x].mx,s[c[x][1]].mx);
} void down(int x)
{
if(rev[x])
{
rev[x]^=1;
rev[c[x][0]]^=1; rev[c[x][1]]^=1;
swap(c[x][0],c[x][1]);
}
} void rotate(int x)
{
int y=fa[x],z=fa[y];
int l=gd(x),r=!l;
if(!isroot(y)) c[z][gd(y)]=x;
fa[x]=z; fa[y]=x; fa[c[x][r]]=y;
c[y][l]=c[x][r]; c[x][r]=y;
up(y); up(x);
} void splay(int x)
{
int hy=0; stack[++hy]=x;
for(int i=x;!isroot(i);i=fa[i]) stack[++hy]=fa[i];
for(int i=hy;i;i--) down(stack[i]);
for(;!isroot(x);)
{
int y=fa[x];
if(!isroot(y)) (gd(x)^gd(y))?rotate(x):rotate(y);
rotate(x);
}
} void access(int x)
{
int y=0;
while(x)
{
splay(x);
down(x);
if(y) s[x].sub^=s[y].all;
if(c[x][1]) s[x].sub^=s[c[x][1]].all;
c[x][1]=y;
up(x);
y=x;
x=fa[x];
}
} void evert(int x)
{
access(x); splay(x); rev[x]^=1;
} int findroot(int x)
{
access(x); splay(x);
while(c[x][0]) x=c[x][0];
return x;
} void link(int x,int y)
{
evert(x); evert(y);
fa[x]=y; s[y].sub^=s[x].all;
up(y);
} void cut(int x,int y)
{
evert(x); access(y); splay(y);
fa[x]=0; c[y][0]=0;
up(y);
} void Cut(int u)
{
int x=d[u].a,y=d[u].b;
cut(x,u+n); cut(y,u+n);
} bool cle(int u)
{
int x=d[u].a,y=d[u].b;
cut(x,u+n); cut(y,u+n);
if(!s[x].all && !s[y].all) return 1;
link(x,u+n); link(y,u+n);
return 0;
} void add(int x)
{
H[++ht]=x; int now=ht;
while((now>1) && d[H[now>>1]].l<d[H[now]].l)
{
swap(H[now>>1],H[now]);
now>>=1;
}
} void hdown()
{
H[1]=H[ht--]; int now=1;
while((now<<1)<=ht)
{
int uw;
if(((now<<1)|1)>ht) uw=(now<<1); else uw=(d[H[now<<1]].l>d[H[now<<1|1]].l)?(now<<1):(now<<1|1);
if(d[H[now]].l<d[H[uw]].l)
{
swap(H[now],H[uw]);
} else break;
now=uw;
}
} //int findroot(int x) { return ((F[x]<0)?(x):(F[x]=findroot(F[x]))); } /*void uni(int x,int y)
{
int ix=findroot(x),iy=findroot(y);
if(F[ix]>F[iy]) swap(ix,iy);
F[ix]+=F[iy]; F[iy]=ix;
}*/ int main()
{
freopen("2235.in","r",stdin);
freopen("2235.out","w",stdout);
scanf("%d%d",&n,&m);
odd=n; ht=0;
for(int i=1;i<=n;i++) s[i].all=s[i].zi=1;
for(int i=1;i<=m;i++)
{
int lx,ly,cost;
scanf("%d%d%d",&lx,&ly,&cost);
d[i].a=lx; d[i].b=ly; d[i].l=cost;
s[i+n].val=cost; s[i+n].mx=i+n;
if(findroot(lx)!=findroot(ly))
{
evert(lx); evert(ly);
if(s[lx].all && s[ly].all) odd-=2;
link(lx,i+n); link(ly,i+n);
W[i]=1; add(i); //uni(lx,ly);
//hp.insert(make_pair(-cost,i));
} else
{
evert(ly); access(lx); splay(lx);
int yu=s[lx].mx;
if(s[yu].val>cost)
{
Cut(yu-n);
link(lx,i+n); link(ly,i+n);
W[i]=1; W[yu-n]=0; add(i);
//hp.erase(make_pair(-s[yu].val,yu-n));
//hp.insert(make_pair(-cost,i));
}
}
if(odd==0)
{
for(;;)
{
int yu=H[1];
if(!W[yu] || cle(yu)) hdown(); else break;
}
printf("%d\n",d[H[1]].l);
} else printf("-1\n");
/*if(odd==0)
{
for(;;)
{
int e=(*hp.begin()).second;
if(cle(e)) hp.erase(hp.begin()); else break;
}
printf("%d\n",-(*hp.begin()).first);
} else printf("-1\n");*/
}
return 0;
}

NOIP2017提高组 模拟赛13(总结)的更多相关文章

  1. NOIP2017提高组 模拟赛15(总结)

    NOIP2017提高组 模拟赛15(总结) 第一题 讨厌整除的小明 [题目描述] 小明作为一个数学迷,总会出于数字的一些性质喜欢上某个数字,然而当他喜欢数字k的时候,却十分讨厌那些能够整除k而比k小的 ...

  2. NOIP2017提高组模拟赛 10 (总结)

    NOIP2017提高组模拟赛 10 (总结) 第一题 机密信息 FJ有个很奇怪的习惯,他把他所有的机密信息都存放在一个叫机密盘的磁盘分区里,然而这个机密盘中却没有一个文件,那他是怎么存放信息呢?聪明的 ...

  3. NOIP2017提高组模拟赛 8(总结)

    NOIP2017提高组模拟赛 8(总结) 第一题 路径 在二维坐标平面里有N个整数点,Bessie要访问这N个点.刚开始Bessie在点(0,0)处. 每一步,Bessie可以走到上.下.左.右四个点 ...

  4. NOIP2017提高组模拟赛 9 (总结)

    NOIP2017提高组模拟赛 9 (总结) 第一题 星星 天空中有N(1≤N≤400)颗星,每颗星有一个唯一的坐标(x,y),(1≤x,y ≤N).请计算可以覆盖至少K(1≤K≤N)颗星的矩形的最小面 ...

  5. NOIP2017提高组模拟赛 7(总结)

    NOIP2017提高组模拟赛 7(总结) 第一题 斯诺克 考虑这样一个斯诺克球台,它只有四个袋口,分别在四个角上(如下图所示).我们把所有桌子边界上的整数点作为击球点(除了4个袋口),在每个击球点我们 ...

  6. NOIP2017提高组模拟赛5 (总结)

    NOIP2017提高组模拟赛5 (总结) 第一题 最远 奶牛们想建立一个新的城市.它们想建立一条长度为N (1 <= N <= 1,000,000)的 主线大街,然后建立K条 (2 < ...

  7. NOIP2017提高组模拟赛4 (总结)

    NOIP2017提高组模拟赛4 (总结) 第一题 约数 设K是一个正整数,设X是K的约数,且X不等于1也不等于K. 加了X后,K的值就变大了,你可以重复上面的步骤.例如K= 4,我们可以用上面的规则产 ...

  8. 计蒜客NOIP2017提高组模拟赛(三)day1

    火山喷发 火山喷发对所有附近的生物具有毁灭性的影响.在本题中,我们希望用数值来模拟这一过程. 在环境里有 n 个生物分别具有 A​1​​,A​2​​,⋯,A​n​​点生命值,一次火山喷发总计 MM 轮 ...

  9. 计蒜客NOIP2017提高组模拟赛(四)day1

    T1:小X的质数 小 X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的情感.小 X 认为,质数是一切自然数起源的地方. 在小 X 的认知里,质数是除了本身和 1 以外,没有其他因数的 ...

随机推荐

  1. LeetCode——Valid Parentheses

    Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the inpu ...

  2. C++实现位数组

    当我们遇到大量整数排序时候为了节省内存空间我们能够考虑使用bit数组来实现,缺点是其仅仅适用于正整数. 思想: 在32位系统一个int类型占4个字节,按位来计算一个int类型能够记录32个数.因此,採 ...

  3. Spring整合TimerTask实现定时任务调度

    一. 前言 近期在公司的项目中用到了定时任务, 本篇博文将会对TimerTask定时任务进行总结, 事实上TimerTask在实际项目中用的不多, 由于它不能在指定时间执行, 仅仅能让程序依照某一个频 ...

  4. $scope angular在controller之外调用

    1.定义 var m = angular.module('ddd',[]); m.controller('ctrl',['$scope',function ($scope) { }]); 2.外部调用 ...

  5. 浅谈for循环

    for循环 <script> /* ** (1) 是执行代码块之前 ** (2) 运行代码块的条件 ** (3) 需要执行的代码块 ** (4) 代码块执行后执行 ** 执行顺序是(1)( ...

  6. 从极大似然估计的角度理解深度学习中loss函数

    从极大似然估计的角度理解深度学习中loss函数 为了理解这一概念,首先回顾下最大似然估计的概念: 最大似然估计常用于利用已知的样本结果,反推最有可能导致这一结果产生的参数值,往往模型结果已经确定,用于 ...

  7. Qt-窗口部件概念介绍

    前言:包括基础窗口部件QWidget.对话框QDialog.QFrame类族 .按钮部件.行编辑器.数值设定框以及滑块部件. 一.基础窗口部件QWidget 窗口部件(Widget)是Qt中建立用户界 ...

  8. Spark RDD概念学习系列之Pair RDD的transformation操作

    不多说,直接上干货! Pair RDD的transformation操作 Pair RDD转换操作1 Pair RDD 可以使用所有标准RDD 上转化操作,还提供了特有的转换操作. Pair RDD转 ...

  9. Core Java(六)

    面向对象语言特性 (一) (一)  static 作用于 变量,方法,代码块 静态变量:被类的所有对象共享   在类加载时被加载   优先于对象 Student.country = "中国& ...

  10. Android开发实现QQ三方登录 标签: android开发qq三方登录

    本文分为两个部分:一是QQ的授权部分:二是获取用户的基本信息部分 一.授权部分 1.首先,先去腾讯开放平台获取APP ID和APP KEY(未注册腾讯开发者账号的可能需要先注册账号),获取的过程还是还 ...