2019浙江ACM省赛部分题解-ABDEFGHIJK

太菜了,心态炸了。QAQ

A-Vertices in the Pocket()

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4100

题目大意:给出T组合数据,每组数据n个点,m次询问,每次有两种情况,1.x,y之间链接一条边。2.如果这个图加入k条边,输出最少的联通块数和最多的联通快数。注意,连点的时候,一对点只能连一条边,即x y连后,不能再连x y了。

思路:看着像CF里面的一道题,当时猛哥读出来的时候说这个先放一放,最后写,结果最后也没有写。。。

最少的联通快个数很好求,当前联通快个数-k即可。(在不同的联通快之间连边),注意联通快的最小个数为1.

剩下就是求最大的联通块个数了。我们已经有一些联通块了,(操作1给出的联通快可以用并查集来维护)。同时用权值线段树维护联通快的大小,可用边的数量,联通快数量。

剩下的就是找最少链接几个联通快能把这k条边都用上。我们贪心的每次都选择最大的联通快,然后是次大的,再次的。。

选到最后,二分剩余的联通快的个数,取最小值即可。

ACCode:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
  
#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;

class WeiSegment{
	ll SizDots[MAXN<<2],AvailableEdge[MAXN<<2],UnicomBlock[MAXN<<2];
	//大小为k的块的点的个数,可容纳边总和,大小为k的块点的个数总和 
	//显然,初始化:
	//SizDots:一开始大小为1的块的个数为n,
	//AvailableEdge:可容纳边的总和为0,
	//UnicomBlock:点1的个数总和为n 
	int n;
	
	void PushUp(int rt){
		SizDots[rt]=SizDots[rt<<1]+SizDots[rt<<1|1];
		AvailableEdge[rt]=AvailableEdge[rt<<1]+AvailableEdge[rt<<1|1];
		UnicomBlock[rt]=UnicomBlock[rt<<1]+UnicomBlock[rt<<1|1];
	}
	
	public :
		void SetN(int Key){
			n=Key;
		}
		void Build(int l,int r,int rt){
			SizDots[rt]=AvailableEdge[rt]=UnicomBlock[rt]=0;
			if(l==r){
				if(l==1){
					SizDots[rt]=UnicomBlock[rt]=n;
					AvailableEdge[rt]=0;
				}return ;
			}
			int mid=(l+r)>>1;
			Build(l,mid,rt<<1);Build(mid+1,r,rt<<1|1);
//			PushUp(rt);
		}
		void Update(int p,int l,int r,int rt){
			if(l==r){
				SizDots[rt]+=l;
				AvailableEdge[rt]+=l*(l-1)/2;
				UnicomBlock[rt]++;
				return ;
			}
			int mid=(l+r)>>1;
			if(p<=mid) Update(p,l,mid,rt<<1);
			if(p>mid) Update(p,mid+1,r,rt<<1|1);
			PushUp(rt);
		}
		void Del(int p,int l,int r,int rt){
			if(l==r){
				SizDots[rt]-=l;
				AvailableEdge[rt]-=l*(l-1)/2;
				UnicomBlock[rt]--;
				return ;
			}
			int mid=(l+r)>>1;
			if(p<=mid) Del(p,l,mid,rt<<1);
			if(p>mid) Del(p,mid+1,r,rt<<1|1);
			PushUp(rt);
		}
		int Query(ll k,ll v,int l,int r,int rt){
			if(l==r){
				int ql=1,qr=UnicomBlock[rt];
				while(ql<=qr){
					int mid=(ql+qr)>>1;
					if((v+mid*l)*(v+mid*l-1)/2>=l*(l-1)/2*mid+k) qr=mid-1;
					else ql=mid+1;
				}return ql;
			}
			int mid=(l+r)>>1;
			int Dots=SizDots[rt<<1|1],UsEdge=AvailableEdge[rt<<1|1];
			if((v+Dots)*(v+Dots-1)/2>=k+UsEdge) return Query(k,v,mid+1,r,rt<<1|1);
			else return Query(k+UsEdge,v+Dots,l,mid,rt<<1)+UnicomBlock[rt<<1|1];
		}
};
WeiSegment WSeg;
int Pre[MAXN],Siz[MAXN];
int n,m;

void Intt(){
	for(int i=0;i<=n;++i){
		Pre[i]=i;Siz[i]=1;
	}WSeg.SetN(n);WSeg.Build(1,n,1);
}
int Find(int x){
	if(Pre[x]==x) return x;
	return Pre[x]=Find(Pre[x]);
}
int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);Intt();
		ll AvailableEdge=0,UnicomBlock=n;
		for(int i=1;i<=m;++i){
			int oper;scanf("%d",&oper);
			if(oper==1){
				int x,y;scanf("%d%d",&x,&y);
				int xx=Find(x),yy=Find(y);
				if(xx!=yy){
					WSeg.Del(Siz[xx],1,n,1);WSeg.Del(Siz[yy],1,n,1);
					AvailableEdge-=Siz[xx]*(Siz[xx]-1)/2+Siz[yy]*(Siz[yy]-1)/2;
					Siz[xx]=Siz[xx]+Siz[yy];Pre[yy]=xx;//联通 
					AvailableEdge+=Siz[xx]*(Siz[xx]-1)/2;
					WSeg.Update(Siz[xx],1,n,1);
					UnicomBlock--;
				}AvailableEdge--;
			}
			else{
				ll k;scanf("%lld",&k);
				printf("%lld %lld\n",max(1ll,(UnicomBlock-k)),UnicomBlock+1-WSeg.Query(k-AvailableEdge,0,1,n,1));
			}
		}
	}
}

B-Element Swapping()

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4101

看的我头疼,一脸蒙蔽,溜了溜了。

队友做的,题解:https://blog.csdn.net/henucm/article/details/89742028

D-Traveler

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=6005

题目大意:一个人一开始在点1,要走到点n,其中每个点都要走一遍,问路径。行走的方式有四种:

1. i->i-1       2.i->2i         3.i->2i+1             4.i->int[i/2]

每个点只能走一次,每一步都不能超过n。

思路:试着写了几个点,画了波图,发现可以看成这样的:

直接一层一层的刷新就行了,跟本没有走不到的。具体看代码就好了

ACCOde:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
  
#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;

int Vis[MAXN];
int n;

int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		if(n==1){
			printf("1\n");continue;
		}
		else if(n==2){
			printf("1 2\n");continue;
		}
		else if(n==3){
			printf("1 3 2\n");continue;
		}
		for(int i=0;i<=n;++i) Vis[i]=0;
		printf("1");Vis[1]=1;
		int x=2;
		while(1){
			if(Vis[x]==0){
				printf(" %d",x);Vis[x]=1;
			}
			if(2*x==n){
				printf(" %d",n);Vis[n]=1;
				for(int i=n-1;Vis[i]==0;i-=2){
					if(Vis[i]==0){
						printf(" %d",i);Vis[i]=1;
					}
					if(Vis[i/2]==0){
						printf(" %d",i/2);Vis[i/2]=1;
					}
					if(Vis[i-1]==0){
						printf(" %d",i-1);Vis[i-1]=1;
					}
				}break;
			}
			else if(2*x+1==n){
				for(int i=n;Vis[i]==0;i-=2){
					if(Vis[i]==0){
						printf(" %d",i);Vis[i]=1;
					}
					if(Vis[i/2]==0){
						printf(" %d",i/2);Vis[i/2]=1;
					}
					if(Vis[i-1]==0){
						printf(" %d",i-1);Vis[i-1]=1;
					}
				}break;
			}
			if(Vis[x-1]==0) x=x-1;
			else x=x*2;
		}printf("\n");
	}
}
/*

20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

*/

E-Sequence in the Pocket

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4104

题目大意:n个数,每个数都可以放在一开始,给你一个排列,看最少经过多少次修改能使队列单调不减

思路:队友写的,我在摸鱼

ACCode:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
  
#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
 
int n;
struct node
{
	int x,i;
}a[MAXN];

int mmp(node x,node y)
{
	if(x.x!=y.x)
	{
		return x.x<y.x;
	}
	return x.i<y.i; 
}
int main(){ 
	int t;
	scanf("%d",&t);
	while(t--){
		int n;
		scanf("%d",&n);
		for(int i=0;i<n;i++){
			scanf("%d",&a[i].x);
			a[i].i=i; 
		}
		sort(a,a+n,mmp);
		int f=1;
		int i;
		for(i=n-1;i>0;i--){
			if(a[i].i>a[i-1].i){
				f++;
			}else 
			{
				int j=i-1;
				while(j>=0&&a[i-1].x==a[j].x){
					if(a[j].i<a[i].i){
					//	printf("%d  %d\n",a[j].x,a[i].x);
						f++;
					}
					j--;
				} 
				break;
				
			}
			
		}	
		printf("%d\n",n-f);
	}
}

F-Abbreviation

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4105

题目大意:除了首字母外,其他定义为元音的字母都去掉。

思路:模拟就行了

ACCode:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
  
#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;

char p[7]={'a','e','i','y','o','u'};
char s[MAXN];

int main(){
	int T;//scanf("%d",&T);
	while(~scanf("%d",&T)){
		while(T--){
			scanf("%s",&s);
			int len=strlen(s);
			printf("%c",s[0]);
			for(int i=1;i<len;++i){
				int flag=1;
				for(int j=0;j<=5;++j){
					if(s[i]==p[j]){
						flag=0;break;
					}
				}
				if(flag) printf("%c",s[i]);
			}printf("\n");
		}
	}

}

G-Lucky 7 in the Pocket

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4106

题目大意:在n后面距离n最近的那个数,可以被7整除但不可以被4整除,输出。

思路:签到提,模拟。

ACCode:

int main(){
	int T;scanf("%d",&T);
	while(T--){
		int n;scanf("%d",&n);
		for(int i=n;1;++i){
			if(i%7==0&&i%4!=0){
				printf("%d\n",i);
				break;
			}
		}
	}
	
}

H-Singing Everywhere

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4107

题目大意:给出n个数,如果存在一个数a[i]>a[i-1]&&a[i]>a[i+1]那么就有一个“峰”,问最多删掉一个数,这个数组的最小峰的个数是多少?

思路:模拟,因为删掉一个数只会对前面和后面那个数产生影响,枚举模拟即可。

ACCode:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
  
#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;

int a[MAXN],b[MAXN];
int n;

int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		clean(b,0);
		for(int i=1;i<=n;++i){
			scanf("%d",&a[i]);
		}
		int ans=0;
		for(int i=2;i<n;++i){
			if(a[i]>a[i-1]&&a[i]>a[i+1]){
				b[i]=1;ans++;
			}
		}
		int res=ans;
		//特判2,n-1 
		int x=ans;
		if(b[2]) x--;
		if(a[3]>a[1]&&a[3]>a[4]){
			if(b[3]) x=x;
			else x++;
		}
		else{
			if(b[3]) x--;
			else x=x;
		}res=min(res,x);
		x=ans;
		if(b[n-1]) x--;
		if(a[n-1]>a[n-2]&&a[n-1]>a[n]){
			if(b[n-1]) x=x;
			else x++;
		}
		else{
			if(b[n-1]) x--;
			else x=x;
		}res=min(res,x);
		for(int i=3;i<=n-2;++i){
			x=ans;
			if(b[i]) x--;
			if(a[i+1]>a[i-1]&&a[i+1]>a[i+2]){
				if(b[i+1]) x=x;
				else x++;
			}
			else{
				if(b[i+1]) x--;
				else x=x;
			}
			if(a[i-1]>a[i-2]&&a[i-1]>a[i+1]){
				if(b[i-1]) x=x;
				else x++;
			}
			else{
				if(b[i-1]) x--;
				else x=x;
			}res=min(res,x);
		}
		printf("%d\n",res);
	}
}

I-Fibonacci in the Pocket

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4108

题目大意:给你一个斐波那契数列,然后问你第x项加到第y项是奇数还是偶数,奇数输出1,偶数输出0.

思路:找到规律后发现三个一组都是奇奇偶,那么就可以%3直接判断了。

ACCode:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
  
#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;

char a[MAXN],b[MAXN];

int Sura(int len){
	int ans=0;
	for(int i=0;i<len;++i){
		ans=ans*10+(a[i]-'0');
		ans=ans%3;
	}return ans;
}
int Surb(int len){
	int ans=0;
	for(int i=0;i<len;++i){
		ans=ans*10+(b[i]-'0');
		ans=ans%3;
	}return ans;
}
int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%s%s",&a,&b);
		int lena=strlen(a),lenb=strlen(b);
		int sura=Sura(lena),surb=Surb(lenb);
//		cout<<"a: "<<sura<<" , "<<a<<endl;
//		cout<<"b: "<<surb<<" , "<<b<<endl;
		sura=(sura+3-1)%3;
//		cout<<"sura,surb: "<<sura<<" "<<surb<<endl;
		if(surb%2==0){
			if(sura%2) printf("1\n");
			else printf("0\n");
		}
		else{
			if(sura%2) printf("0\n");
			else printf("1\n");
		}
	}
	
	
}

J-Welcome Party()

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4109

题目大意:n个人,m个关系,然后让你找出n个人的进入房间的字典序最小的序列。房间里有不认识的人,进入后不开心。输出最小的不开心数。

思路:ZOJ栈啊!!!!!卡了我两个半小时,最后发现是爆栈了,改成BFS就过了!!换成数组模拟DFS也过了,佛了。

建好图之后,每个联通快编号最小的人先进去,优先队列来维护下一个进入的id。

ACCode:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
  
#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e6+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;

struct Node1{
	int v,val,nxt;
	Node1(int _v=0,int _val=0,int _nxt=0){
		v=_v;val=_val;nxt=_nxt;
	}
};
Node1 Edge[MAXN<<2];
int Head[MAXN];
//vector<int> Vec[MAXN];
int Belong[MAXN];
int Vis[MAXN];
int Ans[MAXN];
int n,m,Ecnt,Cnt;

priority_queue<int,vector<int>,greater<int> > que;

void Intt(){
	for(int i=0;i<=n;++i){
		Head[i]=-1;
		Belong[i]=0;
		Vis[i]=0;Ans[i]=0;
	}Ecnt=0;Cnt=0;
}
void AddEdge(int u,int v,int val){
	Edge[Ecnt]=Node1(v,val,Head[u]);
	Head[u]=Ecnt++;
}
int Stk[MAXN],Top;
void DFS(int u){
	Top=0;Stk[++Top]=u;
	while(Top){
		u=Stk[Top--];
		if(Belong[u]==0){
			Belong[u]=Cnt;
			for(int i=Head[u];i+1;i=Edge[i].nxt){
				int temp=Edge[i].v;
				if(Belong[temp]==0){
					Stk[++Top]=temp;
				}
			}
		}
	}
}
queue<int> que1;
void BFS(int u){
	while(que1.size()) que1.pop();
	que1.push(u);
	while(que1.size()){
		u=que1.front();que1.pop();
		if(Belong[u]==0){
			Belong[u]=Cnt;
			for(int i=Head[u];i+1;i=Edge[i].nxt){
				int temp=Edge[i].v;
				if(Belong[temp]==0) que1.push(temp);
			}
		}
	}
}
int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);Intt();
		for(int i=1;i<=m;++i){
			int x,y;scanf("%d%d",&x,&y);
//			Vec[x].push_back(y);Vec[y].push_back(x);
			AddEdge(x,y,1);AddEdge(y,x,1);
		}
		for(int i=1;i<=n;++i){
			if(Belong[i]==0){
				++Cnt;
				DFS(i);
				//BFS(i);
			}
		}
		for(int i=1;i<=n;++i){//Vis[i]是i联通快 
			if(Ans[Belong[i]]==0){//属于该种类的跟不存在 
				Ans[Belong[i]]=i;//赋予跟 
			}
		}
		for(int i=1;i<=Cnt;++i) que.push(Ans[i]);
		printf("%d\n",Cnt);
//		for(int i=1;i<=n;++i) cout<<i<<" : "<<Vis[i]<<endl;
		int fir=1;
		while(que.size()){
			int u=que.top();que.pop();
//			cout<<u<<" ";
			if(Vis[u]) continue;
			Vis[u]=1;
			if(fir){
				printf("%d",u);fir=0;
			}
			else printf(" %d",u);
			for(int i=Head[u];i+1;i=Edge[i].nxt){
				int temp=Edge[i].v;
				if(Vis[temp]) continue;
				que.push(temp);
			}
//			int len=Vec[u].size();
//			for(int i=0;i<len;++i){
//				int temp=Vec[u][i];
//				if(Vis[temp]) continue;
//				que.push(temp);
//			}
		}printf("\n");
	}
}
/*

10
4 3
1 2
1 3
1 4

4 2
1 2
3 4

6 5
1 3
1 5
1 6
2 3
2 4

6 4
1 3
2 3
3 5
4 6

*/

K-Strings in the Pocket

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4110

文少写的,但是似乎还没发博客,于是我就先占个坑。据说是用马拉车写的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值