day1

road

题意

有n(\(n \leq 10^5\))个数\(a_1,a_2,...,a_n\)排成一排,每次可以选择一段大于零的数减一,问最少几次把所有数减为0。

题解

先想到一个简单的策略:当处理到区间\([l,r]\)时,找出其中的最小值出现的位置\(k\),对这个区间进行\(a_k\)次区间减一,再分别处理\([l,k-1]\)和\([k+1,r]\)。
但是区间\([l,r]\)要是有很多个最小值,出现位置为\(k_1,k_2,\)...\(,k_p\),该怎么办?想必是没什么影响的。对这个区间进行最小值次区间减一后,\(k_1,k_2,\)...\(,k_p\)上的数都变成0,选其中的哪一个作为断点都没什么区别。
要想维护区间最值,用st表就行了。

代码

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<stack>
#include<vector>
#include<queue>
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define maxn 100010
using namespace std;
int read()
{int x=0,f=1;char ch=getchar();while(!isdigit(ch)&&ch!='-')ch=getchar();if(ch=='-')f=-1,ch=getchar();while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();return x*f;
}
void write(int x)
{if(x==0){putchar('0'),putchar('\n');return;}if(x<0){putchar('-'),x=-x;}char ch[20];int f=0;while(x)ch[++f]=x%10+'0',x/=10;while(f)putchar(ch[f--]);putchar('\n');
}
int n,d[maxn],st[20][maxn],lg[maxn],ans=0;
int MIN(int l,int r)
{int len=r-l+1;return d[st[lg[len]][l]]<=d[st[lg[len]][r-(1<<lg[len])+1]]?st[lg[len]][l]:st[lg[len]][r-(1<<lg[len])+1];
}
void work(int l,int r,int lst)
{int minx=MIN(l,r);ans+=(d[minx]-lst);if(l<=minx-1)work(l,minx-1,d[minx]);if(minx+1<=r)work(minx+1,r,d[minx]);return;
}
int main()
{n=read();rep(i,1,n)d[i]=read(),st[0][i]=i;lg[0]=-1;rep(i,1,n)lg[i]=lg[i>>1]+1;rep(k,1,lg[n])for(int i=1;i+(1<<k)-1<=n;i++)st[k][i]=d[st[k-1][i]]<=d[st[k-1][i+(1<<(k-1))]]?st[k-1][i]:st[k-1][i+(1<<(k-1))];work(1,n,0);write(ans);return 0;
}

money

题意

有\(n\)(\(n\leq 100\))个数\(a_1,a_2,\)...\(,a_n\)(\(\forall i\in[1,n],a_i\leq25000\))。
定义“凑出”是:当存在一个\(n\)个数的数列\(t_1,t_2,\)...\(,t_n\)使\(\sum_{i=1}^n a_i*t_i \space= k\)时,k能被这n个数凑出。
求最小的数\(m\),使存在m个数\(b_1,\)...\(,b_m\),这些数能凑出\(a_1,\)...\(,a_n\)能凑出的所有数,凑不出\(a_1,\)...\(,a_n\)凑不出的所有数。
共\(T\)(\(T\leq20\))组输入。

题解

把这\(n\)个数中所有能被\(n\)个数中的其它数凑出的删掉。
正确性:假设数\(x\)能被\(n\)个数中的其它数凑出,那么\(x\)能凑出的数一定能被凑出\(x\)的数凑出,删掉\(x\)后,原来能凑出的数还能被凑出。
最优性:那么这个可以用反证法来证明,假设存在一种删去了p个数,又添加了q(q<p)个数的方法比只删数更优。为了让方法更优,添加的数一定不能被未删除的数凑出。但是,这样添加的数就是原来凑不出的数,现在能凑出了,与题意不符。所以添加数不会使答案更优,只删掉能被凑出的数就行了。
需要判断每个数能否被凑出,这是个完全背包问题。

代码

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<stack>
#include<vector>
#include<queue>
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define maxk 25010
#define maxn 110
using namespace std;
int read()
{int x=0,f=1;char ch=getchar();while(!isdigit(ch)&&ch!='-')ch=getchar();if(ch=='-')f=-1,ch=getchar();while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();return x*f;
}
void write(int x)
{if(x==0){putchar('0'),putchar('\n');return;}if(x<0){putchar('-'),x=-x;}char ch[20];int f=0;while(x)ch[++f]=x%10+'0',x/=10;while(f)putchar(ch[f--]);putchar('\n');
}
int yes[maxk],t,maxpos,a[maxn],n,ans,maxlim;
int main()
{t=read();while(t--){n=read(),ans=n;maxlim=maxpos=0;rep(i,1,n)a[i]=read(),maxlim=max(maxlim,a[i]);rep(i,1,maxlim)yes[i]=0;yes[0]=1;sort(a+1,a+n+1);rep(i,1,n){if(yes[a[i]]){ans--;continue;}rep(j,0,maxpos){if(j+a[i]>maxlim)break;if(yes[j])yes[j+a[i]]=1,maxpos=max(maxpos,j+a[i]);}}write(ans);}return 0;
}

track

题意

有一棵有\(n\)(\(n\leq5*10^4\))的树,有边权。
要把这棵树拆成\(m\)条链,链之间可以有公共点,但不能有公共边。
求一种拆分方案,使边权和最小的链边权和最大。

题解

“最大值最小”显然是需要二分的,然后就是判断这棵树能否拆成不少于m条边权和大于等于k的链。
这样问题就转换成:对于每个点,选若干对儿子,使得每一对中,两个儿子向下连的直链长度,加上该点到两个儿子的边大于等于\(k\),在剩下儿子中选择向下的直链长度加该点到这个儿子的边长度最长的作为该点向下的直链。需要找出一种方法使选出的儿子对的个数尽可能多,在此基础上,该点向下的直链长度尽可能长。
\(l_i\)表示在处理完\(i\)的子树后,点\(i\)向下连的链最长有多长。
在计算完点\(u\)的所有儿子\(v_i\)的\(l_{v_i}\)后,将所有儿子按\(l_{v_i}+i到这个儿子的距离\)排序,第\(j\)个记作\(a_j\)。
这样问题就变成在单调不降数列\(a_1,\)...\(,a_p\)中,选出若干对数,同一个数只能被选一次,使每一对的和大于等于\(k\),选出的数对的个数尽可能多,在此基础上,剩下的数中最大的数尽可能大。
如果只用考虑数对个数最多,就可以这样:找出位置\(q\)使\(k\leq a_q+a_{q+1}\)且\(k\geq a_{q-1}+a_q\),那么对于小于\(a_q\)的数,只有在大于\(a_q\)的数中才能找到与它相加大于\(k\)的。那么就可以从\(a_{q-1}\)到\(a_1\),判断是否存在\(i\)使\(a_i\)未被选且\(当前数+a_i\geq k\),如果有,就取符合条件的最小的\(a_i\)。判断完所有小于\(a_q\)的数后,未被选的大于等于\(a_q\)的数直接两两配对就行了。以上过程的时间复杂度是\(O(n)\)的,可以维护一个指针\(i\),初始位置为\(q\),每当\(当前数+a_i\leq k\)时,右移\(i\),因为随着当前数减小,符合条件的与它配对的数是不断增大的。
那要是要考虑在选出数对个数最多的基础上,剩下的数的最大值尽可能大呢?看上去没有简单的贪心策略。先有个暴力的想法:枚举最后剩下的数中的最大值,求删掉枚举的数后的数列中最多能选出多少对。会发现删掉较大的数后的答案肯定不会比删掉较小的数的答案更大,也就是有单调性。那么只要先二分出剩下的数的最大值,再贪心求出删掉该数后最多能凑出几对就行了。

代码

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<stack>
#include<vector>
#include<queue>
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define maxn 50010
#define maxm 100010
using namespace std;
int read()
{int x=0,f=1;char ch=getchar();while(!isdigit(ch)&&ch!='-')ch=getchar();if(ch=='-')f=-1,ch=getchar();while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();return x*f;
}
void write(int x)
{if(x==0){putchar('0'),putchar('\n');return;}if(x<0){putchar('-'),x=-x;}char ch[20];int f=0;while(x)ch[++f]=x%10+'0',x/=10;while(f)putchar(ch[f--]);putchar('\n');
}
int num,ans,mid,n,m,fa[maxn],fir[maxn],nxt[maxm],v[maxm],w[maxm],sons;
int tofa[maxn],son[maxn],tmp[maxn],tn,mk[maxn],len[maxn],L=10001,R,cnt,tmpnum;
void ade(int u1,int v1,int w1){v[cnt]=v1,w[cnt]=w1,nxt[cnt]=fir[u1],fir[u1]=cnt++;}
int getx(int u){return len[u]+tofa[u];}
bool cmp(int x,int y){return getx(x)<getx(y);}
void check(int lim)
{tmpnum=tn=0;int pos=0;rep(i,1,sons)if(i!=lim)tmp[++tn]=son[i];rep(i,1,tn-1)if(getx(tmp[i])+getx(tmp[i+1])>=mid){pos=i;break;}if(pos==0){return;}else{rep(i,1,tn)mk[i]=0;int b=pos+1,c=0;dwn(a,pos,1){if(b>tn)break;while(b<tn&&getx(tmp[a])+getx(tmp[b])<mid)b++;if(getx(tmp[a])+getx(tmp[b])>=mid)mk[a]=mk[b]=1,b++,tmpnum++;else break;} rep(i,pos+1,tn)if(!mk[i])c++;tmpnum+=c/2;}
}
void getans(int u)
{for(int k=fir[u];k!=-1;k=nxt[k])if(v[k]!=fa[u]){getans(v[k]);}sons=0;for(int k=fir[u];k!=-1;k=nxt[k])if(v[k]!=fa[u]){if(getx(v[k])>=mid)num++;else son[++sons]=v[k];}if(sons==0){len[u]=0;return;}sort(son+1,son+sons+1,cmp);int pos=0;rep(i,1,sons-1)if(getx(son[i])+getx(son[i+1])>=mid){pos=i;break;}if(pos==0){len[u]=getx(son[sons]);return;}else{int l=1,r=sons,ansnum=0,anslen=0;check(0);ansnum=tmpnum;while (l<=r){int mi=(l+r)>>1;check(mi);if(tmpnum>ansnum||(tmpnum==ansnum&&getx(son[mi])>anslen))ansnum=tmpnum,anslen=getx(son[mi]),l=mi+1;else r=mi-1; }num+=ansnum,len[u]=anslen; }return;
}
int check()
{num=0;rep(i,1,n)len[i]=0;getans(1);if(num>=m)return 1;else return 0;
}
void getfa(int u)
{for(int k=fir[u];k!=-1;k=nxt[k])if(v[k]!=fa[u])tofa[v[k]]=w[k],fa[v[k]]=u,getfa(v[k]);
}
int main()
{n=read(),m=read();memset(fir,-1,sizeof(fir));rep(i,1,n-1){int x=read(),y=read(),z=read();ade(x,y,z),ade(y,x,z);L=min(L,z),R+=z;}getfa(1);while(L<=R){mid=((L+R)>>1);int f=check();if(f)ans=max(mid,ans),L=mid+1;else R=mid-1;}write(ans);fclose(stdout);return 0;
}

day2

travel

题意

有一棵有\(n\)(\(n\leq 5000\))个点的树或基环外向树。
每个点只能走一次,求字典序最小的DFS序。

题解

如果是树,就贪心地先走编号更小的儿子。
有环的话,就枚举删掉环上的哪条边,变成树。
需要注意的是,要在枚举删边之前将每个点的儿子排序。要不然\(O(n^2 log n)\)会被卡。

代码

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define maxn 5010
using namespace std;
int read()
{int x=0,f=1;char ch=getchar();while(!isdigit(ch)&&ch!='-')ch=getchar();if(ch=='-')f=-1,ch=getchar();while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();return x*f;
}
void write(int x)
{if(x==0){putchar('0'),putchar(' ');return;}int f=0;char ch[20];if(x<0)putchar('-'),x=-x;while(x)ch[++f]=x%10+'0',x/=10;while(f)putchar(ch[f--]);putchar(' ');return;
}
int to[maxn][maxn],tl[maxn],qx[maxn],qy[maxn],num,n,m,nox,noy,vis[maxn],ans[maxn],tmp[maxn],tmpn,cntq,yes;
void work(int u)
{vis[u]=1,tmp[++tmpn]=u;rep(k,1,tl[u])if(!vis[to[u][k]]&&(u!=nox||to[u][k]!=noy)&&(u!=noy||to[u][k]!=nox))work(to[u][k]);
}
void getcir(int u,int fa)
{vis[u]=1;rep(k,1,tl[u]){if(to[u][k]!=fa){if(vis[to[u][k]]){yes=1;qx[++cntq]=u,qy[cntq]=to[u][k];return;}else{getcir(to[u][k],u);if(yes==1){if(u==qy[1])yes=-1;qx[++cntq]=u,qy[cntq]=to[u][k];return; }if(yes)return;}}}
}
void upd()
{if(ans[1]!=0){rep(i,1,n){if(tmp[i]<ans[i])break;if(tmp[i]>ans[i])return;}}rep(i,1,n)ans[i]=tmp[i];return;
}
int main()
{n=read(),m=read();rep(i,1,m){int x=read(),y=read();to[x][++tl[x]]=y,to[y][++tl[y]]=x;}rep(i,1,n)sort(to[i]+1,to[i]+tl[i]+1);if(n-1==m){work(1);rep(i,1,n)write(tmp[i]);return 0;}getcir(1,0);rep(i,1,cntq){nox=qx[i],noy=qy[i];tmpn=0;rep(i,1,n)vis[i]=0;work(1);upd();}rep(i,1,n)write(ans[i]);return 0;
}

game

自闭了,不写。

defence

自闭了,不写。

总结

爆零就完事儿了
我记得有一次我接了个任务:砍五只大野猪
我想:我都是个上位猎人了,单挑火龙一家、两只雷狼都不带掉血的,五只大野猪算什么?
于是拿着古结云大剑,啥都没穿,啥都没拿就去了
结果被秋名山猪神安排得明明白白的,虽然完成了,但是过程不太愉快
可能有一些方面是因为轻敌,但主要还是走位不够灵活、预判不够精准及时、对地形的运用不够好导致的
活用道具、合理配置装备,确实是比较重要的
但要想在技术上更进一步,就必须尝试脱离这些东西,只靠自己的脑子和手战斗
在这种情况下能够通关后,也该尝试着在通关速度上更进一步,或者用不常使用的武器(大剑、片手以外的所有武器。。。)通关
\(\color{white}{\text{事实上,这个任务上位猎人拿脚玩都没问题……所以,你知道我只是在比喻,对吧?}}\)
我什么时候才能成为能裸装零针迅龙的大剑使呢?

转载于:https://www.cnblogs.com/xzyf/p/9997668.html

并不对劲的noip2018相关推荐

  1. [NOIP2018]普及组游记

    想不到自己还有机会写游记 --sysky 考完一个月后 DAY -INF 报名 还为了拍照下载了一个PS 特地把自己P白了一点233 花里胡哨得提交了rg.noi.cn DAY -14~-2 停课集训 ...

  2. 【NOIP2018】 游记

    All ended? [day 0] 一点感觉没有,不过翘掉了早上的课(当然还有前三周的课),然后刚想睡一会儿,就被通知要上车了/难受 在车上玩了一会儿早上下的Super Mario(主要是早上刷了一 ...

  3. noip2018——题解总结

    近期正在疯狂复习某些东西,这篇博客尽量年底更完--(Day2T2除外) 好了,所有的希望都破灭了,原来这就是出题人的素质.--一个被欺骗的可怜 $OIer$ 人生中倒数第三次 $noip$ (Mayb ...

  4. CCF关于对NOIP2018复赛违规处罚的公告

    NOIP2018复赛于11月10-11日在全国31个赛区同时举行,现已结束.总体有序,但也有赛区出现违规现象.现将复赛中违规情况进行通报. 一.数据提交情况 CCF要求NOI各省组织单位在考试结束后在 ...

  5. 并不对劲的概率与期望

    并不觉得今天学到了什么东西-感觉像上了数学课一样- 很对劲的太刀流-> 一.枚举法 初二数学就有提到的.不过,有时算出的概率和直觉并不相符,所以并不能直接凭感性认识,并不对劲的人有时还得理性分析 ...

  6. NOIP2018退役记

    NOIP2018退役记 手动博客搬家: 本文发表于20181112 08:25:07, 原地址https://blog.csdn.net/suncongbo/article/details/83961 ...

  7. NOIP2018 退役记

    手动博客搬家: 本文发表于20181112 08:25:07, 原地址https://blog.csdn.net/suncongbo/article/details/83961273 以下为退役记 1 ...

  8. NOIP2018——总结油记

    油记 Day 0 这天一大早去校运会开幕式,摇着个旗子毫无违和感,经过主席台中间的一位老师不屑一顾地鼓着掌--无一不体现了今年校运会之无趣. 赶紧逃离校运会后,开始到机房努力刷手感. symbol对高 ...

  9. NOIP2018提高组比赛总结

    NOIP2018提高组比赛总结 前言 新赛季,依旧有很多失误. 在些许的遗憾和无奈中,NOIP2018,撒花结束 纵观今年的整一场NOIP,有许多值得总结的地方 正文 NOIP2018初赛 第二次参加 ...

最新文章

  1. 未来数据中心的选择:宽带多模光纤
  2. c#发送http请求
  3. 【Android 逆向】Android 权限 ( Android 逆向中使用的 android.permission 权限 | Android 系统中的 Linux 用户权限 )
  4. android广播面试题,Android相关面试题
  5. C++中#ifndef/#define/#endif使用详解
  6. iOS一些推荐的学习路径发展
  7. SAP Data Intelligence Modeler里的Kafka Producer和Kafka Consumer
  8. ubuntu 目录及文件权限 000 444 666 777(转)
  9. MS SQL 能否修改实例名称
  10. IOC操作Bean管理XML方式(FactoryBean)
  11. AI新时代-大神教你使用python+Opencv完成人脸解锁(附源码)
  12. 安装squid_「首席推荐」设置Squid转发代理或者正向代理
  13. colab显示没有gpu的解决方法
  14. Android Bitmap(位图)详解
  15. linux建模工具有哪些,linux uml 免费 建模工具
  16. NFT推动全球加密艺术浪潮
  17. UCF101动作识别数据集
  18. 设备划分冲突域和广播域
  19. java能自学吗_java能自学吗?
  20. php radio是什么意思,radio是什么意思_radio在线翻译_英语_读音_用法_例句_海词词典...

热门文章

  1. seo全攻略_SaaS 企业推广获客全攻略(2):如何做好企业官网?
  2. STM32H743+CubeMX-计算FDCAN2上的MessageRAMOffset(使两路FDCAN正常工作)
  3. linux禁止防火墙命令,LINUX关闭打开防火墙命令
  4. xgboost参数_XGBoost实战和参数详解
  5. HTML期末作业-中国足球网页
  6. oracle备份信息在控制文件丢失,恢复之利用备份在所有控制文件丢失情况下恢复(一)...
  7. mysql root命令_设置更改root密码、连接mysql、mysql常用命令
  8. 更新widget 导致widget host(home) 挂掉
  9. mongodb 分组聚合_mongodb 聚合命令
  10. 存储器空间或者桌面堆_向爱因斯坦学习桌面管理之道