高一高考集训欢乐赛

大石碎胸口——万能青年旅店
久违的头图

image

渔王还想 继续做渔王
而海港已经 不知去向
此刻他醉倒 在洗浴中心
没有潮汐的梦
胸口已暮色苍茫
肥胖的城市 递给他一个
传统的方法 来克制恐慌
卖掉武器 风暴喉咙
换取饮食
背叛能让你获得自由
停电之后 暂时摆脱了
坚硬的时刻 倒转的河
肥胖的城市
驱赶着所有 拒绝沉没的人
那首疯狂的歌又响起
电灯熄灭 物换星移 泥牛入海
黑暗好像 一颗巨石 按在胸口
独脚大盗 百万富翁 摸爬滚打
黑暗好像 一颗巨石 按在胸口

高一高考集训欢乐赛

少有的 IOI 赛制。

雀食唐氏,和名字一样。

赛时榜

image

T1 Efim与奇怪的成绩

模拟。

只是注意几个点:

  1. 只能在小数部分进位;
  2. 输出时不要后缀 \(0\) 和小数点;
  3. 注意在整数部分的进位。

主要思想是,进位的位置越靠前越大,然后轻松在第 3 个小时才打出来,主要是既没大样例又看不到测试点,到了不得不去想那 WA 掉的 15 分时才绞尽脑汁想到整数的进位问题。

code:
namespace Wisadel
{
	short main()
	{
		cin>>n>>m;
		scanf("%s",ss+1);
		while(k<=n&&ss[k]!='.')k++;
		//找到小数点 
		int i=k+1;
		for(;i<=n;)
		{
			if(!m)
				break;
			int num=ss[i]-'0';
			if(num>=5)
			{//能进位就进 
				int pp=i,sds=i;
				while(pp<=n)
					ss[pp++]=0;
				//后面全部不要 
				n=sds;m--;
				//更新现在实数的长度 剩余的次数 
				if(--i==k)
				{//小数部分没了 
				//因为整数部分不可四舍五入 所以无论如何要结束循环 
					ss[i]=0;
					if(ss[i-1]=='9') 
					{//多重进位 
						while(--i>0&&ss[i]=='9')
							ss[i]='0';
						//都变成0 
						if(i==0)
						{//全部都进一 然后没了 也就是整数部分都是9 
							printf("1");
							printf("%s\n",ss+1);
							//把多的1输出来 然后输出后面的0 
							return Ratio;
						}
						else
						{
							ss[i]++;
							printf("%s\n",ss+1);
							//不全是9 直接进位后输出 
							return Ratio;
						}
					}
					else
						ss[--i]++;
					break; 
				}
				else
				{
					ss[i]++;
					i=k+1;
					//没到整数部分,那么从十分位再次循环寻找进位机会 
					continue; 
				}
				
			}
			i++; 
		}
		while(k<=n&&(ss[n]=='0'||ss[n]=='.'))
			ss[n--]=0;
		//去除后缀0和. 
		cout<<ss+1;
		return Ratio;
	}
}

T2 美丽的IP地址

暴搜就行,不过。。。

image

所以仙姑。

T3 装饰

仅有的好切的水题。

感觉下发的题解少有的讲得清楚。就是当三种颜色没有一种特别多(指超过其他两种颜色的 2 倍)时,都可以通过补凑的方法补齐,此时答案为 \(\frac{a+b+c}{2}\)

当存在上述一种特别多的颜色时,无论如何补凑都只能达到 \(a+b\) (我们假设 \(a\le b\le c\) ),也就是此时的答案。

注意 long long

code:
namespace Wisadel
{
	void Wmov()
	{
		if(a>b) swap(a,b);
		if(a>c) swap(a,c);
		if(b>c) swap(b,c);
	}
	short main()
	{
		int T=qr;
		while(T--)
		{
			a=qr,b=qr,c=qr;
			Wmov();
			if(a==0&&b==0)
				printf("0\n");
			else if(c>2*(a+b))
				printf("%lld\n",a+b);
			else printf("%lld\n",(a+b+c)/3);
		}
		return Ratio;
	}
}

T4 大子矩阵Largest Submatrix

出生题,搜就完了。

真是醇搜啊,想了单调栈和坐标 dp,最后还真是暴力。

感谢 PEP 提供的借鉴。

code:
namespace Wisadel
{
	bool Wck(int i,int j,int x,int y)
	{
		if(dh[i][j]==dh[x][y]||(dh[i][j]=='a'||dh[i][j]=='b')&&dh[x][y]=='w'||(dh[i][j]=='b'||dh[i][j]=='c')&&dh[x][y]=='x'||(dh[i][j]=='b'||dh[i][j]=='c'||dh[i][j]=='a')&&dh[x][y]=='z'||(dh[i][j]=='c'||dh[i][j]=='a')&&dh[x][y]=='y')return true;
		if(dh[x][y]==dh[i][j]||(dh[x][y]=='a'||dh[x][y]=='b')&&dh[i][j]=='w'||(dh[x][y]=='b'||dh[x][y]=='c')&&dh[i][j]=='x'||(dh[x][y]=='b'||dh[x][y]=='c'||dh[x][y]=='a')&&dh[i][j]=='z'||(dh[x][y]=='c'||dh[x][y]=='a')&&dh[i][j]=='y')return true;
		return false;
	}
	void W(int i,int j)
	{
		ll sumi=1;
		fo(k,j+1,m)
			if(Wck(i,j,i,k))
				sumi++;
			else break;
		ans=max(ans,sumi);
		ll sumj = 1;
		fo(k,i+1,n)
			if(Wck(i,j,k,j))
				sumj++;
			else break;
		ans=max(ans,sumj);
		ll mi=sumi;
		fo(ii,i+1,sumj+i-1)
		{
			ll sum=1;
			fo(jj,j+1,sumi+j-1)
				if(Wck(i,j,ii,jj))
					sum++;
				else break;
			mi=min(mi,sum);
			ans=max(ans,mi*(ii-i+1));
		}
	}
	short main()
	{
		while(scanf("%d%d",&n,&m)!=EOF) 
		{
			memset(dh,0,sizeof dh);
			ans=0;
			fo(i,1,n)
				fo(j,1,m)
					cin>>dh[i][j]; 
			fo(i,1,n)
				fo(j,1,m)
					if(dh[i][j]=='w')
					{
						dh[i][j]='a';W(i,j);
						dh[i][j]='b';W(i,j);
						dh[i][j]='w';
					}
					else if(dh[i][j]=='y')
					{
						dh[i][j]='a';W(i,j);
						dh[i][j]='c';W(i,j);
						dh[i][j]='y';
					}
					else if(dh[i][j]=='z')
					{
						dh[i][j]='a';W(i,j);
						dh[i][j]='b';W(i,j);
						dh[i][j]='c';W(i,j);
						dh[i][j]='z';
					}
					else if(dh[i][j]=='x')
					{
						dh[i][j]='b';W(i,j);
						dh[i][j]='c';W(i,j);
						dh[i][j]='x';
					}
					else
						W(i,j);
			printf("%lld\n",ans);
		}
		return Ratio;
	}
}

T5 中国象棋

有很多转移方程的 dp。

image

雀食像棋。

首先审题,得到一个关键结论:一行或一列中最多只能有两个炮

那么为了确定场上时刻的局势,我们令 \(f_{i,j,k}\) 为转移到第 \(i\) 行,有 \(j\) 列含有一个炮,\(k\) 列含有两个炮,那么可知,\(m-j-k\) 列没有炮。

我们按放炮的方式推。每行最多放两个炮,那么会有三种情况。

一,不放炮,由上一行的情况直接转移。

\[f_{i,j,k}=f_{i-1,j,k} \]

二,放一个炮,那么又会有两种情况,一种是放在没有炮的列上,一种是放在有一个炮的列上。

\[f_{i,j,k}+=f_{i-1,j-1,k}\times (m-j-k+1) \quad(j\ge 1) \]

\[f_{i,j,k}+=f_{i-1,j+1,k-1}\times (j+1) \quad(k\ge 1) \]

三,放两个炮,有三种情况,一是都放在没有炮的列上,二是一个放在有一个炮的列上,另一个放在没有炮的列上,三是两个都放在有一个炮的列上。

\[f_{i,j,k}+=f_{i-1,j-2,k}\times C(m-j-k+2,2) \quad(j\ge 2) \]

\[f_{i,j,k}+=f_{i-1,j,k-1}\times j\times (m-j-k+1) \quad (k\ge 1) \]

\[f_{i,j,k}+=f_{i-1,j+2,k-2}\times C(j+2,2) \quad(k\ge 2) \]

这里 \(C(n,m)\) 为组合数。

边界为 \(f_{0,0,0}=1\),最后答案是\(\sum_{0\le i\le m,0\le j\le m}f_{n,i,j}\pmod {9999973}\)

注意 long long

code:
namespace Wisadel
{
	int C(int x,int y)
	{
		return ((x*(x-1))/y)%mod;
	}
	short main()
	{
		n=qr,m=qr;
		zl[0][0][0]=1;
		fo(i,1,n)//行 
		//一行最多放两个炮 
			fo(j,0,m)//一个炮列 
				fo(k,0,m-j)//两个炮列 
				{
					zl[i][j][k]=zl[i-1][j][k];//这一行不放炮 
					//两个炮的列++
					if(k>=2)
						zl[i][j][k]+=zl[i-1][j+2][k-2]*C(j+2,2);//在两个1炮列上放 
					if(k>=1)
						zl[i][j][k]+=zl[i-1][j+1][k-1]*(j+1),//在一个1炮列上放 
						zl[i][j][k]+=zl[i-1][j][k-1]*j*(m-j-k+1);//在没有炮的列上放 
					//一个炮的列++ 
					if(j>=1)
						zl[i][j][k]+=zl[i-1][j-1][k]*(m-j-k+1);//放在没炮的列
					if(j>=2) 
						zl[i][j][k]+=zl[i-1][j-2][k]*C(m-j-k+2,2);//放在两个没炮的列 
					zl[i][j][k]%=mod;
				}
		fo(i,0,m)
			fo(j,0,m)
				ans=(ans+zl[n][i][j])%mod;
		printf("%lld\n",(ans+mod)%mod);
		return Ratio;
	}
}

T6 奇妙的 Fibonacci

雀食奇妙,还没有人 AC。


完结撒花~

image

posted @ 2024-06-12 14:51  DrRatio  阅读(74)  评论(7编辑  收藏  举报