佳木斯集训Day4考试

今天又打了两道题的正解 这次没出锅 稳rk1

在这里插入图片描述
稳?唉我还是Too young, too naive…
在这里插入图片描述
wtm

思维题(thinking)

题目描述
题目背景: Dilhao在成为毒瘤出题人的道路上,出的第一题是一道思维题
jmsyzsfq吃饭总喜欢用三根筷子,而且每次三根筷子的长度都不相同,Dilhao很好奇,终于有一天他鼓起勇气问jmsyzsfq说:你为什么吃饭总是用三根筷子呢?jmsyzsfq告诉Dilhao,他每次吃饭用的三根筷子都可以拼成一个三角形,并且三根筷子的长度的异或和为0,他想考考Dilhao,如果他用的筷子长度都不超过n,那么他有几种筷子组合可以使用?
Dilhao还是不知道jmsyzsfq为什么吃饭要用三根筷子,但是jmsyzsfq保证如果Dilhao帮他解决了难题,他就请Dilhao吃完饭,Dilhao现在想请你帮帮他解决一下这道难题,这样他就能在饭桌上好好研究一下jmsyzsfq为什么用三根筷子吃饭,
输入
输入一个整数n,表示jmsyzsfq的三根筷子长度都不能超过n
输出
输出包含一个整数为jmsyzsfq能用的筷子组合数
样例输入
【样例 1 输入】
6
【样例 2 输入】
10
样例输出
【样例 1 输出】
1
【样例 2 输出】
2
提示
【样例1解释】
只存在一种筷子组合为3,5,6。
3^ 5 ^6=0且3,5,6可以组成三角形
【数据范围与约定】
对于20%的数据,n≤10。
对于50%的数据,n≤100。
对于100%的数据,n≤2500。
n ≤ 2500 n≤2500 n2500?我第一反应想的不是这题 O ( n 2 ) O(n^2) O(n2)可过 而是打表 [滑稽]
打表程序

#include<cstdio>
int main()
{
    
    
	freopen("text.txt","w",stdout);
	printf("a[]={0,0,0");
	for(int i=3;i<=2500;i++)
	{
    
    
		long long ans=0;
		for(int j=1;j<=i;j++)
		{
    
    
			for(int k=j;k<=i;k++)
			{
    
    
				for(int l=k;l<=i;l++)
					if(j!=k&&k!=l&&l!=j&&j+k>l&&j+l>k&&k+l>j&&j^k^l==0)ans++;
			}
		}
		printf(",%lld",ans);
	}
	printf("];\n");
}

O ( n 3 ) O(n^3) O(n3) 2个小时稳出表 不过…
打着打着就想出正解了…
因为a^ b ^c=0 所以c=a ^b 换个角度 已经确定两个数a、b 那么c一定是确定的
所以直接 O ( n 2 ) O(n^2) O(n2) 注意下不要加重 所以要存一下已经加过的
上代码

#include<cstdio>
int maxx(int a, int b){
    
    return a>b?a:b;}
int minn(int a, int b){
    
    return a<b?a:b;}
int maxxx(int a, int b, int c){
    
    return maxx(maxx(a,b),c);}
int minnn(int a, int b, int c){
    
    return minn(minn(a,b),c);}
bool check(int a, int b, int c){
    
    return (a+b>c&&b+c>a&&c+a>b);}
int n;
long long ans;
bool vis[2501][2501];
int main()
{
    
    
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
    
    
		for(int j=1;j<=n;j++)
		{
    
    
			int k=i^j;
			if(k<=n&&i!=j&&j!=k&&i!=k&&check(i,j,k))
			{
    
    
				if(!vis[minnn(i,j,k)][maxxx(i,j,k)])
				{
    
    
					ans++;
					vis[minnn(i,j,k)][maxxx(i,j,k)]=true;
				}
			}
		}
	}
	printf("%lld\n",ans);
}

数论题(math)

题目描述
题目背景:Dilhao在成为毒瘤出题人的道路上,出的第二题是一道数论题
versky在学校操场上找到了三个蚂蚁群A,B,C,每个蚂蚁群分别有x,y,z个蚂蚁窝,这三个蚂蚁群之间势如水火,如果在两个不同蚂蚁群的蚂蚁窝之间放上一根小木棍,那么这两个蚂蚁窝里的蚂蚁就会展开战斗,假设versky有无限多的小木棍,每个小木棍的长度为1,versky希望同一个蚂蚁群的蚂蚁窝之间的距离大于2,这样蚂蚁们的战斗才会变得更加精彩,现在versky想问问你,一共有几种放置小木棍的方案?
输入
输入三个整数x,y,z,表示三个蚂蚁群的蚂蚁窝数量
输出
输出包含一个整数为versky放置小木棍的方案数,由于结果过大,你需要将结果取模998244353
样例输入
【样例 1 输入】
1 1 1
【样例 2 输入】
1 2 2
【样例 3 输入】
6 2 9
样例输出
【样例 1 输出】
8
【样例 2 输出】
63
【样例 3 输出】
813023575
提示
【题目解释】
以样例2为例,如图所示,上面两图是合法的方案,下面两图的情况是不被允许的,注意,整张图不一定连通
在这里插入图片描述
【数据范围与约定】
对于 30%的数据,x,y,z≤2。
对于50%的数据,x,y,z≤100。
对于 100%的数据,x,y,z≤3,000。
首先我们需要知道 每两个集合之间选的窝是需要一一对应的。理由是:题中说每个集合中的任意两个窝的距离要大于2 而如果同一集合的两个窝如果连到另一集合的同一个窝 它们之间的距离就为2。
其次,集合两两之间的联通对第三个集合的答案没有影响。所以答案 a n s = a n s 1 ∗ a n s 2 ∗ a n s 3 ans=ans1*ans2*ans3 ans=ans1ans2ans3
那么问题来了 如何求每两个集合之间的ans?
前面说过 每两个集合之间的窝是要一一对应的 显然两个集合选出窝的个数是一样的
设两个集合的窝数 窝数??? 分别为 n n n m m ,选出 i i i个窝 那么这 i i i个窝连线的总方案为 i ! i ! i!
选出i个窝的方案为 ( n i ) × ( m i ) × i ! \binom{n}{i}×\binom{m}{i}×i! (in)×(im)×i!
所以两两集合之间连线的方案为 ∑ i = 0 m i n ( n , m ) ( n i ) × ( m i ) × i ! \sum_{i=0}^{min(n,m)} \binom{n}{i}×\binom{m}{i}×i! i=0min(n,m)(in)×(im)×i!
上代码

#include<cstdio>
typedef long long ll;
const ll mod=998244353,N=3000;
ll minn(ll a, ll b){
    
    return a<b?a:b;}
ll x,y,z,ansx,ansy,ansz,now,fac[3001],facinv[3001],inv[3001];
ll C(ll n, ll m){
    
    return fac[n]*facinv[m]%mod*facinv[n-m]%mod;}
int main()
{
    
    
	inv[1]=fac[1]=fac[0]=facinv[1]=facinv[0]=1;
	for(ll i=2;i<=N;i++)
	{
    
    
		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		fac[i]=fac[i-1]*i%mod;
		facinv[i]=facinv[i-1]*inv[i]%mod;
	}
	scanf("%lld%lld%lld",&x,&y,&z);
	now=minn(x,y);
	for(ll i=0;i<=now;i++)(ansx+=(C(x,i)*C(y,i)%mod*fac[i]%mod))%=mod;
	now=minn(y,z);
	for(ll i=0;i<=now;i++)(ansy+=(C(y,i)*C(z,i)%mod*fac[i]%mod))%=mod;
	now=minn(z,x);
	for(ll i=0;i<=now;i++)(ansz+=(C(z,i)*C(x,i)%mod*fac[i]%mod))%=mod;
	printf("%lld\n",ansx*ansy%mod*ansz%mod);
}

T3最短路 由于 D a w n Dawn Dawn 现场只会打 45 B 45B 45B的代码还被扣了 30 30 30分…所以一会儿改完会补上
补不补就不一定了 D a w n Dawn Dawn的嘴 骗人的鬼
显然 D a w n Dawn Dawn是一个靠谱的男人 D a w n Dawn Dawn 会了这道题正解了
先上题

题目描述
题目背景:Dilhao在成为毒瘤出题人的道路上,出的第三题是一道图论题
Blackjack又一次来到了J市,可迎接他的,只有无尽的黑暗。
Blackjack在一个深夜从火车站下了火车,他想去宾馆,但是他很怕黑,假设把J市的街道看成一个n*m的网格图,每个网格代表一个路口,其中有k个路口的路灯是亮的,火车站在标号为(1,1)的路口,而宾馆在标号为(n,m)的路口,Blackjack想保证自己只走亮灯的路口,但很显然只靠k盏灯是无法到达目的地的,这时候Blackjack想起了万能的zP1nG,他给zP1nG打了个电话,zP1nG告诉他自己可以让某一条街道(横行或纵行)的路灯全部亮起,但每次这么做会消耗zP1nG一份rp,而且如果他要让另一条街道上的路灯亮起,就必须要先关掉上一条街道上自己打开的路灯,也就是说在这个过程中Blackjack必须站在某个始终亮起的路口,保证火车站始终是亮着灯的,问Blackjack能不能顺利到达目的地?如果能,那么他最少需要花费zP1nG多少rp?
输入
第一行包括三个整数n,m,k,表示J市的长宽以及亮灯的数量
下面k行,每行2个整数x,y,表示坐标为(x,y)的路口有灯。
输出
输出包含一个整数为zP1nG最小花费的rp数量,如果Blackjack无法到达目的地,那么输出-1
样例输入
【样例1输入】
4 4 5
1 1
2 1
2 3
3 3
4 3
【样例2输入】
5 5 4
1 1
2 1
3 1
3 2
【样例 3 输入】
2 2 4
1 1
1 2
2 1
2 2
样例输出
【样例 1 输出】
2
【样例 2 输出】
-1
【样例 2 输出】
0
提示

这道题要用到 S P F A SPFA SPFA 不会 S P F A SPFA SPFA的可以看博客SPFA的两种优化里面还有两种优化 S L F SLF SLF优化和 L L L LLL LLL优化
你肯定要问为什么不能用 d i j k s t r a dijkstra dijkstra算法 好问题 因为用 d i j k s t r a dijkstra dijkstra就不能推博客了
本题是一道最短路裸题 相邻的两个点之间边权为0 横或纵坐标距离差小于等于2的两个点之间边权为1
直接跑一遍最短路就能得出答案
上代码

#include<cstdio>
#include<cstring>
#include<deque>
using namespace std;
int abss(int a){
    
    return a>0?a:-a;}
struct node
{
    
    
	int nxt,to,val;
}edge[40001];
int n,m,k,cnt,dis[3003],x[3003],y[3003],head[3003];
bool check,vis[3003];
deque<int> q;
inline void read(int &x)
{
    
    
	int s=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){
    
    s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
	x=s;
}
inline void addedge(int u, int v, int w)
{
    
    
	edge[++cnt].to=v;
	edge[cnt].nxt=head[u];
	edge[cnt].val=w;
	head[u]=cnt;
}
inline void superadd(int u, int v, int w)
{
    
    
	addedge(u,v,w);
	addedge(v,u,w);
}
void Shortest_Path_Faster_Algorithm(int s)
{
    
    
	q.push_back(s);
	while(!q.empty())
	{
    
    
		int u=q.front();q.pop_front();vis[u]=false;
		for(int i=head[u];i;i=edge[i].nxt)
		{
    
    
			int v=edge[i].to;
			if(dis[v]>dis[u]+edge[i].val)
			{
    
    
				dis[v]=dis[u]+edge[i].val;
				if(!vis[v])
				{
    
    
					vis[v]=true;
					if(q.empty()||dis[v]>dis[q.front()])q.push_back(v);
					else q.push_front(v);
				}
			}
		}
	}
}
int main()
{
    
    
	read(n);read(m);read(k);
	for(int i=1;i<=k;i++)
	{
    
    
		read(x[i]);read(y[i]);
		if(x[i]==n&&y[i]==m)check=true;
		for(int j=1;j<i;j++)
		{
    
    
			if((abss(x[i]-x[j])==1&&y[i]==y[j])||(abss(y[i]-y[j])==1&&x[i]==x[j]))superadd(i,j,0);
			else if(abss(x[i]-x[j])<=2||abss(y[i]-y[j])<=2)superadd(i,j,1);
		}
	}
	if(!check)
	{
    
    
		for(int i=1;i<=k;i++)if(y[i]==m||x[i]==n||y[i]==m-1||x[i]==n-1)superadd(i,k+1,1);
		k++;
	}
	memset(dis,0x7f,sizeof(dis));
	dis[1]=0;vis[1]=true;
	Shortest_Path_Faster_Algorithm(1);
	if(dis[k]==dis[k+1])puts("-1");
	else printf("%d\n",dis[k]);
}

有问题可以发在评论区或者加 Q Q 407694747 QQ407694747 QQ407694747我们一起讨论
各位大佬各路神犇多多指教!

猜你喜欢

转载自blog.csdn.net/dhdhdhx/article/details/97653270