7.27 18级牛客多校第六场

比赛过程

  

题解

B

题意

  给出一个 n * n 的 01 矩阵,求满秩的概率

解法

  这道题比较遗憾,是我们队当时花了较多时间去想但是没有想出来,很大的问题还是审题不清,比赛快结束了才看到“Note that when adding up two vectors, the components are modulo 2”这句话,还有就是最后求的是f1 xor f2…xor fn,之前做到过异或的题,然后就老是觉得这个异或应该能够结合公式化简,然而看了题解发现想多了,人家就是单纯的预处理。
  这道题首先是推波公式

  1. 对于第一个向量来说,只需要至少有一个位置为 1 即可,即全部为 0 的情况不满足条件,此时满足条件的情况为2^n-1
  2. 对于第二个向量来说,需要满足的条件是,不能全部为 0 ,且不能被第一个向量所表示,此时满足条件的情况为2^n-2
  3. 对于第三个向量来说,同样不能为 0,不能被第一个向量所表示,不能被第二个向量所表示,不能被第一个向量和第二个向量所表示,此时满足条件的情况为2^n-4
  4. 对于第四个向量来说,不能被前面向量表示的集合为 { ∅ , { 1 } , { 2 } , { 3 }, { 1 , 2 } , {1 , 3 } , { 2 , 3 } , { 1 , 2 , 3 } } ,共八种情况,所以此时满足条件的情况为2^n-8
  5. 对于第 n 个向量来说,不能被前面 n - 1 个向量单独或混合表示,此时满足条件的情况为2n-2{n-1}

  至于为什么不能被两个向量所表示要-1,是因为上面提到的那句话,相当于把向量的加减运算变成异或运算。
  最后可以推出:
在这里插入图片描述

代码
//头文件太长就不放了
ll Pow(ll a, ll b, ll mode)
{
  ll sum = 1;
  a = a % mode;
  while (b > 0)
  {
    if (b % 2 == 1) //判断是否是奇数,是奇数的话将多出来的数事先乘如sum
      sum = (sum * a) % mode;
    b >>= 1;
    a = (a * a) % mode; // 不断的两两合并再取模,减小a和b的规模
  }
  return sum;
}
ll inv(ll x)
{
	return Pow(x,mode-2,mode);
}
ll ans[MAXN];
int main()
{
	ll t;
	read(t);
	ll iv2=inv(2);
	ll f=ans[1]=iv2;
	ll tem=2;
	ll iv=iv2;
	re(i,2,2e7)
	{
		tem=tem*2%mode;
		iv=iv*iv2%mode;
		f=f*(tem-1ll+mode)%mode*iv%mode;
		ans[i]=ans[i-1]^f;
	}
	while(t--)
	{
		ll n;
		read(n);
		printf("%lld\n",ans[n]);
	}

}

C

题意

   一个矩阵的底面积定义为最后一行的数的和,重量定义为所有数的和,给一个正整数矩阵,找一个“压强”最大的可非连续子矩阵。

解法

  哈哈哈终于可以说这题不难了,仔细一想不难一定要选择单独的一列,应为如果选择两列,把他拆成两列单独算压强,一定会有一个比两者合起来的压强大,所以就是枚举一波底面即可。

代码
//code已去头
ll mp[205][205];
ll sum[205][205];
int main()
{
	int t;
	read(t);
	while(t--)
	{
		int n,m;
		read(n);
		read(m);
		ms(mp,0);
		ms(sum,0);
		re(i,1,n)
		re(j,1,m)
		{
			read(mp[i][j]);
			sum[i][j]=sum[i-1][j]+mp[i][j];
		}
		double ans=0.0;
		re(i,1,n)
		{
			re(j,1,m)
			{
				double tem=(double)sum[i][j]/(double)mp[i][j];
				ans=max(ans,tem);
			}
		}
		printf("%.10lf\n",ans);
	}
}

E

题意

  给定 n,k,问是否可以构造一个 1~n 的排列 P,使得对于 1~n 中任意的数 i,P 都存在一个长为 i 的子区间,其和模 n 余 k。有解输出任意一组,无解输出 -1。

解法

  根据n的奇偶性构造即可

代码
int main()
{
	int n,k;
	read(n);
	read(k);
	ll sum=(1+n)*n/2;
	sum%=n;
	if(sum!=k)
	{
		printf("-1\n");
		return 0;
	}
	if(n%2)
	{
		re(i,1,n/2)
		{
			printf("%d %d ",i,n-i);
		}
		printf("%d\n",n);
	}
	else
	{
		re(i,1,n/2-1)
		{
			printf("%d %d ",i,n-i);
		}
		printf("%d %d\n",n/2,n);
	}
}

K

题意

• K-bag序列定义为由多个1-k的排列顺序连接起来的序列
• 想问你给定序列是不是k-bag的连续子序列

解法

  比赛时曹老师摸到的这道题,摸出来感觉很难,后来确实也没什么想法,看到人家用滑窗加类似dp的思想过了有点吃惊,滑窗的操作之前有遇到过,但这次没想到,趁这次加深映像。
  先判断串中有没有大于K的数,有的化直接就-1;然后从1开始维护一个长度为K的滑窗,每次滑动后求滑窗内的数字总类,如果等于K或者等于当前的下标i(由于我们已经排除了包含大于K数字的串,因此这种情况只会出现在 i < = K i<=K i<=K的情况下,这是为了处理串前端存在部分 K − p e r m u t a t i o n K -permutation Kpermutation的情况)如果这时 i < = K i<=K i<=K我们就将当前点的状态 c a n [ i ] can[i] can[i] 置为可行,就是表示从1到这个点可以构成 K − b a g K-bag Kbag,如果 i > K i>K i>K就另 c a n [ i ] = c a n [ i − k ] can[i]=can[i-k] can[i]=can[ik],表示 i − k i-k ik i i i 这一段是一个 K − p e r m u t a t i o n K -permutation Kpermutation,1到 i i i 能否构成 K − b a g K-bag Kbag取决于 c a n [ i − k ] can[i-k] can[ik]。最后倒着从n往下遍历,最多遍历K长度,维护当前遍历到的种类,如果能够遍历到一个点 c a n [ i ] = t r u e can[i]=true can[i]=true并且当前点的种类等于当前遍历的长度,那么整个序列就可以构成 K − b a g K-bag Kbag,反之不行。最后这一步主要是为了处理后端存在部分 K − p e r m u t a t i o n K -permutation Kpermutation的情况。

代码
//还有这题又是一道卡map的题
unordered_map<ll, int> mp;
ll a[MAXN];
bool can[MAXN];
int main()
{
	ll t;
	read(t);
	while (t--)
	{
		ll n, k;
		read(n);
		read(k);
		mp.clear();
		ms(can, 0);
		bool flag2 = 0;
		re(i, 1, n)
		{
			read(a[i]);
			if (a[i] > k)
			{
				flag2 = 1;
			}
		}
		if (flag2)
			{printf("NO\n");continue;}
		ll kind = 0;
		re(i, 1, n)
		{
			if (i > k)
			{
				mp[a[i - k]]--;
				if (mp[a[i - k]] == 0)
					kind--;
			}
			if (!mp[a[i]])
				kind++;
			mp[a[i]]++;
			if (kind == k || kind == i)
			{
				if (i > k)
					can[i] = can[i - k];
				else
					can[i] = 1;
			}
		}
		mp.clear();
		kind = 0;
		bool flag = 0;
		de(i, n, max(1ll, n - k))
		{
			if (can[i] && kind == n - i)
			{
				flag = 1;
				break;
			}
			if (!mp[a[i]])
				kind++;
			mp[a[i]]++;
		}
		if (flag == 0)
			printf("NO\n");
		else
			printf("YES\n");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值