NOIP2018 失学记及部分题解

Day-3

据说今年HN试用自动收代码系统。如果真丢了就可以再次体验奥妙重重的Day3人工还原代码了。。

下午就跑去试机,真实模拟坐车晕车。

Day-2

被叫去搞心理辅导…??然后就出现了下面这幕


“你配合一下,下次就免死”

“OK”

……

“好,那接下来就是最后一局游戏~”
在这里插入图片描述

Day-1

考试差点翻车.jpg

下午做了两道51nod,晚上就去围观看猫和老鼠

Day 0

要去爬岳麓山。去年NOIP前也说要爬岳麓山来着,只不过因为下雨咕咕咕了

话说有没有人能帮忙奶一下不考高精度啊qwqqq还有去年考了tarjan今年应该不考吧??
突然boshi告诉我逛公园的零环是要建立在于最短路不超过k的前提下的,我好像压根就没注意到…

爬完山腿废了…还有就是天气不错。回来的时候挤的公交,强行挤上去.jpg,体验极差。

早知道还不如坐地铁呢=~=

Day1

发现坐的大巴竟然又是纯电动,想到今年省选晕车,不免有点方。虽然最后没有晕车

T1好像可以st表+分治,担心会爆栈,另写了一个做法,拍了拍感觉没毛病

T2好像是同余系最短路,等等noip出这么难的题?后来别人告诉我直接上完全背包就可以了。。

T3肯定要二分,dp好像很麻烦,应该是贪心。然后证明了一条链的lca深度越深越好,就开始拿set乱搞。结果死活过不去大样例,最烦的是写不出暴力来拍,但是拍了一众特殊数据却稳如*。开始怀疑贪心策略有问题…下考前不久突然发现自己在两两配对的时候从大到小找,可能导致传上去的不是最优的。想着贪心策略可能本来就有问题,可能来不及改了,就检查去了。。

后来发现只要改了这个地方就可A了。wwwwwoc??早知道就改了……但是这个错误贪心可以完美地过掉链和菊花还有m=1等特殊数据。。不知道能不能多骗点分??

下午听说都是原题。嗯嗯?只有我一个人没有AK系列

Day2

可能是我最近睡的都挺早,导致昨晚躺床上1h没睡着。。翻车预警

一拿到题目发现今天的画风不太对,劝退预警。T1不是很送分,T2看起来不友善,T3难道是树上动态dp??这是什么神仙操作,动态dp不是去年WC的新知识点吗,而且一上来就考树上动态dp??我考前还一直以为可能会引进数位dp,然后出一道数位dp的水题。

T1细节比较多,没写 O ( n 2 ) O(n^2) O(n2)的,写了个 O ( n log ⁡ n ) O(n\log n) O(nlogn)。但是好像写挂了几分,不知道CCF会出什么奇妙的数据。

然后就去看T2,以为只要保证每条斜线递减即可,高高兴兴地写状压dp。结果第二个样例都没过,然后以为我状压写挂了调试了一会,发现思路有问题。然后就先去看了T3,然后题目看错了。结果大样例过不去,当时一想,T2和T3都没分。。所以又回去做T2了,最后发现状压可以过n=2的点。

下考前一直没发现看错了T3的题意,直到下考后Dimitry_L告诉我看错题了…晚节不保

在洛谷上测的总分只有100+100+85+72+55+0=412

完全不应该浪费时间在T2上的,T2写完50分就应该赶紧丢,这样的话可能T3还能拿60+。另外感觉今年的题目区分度不够啊,可能分数会密集地分布在 [ 400 , 500 ] [400,500] [400,500]这个区间,wc无望了。。感觉像考了一次弱省省选。

下午思考了一下人生,至少感觉好多了,可能以后我会称D2T2为“一道送我退役的好题”吧。。

后续

猫锟说D2T3不是他出的,而且有一个离线后倍增的NOIP考点做法。
??强行NOIP考点?这实质上和动态DP的思想一致啊


现在想想觉得自己的心态还是大有问题,被难度设置打了个措手不及之后就慌了神,策略完全失误了。紧张感导致我没有按照最优策略去再搞搞D2T3,不然打好68分的暴力,可以说是比较正常的发挥吧,也能给HN的各位神仙垫个底了。。

而且做T2也没有往打表找规律的方向去思考,最后1.5h其实就没有拿分。求稳为重…

部分题解

D1T3

好像很多神仙都做过原题,应该算是一道看起来比较套路的题目。考场的时候脑子一抽想着方便实现就从后往前删死活过不了大样例。

显然可以二分,那么对于一个值mid,统计不短于mid的路径可以选出多少条。我们可以证明选取的道路的lca深度越深越优秀,那么就可以贪心了,在每一个点拿set存下已有的链的长度,然后考虑从小到大依次配对。

#include <cstdio>
#include <set>
using namespace std;
typedef long long ll;
const int maxn=50010;
template <typename Tp> int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> void read(Tp &x)
{
	x=0;char ch=getchar();int f=0;
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') f=1,ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	if(f) x=-x;
}
struct data{int v,w,nxt;}edge[maxn<<1];
int n,m,p,l,r,mid,cnt,ans,head[maxn];
multiset<int> s[maxn];
multiset<int>::iterator itr;
void insert(int u,int v,int w)
{
	edge[++p]=(data){v,w,head[u]};head[u]=p;
	edge[++p]=(data){u,w,head[v]};head[v]=p;
}
void input()
{
	int u,v,w;
	read(n);read(m);
	for(int i=1;i<n;i++)
	{
		read(u);read(v);read(w);
		insert(u,v,w);r+=w;
	}
}
int dfs(int x,int pre)
{
	int res=0,tmp;
	s[x].clear();
	for(int i=head[x];i;i=edge[i].nxt)
	  if(edge[i].v^pre)
	  {
	  	tmp=dfs(edge[i].v,x);
	  	if(tmp+edge[i].w>=mid) ++cnt;
	  	else s[x].insert(tmp+edge[i].w);
	  }
	while(s[x].size()>0)
	{
		tmp=*s[x].begin();
		s[x].erase(s[x].begin());
		itr=s[x].lower_bound(mid-tmp);
		if(itr!=s[x].end()) ++cnt,s[x].erase(itr);
		else getmax(res,tmp);
	}
	return res;
}
int main()
{
	freopen("track.in","r",stdin);
	freopen("track.out","w",stdout);
	input();
	while(l<=r)
	{
		mid=(l+r)>>1;cnt=0;
		dfs(1,1);
		if(cnt>=m) ans=mid,l=mid+1;
		else r=mid-1;
	}
	printf("%d\n",ans);
	return 0;
}

D2T2

神仙题,推导难度比D2T3难多了。。
满足条件的充要条件是

  • ∀ i ∈ ( 0 , n ) , j ∈ ( 0 , m ) A i , j ≥ A i − 1 , j + 1 \forall_{i\in(0,n),j\in(0,m)} A_{i,j}\geq A_{i-1,j+1} i(0,n),j(0,m)Ai,jAi1,j+1
  • A x , y = A x − 1 , y + 1 ⇒ ∀ i ∈ ( x , n ) , j ∈ ( y , m ) A i , j = A i − 1 , j + 1 A_{x,y}=A_{x-1,y+1}\Rightarrow\forall_{i\in(x,n),j\in(y,m)}A_{i,j}=A_{i-1,j+1} Ax,y=Ax1,y+1i(x,n),j(y,m)Ai,j=Ai1,j+1

再者就是大力分情况讨论,对每条对角线计数。由于详细讲解会花费大量的篇幅,所以就丢一篇良心讲解

#include <algorithm>
#include <cstdio>
#define rg register
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
int n,m,a1,a2,a3,ans,f[10];
inline int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int pp(int x){return pls(x,x);}
int power(int x,int y)
{
	int res=1;
	for(;y;y>>=1,x=(ll)x*x%mod)
	  if(y&1)
	    res=(ll)res*x%mod;
	return res;
}
int main()
{
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	read(n);read(m);
	if(n>m) swap(n,m);
	if(n==1){printf("%d\n",power(2,m));return 0;}
	if(n==2){printf("%lld\n",4ll*power(3,m-1)%mod);return 0;}
	if(n==3){printf("%lld\n",112ll*power(3,m-3)%mod);return 0;}
	for(rg int i=2;i<=n;i++) f[i]=pls(pp(pp(f[i-1])),20);
	a1=(ll)power(4,n-2)*power(2,n+1)%mod;
	a2=5ll*power(4,n-4)*power(2,n+1)%mod;
	a3=(ll)(15+pp(f[n-3]))*power(2,n)%mod;
	if(n==m){printf("%d\n",pls(a1,pls(a2,a3)));return 0;}
	ans=pls(a1,a2)*3ll%mod;
	ans=pls(ans,(3ll*f[n-3]+20)%mod*power(2,n));
	ans=pls(ans,pls((3ll*f[n-3]+16)%mod*power(2,n)%mod,12ll*power(2,n-1)%mod));
	ans=(ll)ans*power(3,m-n-1)%mod;
	printf("%d\n",ans);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值