牛客练习赛87 部分题题解

k小数查询

我就说题目描述中说到什么算法,就一定不会用到什么算法...果然在想清楚之前最好还是不要打代码,不然就是wrong,调,wrong,调...陷入死循环...考虑这个题,考虑x肯定是一个关键,先找到x的位置,那么左端点一定小于等于os(x的下标位置)。思考后发现小于x的数十分关键,并且我们要保证合法的区间中一定只有k-1个小于x的数。既然如此,我们就将所有小于x的数的下标放到一个数组里,枚举每个左端点,统计每个左端点对答案的贡献。对于每个左端点而言,首先必须保证右端点要大于等于os,其次这个区间里只能有k-1个比x小的数字。那我们直接在刚才存过的数组里面找当前k-1个数组的下标即可,并且可以直接根据下一个小于x的位置计算答案。....

//不等,不问,不犹豫,不回头.
#include<bits/stdc++.h>
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define P 1000000007
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define ull unsigned long long
#define put(x) printf("%d
",x)
#define putl(x) printf("%lld
",x)
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
#define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=200010;
int n,k,a[N],x,b[N],num;

inline int read()
{
    int x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}

int main()
{
    //freopen("1.in","r",stdin);
	get(n);get(x);get(k);
	int os;
	rep(i,1,n) 
	{
		get(a[i]);
		if(a[i]==x) os=i;
	}	
	int sum=0;
	rep(i,1,n)  
	{
		if(a[i]<x) 
		{
			b[++num]=i;
			if(i<os) sum++;	
		}	
	}
	b[num+1]=n+1;
	ll ans=0; 
	int dd=1;
	rep(i,1,os)//枚举每一个左端点。
	{
		int ss=dd;//ss表示当前i这个点离得最近的小于x的下标在b中的下标。 
		if(sum<=k-1&&ss+k-2<=num)
		{
			ans+=b[ss+k-1]-max(b[ss+k-2],os);
		}
		if(i==b[dd]) dd++,sum--;
	} 
	putl(ans);
    return (0^_^0);
}
//以吾之血,铸吾最后的亡魂.

牛老板

好吧,我承认是我失去了勇气,没有继续思考下去...
考虑这个题,如果只用6和9的话,显然每个数都能转化成6进制数和9进制数,那么用的纸币的数量就是转化成的6进制数和9进制数下所有位数的和,考虑两个一起用的话,怎样会使答案更优,显然是某些数,在转化成9进制数时,其中某部分所有位数的和非常大,但用6进制的话就很简单了。如果这个不理解的话,可以这样想,每个数都可以写成若干个9的次幂相乘的形式,(当然了前面是有系数的但系数小于等于8),我们考虑如何用(6^i)使得答案更优,可能存在一些部分我们进行适当的拆解出来后,这一部分用(6^i)表示出来后系数和会更小,既然如此,我们直接考虑当前数的最高位的进制是9还是6,然后用递归的方式实现并且在两者之间取min即可。

//不等,不问,不犹豫,不回头.
#include<bits/stdc++.h> 
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define P 1000000007
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define ull unsigned long long
#define put(x) printf("%d
",x)
#define putl(x) printf("%lld
",x)
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
#define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
map<ll,int>f;

inline ll read()
{
    ll x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}

inline int find(ll n)
{
	if(n<6) return n;
	if(f.find(n)!=f.end()) return f[n];
	ll s1=1,s2=1;
	while(s1*6<=n) s1*=6;
	while(s2*9<=n) s2*=9;
	return f[n]=min(find(n-s1),find(n-s2))+1;
}

int main()
{
    //freopen("1.in","r",stdin);
	int get(T);
	while(T--)
	{
		ll get(n);
		putl(find(n));
	}
    return (0^_^0);
}
//以吾之血,铸吾最后的亡魂.

贪吃蛇

比遍体鳞伤更可怕的是内心的堕落....
考虑最后牛牛蛇的最大长度是多少?肯定是全部蛇的和啊,只要让一个蛇吃掉其他全部的蛇就可以了。那我们的目标就是每一次都尽可能增加这个全部蛇的和,考虑怎么样才能达到这个目的,由于复活的时间是固定的,我们可以将时间T分为(frac{T}{x}+1)这么多轮,每一轮可以进行蛇吃蛇的操作,显然的是由于蛇复活的长度不变,所以我们每轮都让蛇吃别人或被吃,这样的话下一轮复活后总增加后的长度最大。考虑怎么做,我们可以先将所有蛇的长度从小到大排序,我们向让次大的吃最大的,第三大的吃次大的,第四大的吃第三大的,...这样一直进行下去,这样能使最大的长度不断累计...最后最小的吃次小的,这样一轮之后,我们的蛇的长度由非严格递增变为非严格递减,之后我们再2号蛇吃1号蛇,3号蛇吃2号蛇,...最后n号蛇吃n-1号蛇,这样一直反复就行。发现这个递推可以用矩阵快速幂维护,那么总复杂度为(O(n^3logM)).

//不等,不问,不犹豫,不回头.
#include<bits/stdc++.h>
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define P 1000000007
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define ull unsigned long long
#define put(x) printf("%d
",x)
#define putl(x) printf("%lld
",x)
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
#define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=55;
int n,x,M,l[N];
struct wy
{
	ll a[N][N];
	wy() {memset(a,0,sizeof(a));}
	inline void clear(){memset(a,0,sizeof(a));}
	wy friend operator*(wy a,wy b)
	{
		wy c;
		rep(i,1,n) rep(j,1,n) rep(k,1,n) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%P;
		return c;
	}
	wy friend operator^(wy a,ll y)
	{
		wy c;
		rep(i,1,50) c.a[i][i]=1;
		while(y)
		{
			if(y&1) c=c*a;
			y>>=1;
			a=a*a;
		}
		return c;
	}
}A,B,C,D;

inline int read()
{
    int x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}

int main()
{
    //freopen("1.in","r",stdin);
    int get(T);
    while(T--)
    {
    	A.clear();B.clear();C.clear();D.clear();
    	get(n);get(x);get(M);
    	rep(i,1,n) get(l[i]);
		sort(l+1,l+n+1);
		rep(i,1,n) rep(j,1,i) A.a[i][j]=1;	
		rep(i,1,n) rep(j,i,n) B.a[i][j]=1;	
		rep(i,1,n) D.a[1][i]=l[i];
		C=A*B;
		int t=M/x+1;
		C=C^(t/2);
		if(t%2) C=C*A;
		C=D*C;
		if(t%2) put(C.a[1][1]);
		else put(C.a[1][n]);
	}
    return (0^_^0);
}
//以吾之血,铸吾最后的亡魂.

原文地址:https://www.cnblogs.com/gcfer/p/15169085.html