列表

详情


NC20794. 大法师与魔法石

描述

大法师正在提高自己的魔法水平。

大法师现在有n个魔法石,它们的的魔力值分别是

现在大法师要从魔法石中挑出连续的一段来施法。

大法师有一个自身的法力值v,大法师的魔力可以和魔法石的魔力发生共振,大大增强魔法石的效果。

我们定义一个法力值为x的法术能够被大法师施展当且仅当存在一个使用魔法石的方法(设其和为s),使得

大法师惊奇地发现,所有法力值相同的法术是一样的。

现在大法师想知道,他能施展出多少种法术。

输入描述

本题开启多组数据

第一行一个正整数T表示数据组数。

每组数据两行:

第一行两个正整数n,v分别表示大法师拥有的魔法石数量和大法师自身的法力值。

第二行n个正整数分别表示魔法石的法力值。

输出描述

一共T行,每行一个非负整数表示答案。

示例1

输入:

1
3 2
2 10 100

输出:

73

说明:

大法师一共有6种选择魔法石的方法。

它们的和及能施放出的魔法分别如下所示:
Sum= 2 [1,2]
Sum=12 [6,12]
Sum=10 [5,10]
Sum=112 [56,112]
Sum=110 [55,110]
Sum=100 [50,100]

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 263ms, 内存消耗: 29412K, 提交时间: 2019-08-22 22:17:36

#include<bits/stdc++.h>
#define M 100005
#define ll long long
using namespace std;
int T,fa[M][20],pos[M][20],a[M],n,v;
ll sum[M];
void Init() {
	for(int j=1; (1<<j)<=n; j++) {
		for(int i=1; i+(1<<j)-1<=n; i++) {
			int x=i+(1<<j-1);
			if(fa[i][j-1]>fa[x][j-1])fa[i][j]=fa[i][j-1],pos[i][j]=pos[i][j-1];
			else fa[i][j]=fa[x][j-1],pos[i][j]=pos[x][j-1];
		}
	}
}
int lg2[M],id;
int get(int l,int r) {
	int k=lg2[r-l+1];
	if(fa[l][k]>fa[r-(1<<k)+1][k])return pos[l][k];
	else return pos[r-(1<<k)+1][k];
}
struct node {
	ll l,r;
	bool operator<(const node&_)const {
		if(l!=_.l)return l<_.l;
		return r<_.r;
	}
} Q[18*M];
void fenzhi(int l,int r) {
	if(l>r)return;
	ll now=sum[r]-sum[l-1];
	int k=get(l,r);
	Q[++id]=(node)<%ceil(1.0*a[k]/v),now%>;
	fenzhi(l,k-1),fenzhi(k+1,r);
}
void solve() {
	sort(Q+1,Q+id+1);
//	for(int i=1;i<=id;i++)printf("%lld %lld\n",Q[i].l,Q[i].r);
	ll l=0,ans=0;//之前最远延伸到的地方
	for(int i=1; i<=id; i++) {
		if(Q[i].r<=l)continue;
		if(Q[i].l>l)ans=(ans+Q[i].r-Q[i].l+1);
		else ans=(ans+Q[i].r-l+1);
		l=Q[i].r+1;
	}
	printf("%lld\n",ans);
}
int main() {
	lg2[1]=0;
	for(int i=2; i<M; i++)lg2[i]=lg2[i>>1]+1;
	scanf("%d",&T);
	while(T--) {
		scanf("%d%d",&n,&v);
		id=0,sum[0]=0;
		for(int i=1; i<=n; i++)scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];
		for(int i=1; i<=n; i++)fa[i][0]=a[i],pos[i][0]=i;
		Init();
//		for(int i=1;i<=n;i++,puts(""))for(int j=0;j<=18;j++)printf("%d %d %d\n",i,i+(1<<j)-1,fa[i][j]); 
		fenzhi(1,n);
		solve();
	}
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 164ms, 内存消耗: 872K, 提交时间: 2019-09-30 16:22:26

#include<bits/stdc++.h>
using namespace std;
#define M 100005
#define ll long long
int a[M],n,v;
ll cl(ll l,ll r){
	ll sum=0,ans1=0,ans2=1e18;
	for(int i=1,pr=1;i<=n;++i){
		sum+=a[i];
		while(sum>=r&&pr<=i)sum-=a[pr],pr++;
		if(pr<=i){
			if(sum>=l)ans2=min(ans2,sum);
			else ans1=max(ans1,sum);
		}
	}
	if(ans2<r)return ans2;
	return ans1;
}
void solve(){
	scanf("%d%d",&n,&v);ll sum=0,ans=0;
	for(int i=1;i<=n;++i)scanf("%d",&a[i]),sum+=a[i];
	ll l=(sum+v-1)/v-1,r=sum;ans+=sum-l;
	while(r){
		ll w=cl(l,r);
		if(w==0)break;
		ans+=min(w,l)-((w+v-1)/v-1);r=w;
		l=(w+v-1)/v-1;
	}
	printf("%lld\n",ans);
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--)solve();
	return 0;
}

上一题