您的位置:首页 > 其它

2015暑期多校训练第一场 1,2,3

2015-09-03 21:20 267 查看
//	2015暑期多校训练第一场 1,2,3
//
//	本来想一天能够复习一套的,结果实在太艰难,一题差不多都能搞一天呢
//	而且内心的激动也是想在此时分享分享,前两道大神说的水题,我都理解
//	了大半天,第三题更是理解了三四天才懂了那么一丁点.继续加油吧,明天
//	继续搞!

//	hdu 5288 OO’s Sequence
//
//	对于一个a[i]记录左边一个L右边一个R,分别
//	代表最接近a[i]并且能够被a[i]整除的位置
//	每个a[i]的贡献值是(R[i] - i) * (i - L[i])
//	用一个pre值,记录每个数出现的位置.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 100008;
const ll MOD = 1e9 + 7; 
int a[maxn];
int L[maxn];
int R[maxn];
int n;
vector<int> p[10008];
int pre[maxn];
void init(){
	for (int i=1;i<=10000;i++){
		p[i].clear();
		for (int j=1;j*j<=i;j++){
			if (i%j==0){
				p[i].push_back(j);
				if (j*j!=i)
					p[i].push_back(i/j);
			}
		}
	}
}

void input(){
	for (int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
}

void solve(){
	memset(pre,0,sizeof(pre));
	for (int i=1;i<=n;i++){
		int u = a[i];
		int ind = 0;
		for (int j=0;j<p[u].size();j++){
			ind = max(ind,pre[p[u][j]]);
		}
		L[i] = ind;
		pre[u] = i;
	}

	memset(pre,0x7f,sizeof(pre));

	for (int i=n;i>=1;i--){
		int u = a[i];
		int ind = n + 1;
		for (int j=0;j<p[u].size();j++){
			ind = min(ind,pre[p[u][j]]);
		}
		R[i] = ind;
		pre[u] = i;
	}
	
	ll ans = 0;
	
	for (int i=1;i<=n;i++){
		ans = (ans + (ll)(i-L[i]) * (R[i] - i))%MOD;
	}
	printf("%I64d\n",ans);
}

int main(){
	init();
	freopen("1.txt","r",stdin);
	while(scanf("%d",&n)!=EOF){
		input();
		solve();
	}
}

//	hdu 5289 Assignment 单调队列
//
//	题目大意:
//		
//		题目的意思就是让你求满足最大值最小值之差小与k的区间个数
//
//	解题思路:
//		
//		单调队列,众所周知,单调队列能够维护滑动窗口的最大值和最小值
//	的问题.这里两者都有,我们都维护即可.我们用两个指针.一个指针表示
//	当前插入的元素,另一个指针表示满足条件的开始的元素的位置.维护单
//	调队列的时候我们插入一个元素,当发现插入该元素时,不满足题目所要
//	求的条件,并且第一个指针指向的位置出队.这时两个指针之间的距离就
//	是我们所能得到的区间的数目,累加结果就好.最后还要记得当所有的元
//	素都入队时,此时要看看j是否是最后的位置,因为此时还有满足条件的
//	区间.
//
//	感悟:
//
//		这道题多校训练的时候,是MY做出来的,用的就是单调队列,当时并不
//	怎么明白,后来也自己做了一遍,能想到维护最大值和最小值,但是这之间
//	的距离就不太清楚了.看了看题解,发现确实很奇妙.然后自己仔细仔细的
//	体会了一番,确实很不错.感谢这位神牛.也有的大神用的线段树做出来的
//	也有的是RMQ+二分.有多种解法.多开阔开阔思路,总是好的.继续加油哟~~~
	

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 1e5 + 8;

int n,k;
int a[maxn];
int deqmax[maxn];
int deqmin[maxn];

void input(){
	scanf("%d%d",&n,&k);
	for (int i = 1; i <= n; i++){
		scanf("%d",&a[i]);
	}
}

void solve(){
	int headmax,tailmax,headmin,tailmin;
	headmax = tailmax = headmin = tailmin = 0;
	long long ans = 0;
	int j = 1;
	for (int i=1;i <= n; i++){
		while(headmax < tailmax && a[deqmax[tailmax-1]] <= a[i])
			tailmax--;

		deqmax[tailmax++] = i;

		while(headmin < tailmin && a[deqmin[tailmin-1]] >= a[i])
			tailmin--;

		deqmin[tailmin++] = i;

		while(headmin < tailmin && headmax < tailmax && a[deqmax[headmax]]-a[deqmin[headmin]] >= k){
			ans += i - j;
			if (j == deqmax[headmax])
				headmax++;
			if (j == deqmin[headmin])
				headmin++;
			j++;
		}

	}

	while(j <= n){
		ans += n + 1 - j;
		j++;
	}

	printf("%I64d\n",ans);
}

int main(){
	int t;
	//freopen("1.txt","r",stdin);
	scanf("%d",&t);
	while(t--){
		input();
		solve();
	}
}

//	hdu 5290 Bombing plan
//	
//	题目大意:
//
//		给你一颗树,树上每个节点有一个权值w,当炸毁一个节点
//		时,距离它为w以内的点都被炸毁.则问当所有点被炸毁时
//		最小需要炸毁几个点.
//
//	解题思路:
//
//		树形dp.我们设立两个数组F[I][J],G[I][J].前者表示
//		I及I子树中所有节点全被炸毁,并且沿父节点向上距离
//		为J的点也被炸毁.后者表示I及I的子树中部分节点被炸毁
//		并且未被炸毁的点离I最远为J.
//		转移方程为:
//		不取i点
//			F[i][j] = F[v][j+1] + min(F[L][0...j+1],G[L][0...j-1]);
//			G[i][j] = g[v][j-1] + min(F[L][0....j],G[L][0...j-1]);
//			G[i][0] = sigma(f[v][0]);
//		
//		取i点
//			F[i][w[i]] = 1 + min(F[L][0...w[u]+1],G[L][0...w[u]-1]);
//
//		如果不好理解的话,那么本人按照自己的理解说一下,首先是F[i][j].
//		先选一个满足条件的能达到i向上距离为j的则为F[v][j+1].此时其他
//		的节点,子节点子树全被炸毁的范围F[L][0...j+1],子节点子树未被
//		全部炸毁g[i][j-1].G[i][j]同样是首先选择一个离i未炸毁的G[v][j-1]
//		其他的还是两种选择,要么未炸毁距离小于等于j要么全被炸毁.
//
//		初始化的时候单个叶子节点g[i][0] = 0,f[i][w[i]] = 1;其他的无穷大
//		但是不宜太大,容易造成数据溢出
//
//		看到一位大神写的在这题中,将无根树转化为有根树的时候,将1作为根.
//		并将1本身的节点另起一个编号挂在1上.这样的做法我感觉十分奇妙.自己还是
//		不很理解.希望大牛们能够不吝惜的指点小子一二.小子不慎感激
//
//	感悟:
//
//		多校第一场的第三题,当时根本就不会做,题解也看不懂.现在经过了玩耍的开心
//		时间,是时候逼迫自己去理解了,要不然水平怎么能提高呢,继续加油吧

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#define cls(x,a) memset(x,(a),sizeof(x))
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;

const int maxn = 1e5 + 8;
const int inf = 0x01010101;

vector<int> e[maxn];
int a[maxn];
int F[maxn][111];
int G[maxn][111];
int p[maxn][111];
int q[maxn][111];
int n;

void input(){
	for (int i=1;i<=n;i++){
		e[i].clear();
	}
	for (int i = 1;i <= n;i++){
		scanf("%d",&a[i]);
	}
	e[1].push_back(n+1);
	for (int i=1;i < n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		e[u].push_back(v);
		e[v].push_back(u);
	}

	cls(F,inf);
	cls(G,inf);
	cls(p,inf);
	cls(q,inf);

}

void dfs(int u,int fa){
	for (int i=0;i<e[u].size();i++){
		int v = e[u][i];
		if (v == fa)
			continue;
		dfs(v,u);
	}

	if (e[u].size()==1){
		G[u][0] = 0;
		F[u][a[u]] = 1;
		return;
	}

	for (int i=0;i<e[u].size();i++){
		int v = e[u][i];
		if (v == fa)
			continue;
		p[v][0] = F[v][0];
		q[v][0] = G[v][0];

		for (int j=1;j<103;j++){
			p[v][j] = min(p[v][j-1],F[v][j]);
			q[v][j] = min(q[v][j-1],G[v][j]);
		}
	}

	for (int j=0;j<103;j++){
		for (int k=0;k<e[u].size();k++){
			int v = e[u][k];
			if (v == fa)
				continue;
			
			if (F[v][j+1] == inf)
				continue;

			int f = F[v][j+1];

			for (int i=0;i<e[u].size();i++){
				int t = e[u][i];
				if (i==k || t == fa)
					continue;

				if (j)
					f += min(p[t][j+1],q[t][j-1]);
				else
					f += p[t][j+1];
			}

			F[u][j] = min(F[u][j],f);
		}
	}

	int g = 0;

	for (int i=0;i<e[u].size();i++){
		int v = e[u][i];

		if (v==fa)
			continue;

		g += F[v][0];
	}

	G[u][0] = min(G[u][0],g);

	for (int j=1;j<103;j++){
		for (int k=0;k<e[u].size();k++){
			int v = e[u][k];

			if (v == fa)
				continue;

			if (G[v][j-1] == inf)
				continue;
			
			g = G[v][j-1];

			for (int i=0;i<e[u].size();i++){
				int t = e[u][i];
				if (i==k || t == fa)
					continue;

				g += min(p[t][j],q[t][j-1]);
			}
			G[u][j] = min(G[u][j],g);
		}
	}

	int f = 1;
	
	for (int i=0;i<e[u].size();i++){
		int v = e[u][i];

		if (v == fa)
			continue;

		if (a[u]){
			f += min(p[v][a[u]+1],q[v][a[u]-1]);
		}else {
			f += p[v][a[u]+1];
		}
	}

	F[u][a[u]] = min(F[u][a[u]],f);

}

void solve(){
	dfs(1,0);
	int ans = inf;

	for (int j=0;j<103;j++){
		ans = min(ans,F[1][j]);
	}
	printf("%d\n",ans);
}

int main(){
	freopen("1.txt","r",stdin);
	while(scanf("%d",&n)!=EOF){
		input();
		solve();
	}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: