• 【牛客练习赛87 E】贪吃蛇


    题目

    题目链接:https://ac.nowcoder.com/acm/contest/11177/E

    牛牛在玩贪吃蛇,玩贪吃蛇吃掉别的蛇就会变长。牛牛的蛇被别人吃掉后,发现可以看广告复活,且复活后长度不变。
    牛牛想到了一个作弊的高招,他和他邀请的 (n-1) 个朋友进入同一个房间玩贪吃蛇,初始时一共有 (n) 条蛇,第 (i) 条蛇的长度为 (L_i)
    进入游戏后,首先牛牛从这 (n) 条蛇中选择一条蛇作为自己的蛇,然后他的第 (1) 个朋友从剩下的 (n-1) 条蛇中选择一条蛇,然后他的第 (2) 个朋友从剩下的 (n-2) 条蛇中选择一条蛇 (cdots) 直到牛牛的第 (n-1) 个朋友选择蛇后,游戏开始,现在他们互相吃掉对方。
    设蛇 (A) 此时的长度 (L_A) ,蛇 (B) 此时的长度 (L_B) ,蛇 (A) 吃掉蛇 (B) 后蛇 (A) 长度会变为 (L_A+L_B),而蛇 (B) 则需要看 (x) 秒广告复活。
    牛牛的朋友都会帮助牛牛使牛牛的蛇变得尽可能的长,牛牛想知道,(M) 秒后牛牛的蛇最长可以是多长?(注意从时刻 (0) 开始就可以吃了)
    (假设蛇吃蛇不花时间,可以无限次复活,除了吃蛇没有其它方式可以变长,房间里除了牛牛和牛牛的朋友外没有别人)
    由于答案可能很大,你只需要输出答案对 (10^9+7) 取模的结果。多测。

    (Q,nleq 50)(1leq L_i,x,Mleq 10^6)

    思路

    首先一秒内可以进行任意次吃的操作,不难发现,如果某个时刻存在两条蛇都活着,那么肯定是其中一条立刻吃掉另一条。如果拖后了再吃或者不吃肯定都不会更优。
    所以这个 (m)(x) 都是假的,其实就是说可以进行 (m'=frac{m}{x}+1) 轮互吃,且每一轮都只剩一下一条活着。
    而且我们也不用去关心牛牛选的是哪一条蛇,最后活下来的那一只就给牛牛即可。所以我们只关心最大化 (m') 轮后 (L) 中的最大值。
    对于初始的序列 (L),把他从小到大排序,如果只能合并一次的话,容易发现是让 (n-1)(n)(n-2)(n-1),一直到 (1)(2) 这样最优。
    而吃完后这个序列从单调不降变为了单调不增,所以如果还需要继续合并,那么就是从前往后依次合并。那么其实就是一直重复从后往前,从前往后这两个合并的过程。
    因为 (nleq 50),所以直接上矩阵快速幂即可。如果 (m') 是奇数,最后还需要多乘一次。
    时间复杂度 (O(Qn^3log m))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=52,MOD=1e9+7;
    int Q,n,t,m;
    
    struct Matrix
    {
    	int a[N][N];
    	
    	friend Matrix operator *(Matrix a,Matrix b)
    	{
    		Matrix c;
    		memset(c.a,0,sizeof(c.a));
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=n;j++)
    				for (int k=1;k<=n;k++)
    					c.a[i][j]=(c.a[i][j]+1LL*a.a[i][k]*b.a[k][j])%MOD;
    		return c;
    	}
    }a,b,f;
    
    void fpow(Matrix &a,Matrix &f,int k)
    {
    	for (;k;k>>=1,a=a*a)
    		if (k&1) f=f*a;
    }
    
    int main()
    {
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		memset(f.a,0,sizeof(f.a));
    		memset(a.a,0,sizeof(a.a));
    		memset(b.a,0,sizeof(b.a));
    		scanf("%d%d%d",&n,&t,&m);
    		m=(m)/t+1;
    		for (int i=1;i<=n;i++)
    			scanf("%d",&f.a[1][i]);
    		sort(f.a[1]+1,f.a[1]+1+n);
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=n;j++)
    				a.a[i][j]=b.a[n-i+1][n-j+1]=(i>=j);
    		b=a*b; fpow(b,f,m/2);
    		if (m&1)
    		{
    			f=f*a;
    			cout<<f.a[1][1]<<"
    ";
    		}
    		else cout<<f.a[1][n]<<"
    ";
    	}
    	return 0;
    }
    
  • 相关阅读:
    自动构建部署
    EF 性能调优
    断点续传
    gis 相关资料
    easyui 特殊操作
    KJ面试
    前端面试题汇总
    es6之扩展运算符 三个点(...)
    vue.js开发环境搭建
    gulp 环境搭建
  • 原文地址:https://www.cnblogs.com/stoorz/p/15168778.html
Copyright © 2020-2023  润新知