集训日记:DAY5

集训日记:DAY5

现在晚上22:54分,为什么我现在才开始写日记?都是因为一道傻逼题和一篇傻逼题解……


写在前面的吐槽:

今天得知集训还tm 有5天!!!天天模拟赛真搞得心力憔悴……今天可还行吧,在挂了110分的情况下还水到了90分,混了个第9……


今天提前考了10min——7:50到了就发题了。
还是先遍历一遍
T1我一眼就认出我以前做过的一道分治题,然后……忘了怎么写了……
T2读完题正解毫无头绪,满脑子都是priority_queue暴力
一看数据范围……嚯!好像能水50分!
T3图上倍增?好像挺可做的
T4正解毫无头绪,但是只有一个w[1]>0的20分好像能递推搞出来?
(此时过去20min)
遍历之后我既定的开题顺序是先开T1,然后写T2,T4暴力,最后把大头时间砸在T3上
然后回头去看T1
越看越肯定这题必然做过
肯定是分治分成4块和4种状态,但是具体怎么实现怎么判断却毫无头绪……
(看旁边qyt和lq都在做T1,而且敲的可欢了……)
此时心态有点炸……
又试着写了40min,我果断放弃
因为上次模拟赛的经验告诉我:

永远不要再模拟赛上写你不确定的东西!

于是赶紧放弃
然后去写T2的暴力
由于写T2的时候我忘记了小根的pq怎么写,所以只好手写小根堆
是不是听起来不可思议
然后出奇的顺利,20min写完调完
再转战去推T4
T4我发现w[1]的宽度每+1,就相当于在w[1]-2的长度里放粗线
我设f[i]=dp[w[i]-2];(这里埋下伏笔)
然后我打表找规律,打到i=7的时候发现了递推式,即f[i]=f[i-1]+f[i-2]+1;
然后就愉快地通过了样例和自己造的样例
(此时过去了2h)
下面看T3
T3刚开始我是想把1到n的最短路跑出来,然后二进制拆分
这个思路从想到调通样例花了30min
然后本着严谨的态度,我又自己造了一组数据测了一下
不测不知道,一测下一跳,出锅了!
因为有的不是最短路的路却是2^k,所以我的思路有误!
然后我就想先把1到n的所有路径枚举出来,然后比较时间
这个代码写的时候re了几次,但是还算顺利吧
花了30min写完调完,自己造的样例也过了
(此时过去3h)
看时间还有1h,我又回头去看T1
仍然没敢贪正解,发现有30分打表可以过!
于是开始打表,花了30min打完并通过样例
(打的时候发现傍边的lq也在打表,我俩相视一笑……)
最后30min仔细检查了freopen,数组大小等问题
期望得分:30+50+100+20=200


下午吃完饭回来看分,只有90……好在排名还不算难看……
就T1和期望得分一样,其余均挂分了……
先看T2,发现是压堆的时候忘记取模,导致中途越界……50->20
T3没什么说的,少考虑了自环的情况,而且本身复杂度不够优秀 100->30
T4我找了好半天,才发现我求的是f[]数组而不是dp[]!!!20->10
这些错误还是体现出经验不足,不够仔细,以后还需改正!
(话说T1我回去一看果然做过,还是一次AC……)


最后贴上正解和标程(我订正的就贴了我的)

T1奇怪的道路

题目来源:POJ3889
注意到对于一个正方形,沿横竖两条中线可以将城市切分成 4 个编号连续的
段,每段占用一个大小为原来 1/4 的正方形,并且 4 个正方形结构都与原来的大
正方形结构相似,也可以继续分解。
因此对于一个编号,先查询其在哪一块,之后递归下去查询这个编号在这一
块中的相对坐标,回退时逐步更新为当前正方形中的绝对坐标即可。


当年的一次AC代码……

#include<bits/stdc++.h>
using namespace std;
long long am[5][2]={{0,0},{0,0},{0,1},{1,1},{1,0}};
long long n,a,b,t,x1,x2,y3,y2;
void build1(long long l,long long x,long long &y,long long &z)
{
	long long ax=y,bx=z;
	if(l==1) y=bx,z=ax;
	if(l==4)
	{
		long long k=pow(2,x);
		y=bx;z=ax;
		y=k-y-1;z=k-z-1;
	}
}
void build(long long l,long long x,long long &y,long long &z)
{
	if(l==0) return;
	long long k=pow(2,2*(l-1)),i;
	for(i=1;i<=4;i++) if(k*i>=x) break;
	build(l-1,x-(i-1)*k,y,z);
	build1(i,l-1,y,z);
	y+=pow(2,l-1)*am[i][0];
	z+=pow(2,l-1)*am[i][1];
}
int main()
{
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		scanf("%lld%lld%lld",&n,&a,&b);
		x1=x2=y2=y3=0;
		build(n,a,x1,x2);
		build(n,b,y3,y2);
		long long ans=round(sqrt(pow((x1-y3)*10,2)+pow((x2-y2)*10,2)));
		printf("%lld\n",ans);
	}
	return 0;
}

T2商店

假如能够以某种方式二分答案 ans,那么就可以直接计数确定<=ans 的物品
个数,现在需要考虑的是如何二分这个答案 ans
最终的答案 ans 的表示有两个属性——物品种类以及购买次数,使用比较暴
力一点的思路,比如可以枚举第 k 种商品买了几个,设为 t 个,接下来二分一下
有多少种商品买了至少 t+1 个,这样就可以确定要买的最贵的商品的价格,做一
个计数就可以。
另外考虑到,二分答案后验证计数过程中,假设有 x<k 个商品买了 y 个,那
么应该只有 x/2 个商品买了 y+1 个,因此最终购买方案里第 1 种商品和第 k 种商
品购买数量相差最多是 O(logk)这个级别的——这意味着,在我们上一段所描述
的比较暴力的思路中,让 t 在 n/k 附近 O(logk)个取值枚举即可——事实上 O(1)
个取值似乎也是可以的。
这道题做法应该比较多,欢迎分享实现起来更简单或者思路更好的做法


这题正解和标程完全不可读……建议参考这篇题解
注意: 这篇题解里有一些可爱的傻逼的 小错误,请读者自行寻找参悟
虽然我找出来了但是花了快4h,所以我就不说哪有错误,要怪就怪作者吧,而且他的代码还会TLE哦!

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=105;
const int mod=1e9+7;
int n,k;
int solve(int x)
{
	if(x==0) return 0;
	return x+solve(x/2);
}
int find(int l,int r)
{
	if(l>r) return 0;
	if(r==0) return 0;
	return r-l+1 + find((l+1)/2,r/2);
}
ll ksm(ll x,int k)
{
	ll ans=1,res=x;
	while(k)
	{
		if(k&1) ans=ans*res%mod;
		res=res*res%mod;
		k>>=1;
	}
	return ans;
}
void work(int k,int n)
{
	int tot=solve(n/2);
	if(k<=tot) {work(k,n/2);return;}
	k-=tot;
	int o=k/n,p=k%n;
	if(p==0)
	{
		printf("%lld\n",n*ksm(2,o-1)%mod);
		return;
	}
	int st=n/2+1,ed=n;
	while(st<ed)
	{
		int mid=st+ed>>1;
		if(find(n/2+1,mid)>=p) ed=mid;
		else st=mid+1;
	}
	printf("%lld\n",st*ksm(2,o)%mod);
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&k,&n);
		work(k,n);
	}
	return 0;
}

T3跑路

在这里插入图片描述


我忘记判环,并且做法过于暴力,还是正解香……但是标程是真的不可读

#include<bits/stdc++.h>
using namespace std;
int f[105][105][31],dis[105][105],t,n,m;
int main()
{
	cin>>t;
	while(t--)
	{
		memset(f,0,sizeof(f));
		memset(dis,0x3f,sizeof(dis));
		cin>>n>>m;
		for(int i=1;i<=m;i++)
		{
			int u,v;
			cin>>u>>v;
			f[u][v][0]=1;
		}
		if(n==1)
		{
			cout<<"0"<<endl;
			return 0;
		}
		for(int k=1;k<=30;k++)
			for(int l=1;l<=n;l++)
				for(int i=1;i<=n;i++)
					for(int j=1;j<=n;j++)
						f[i][j][k]|=f[i][l][k-1]&&f[l][j][k-1];
		for(int k=0;k<=30;k++)
			for(int i=1;i<=n;i++)
				for(int j=1;j<=n;j++)
					if(f[i][j][k])
						dis[i][j]=1;
		for(int k=1;k<=n;k++)
			for(int i=1;i<=n;i++)
				for(int j=1;j<=n;j++)
					dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
		cout<<dis[1][n]<<endl;
	}
	return 0;
}
/*
1
4 4
1 1
1 2
2 3
3 4
*/

T4阶梯

在这里插入图片描述


矩阵乘法优化云云,为我不会者也~~

#include<bits/stdc++.h>
using namespace std;
const int N=8,n=7,S=1<<n,mod=1000000007;
struct matrix
{
	long long a[S][S];
}f,ans;
int w[N]={},s=2;
matrix operator*(const matrix &m1,const matrix &m2)
{
	static matrix tmp;
	for(int i=0;i<s;++i)
		for(int j=0;j<s;++j)
			tmp.a[i][j]=0ll;
	for(int i=0;i<s;++i)
		for(int j=0;j<s;++j)
			for(int x=m1.a[i][j],k=0;k<s;++k)
				(tmp.a[i][k]+=x*1ll*m2.a[j][k])%=mod;
	return tmp;
}
int main()
{
	freopen("stairs.in","r",stdin);
	freopen("stairs.out","w",stdout);
	for(int i=0;i<S;++i)
		f.a[i][i]=ans.a[i][i]=1;
	for(int t=1;t<=n;++t,s<<=1)
	{
		cin>>w[t];
		for(int i=0;i<s;++i)
			for(int j=0;j<s;++j)
			{
				int tot[N][2]={};
				tot[0][0]=1;
				for(int k=0;k<t;++k)
				{
					tot[k+1][0]=tot[k+1][1]=tot[k][0]+tot[k][1];
					if(!(i&(1<<k)) && !(j&(1<<k)))
						tot[k+1][0]-=tot[k][0];
				}
				f.a[i][j]=tot[t][0];
			}
		for(int y=w[t]; y ; f=f*f,y>>=1)
			if(y&1)
				ans=f*ans;
	}
	cout<<ans.a[0][0]<<endl;
	return 0;
}

困困……溜了溜了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值