首页 > 其他分享 >容斥原理

容斥原理

时间:2023-08-06 22:12:45浏览次数:43  
标签:方案 int LL 容斥 bad 原理 奶牛 sum

Part1:知识点

在这里插入图片描述
在这里插入图片描述

Part2:例题

【模板题】区间整除数

题意

给出一个数组\(a[1..n]\),问在区间\([L,R]\)中有多少个数,至少能被a中的一个数整除。

解题思路

  • 总体来说,我们可先求出区间 \([1,L-1]\) 中能被a数组整除的数,再求出 \([1,R]\) 中能被a数组整除的数,两者相减即是答案

  • 那么对于区间 \([1,L]\),我们可先求出区间中能被a数组中任意一个数整除的数,那么总量就等于 \(\sum\limits_{i=1}^n\frac{L}{a_i}\) 。但这样很明显会算多,例如 \(a=\{4,6\}\) ,对 \(L=12\),我们求出总量就等于 \(12\div4+12\div6=3+2=5\) 。但其实,真正的答案应为 \(4\) 。这是因为 \(12\) 这个数它既是 \(4\) 的倍数,又是 \(6\) 的倍数

  • 所以,我们考虑容斥原理。那么举个例子,对于区间\([1,12]\),\(a=\{2,4,6\}\),答案就等于 \(\dfrac{L}{\operatorname{lcm}(2)}+\dfrac{L}{\operatorname{lcm}(4)}+\dfrac{L}{\operatorname{lcm}(6)}-\dfrac{L}{\operatorname{lcm}(2,4)}-\dfrac{L}{\operatorname{lcm}(2,6)}-\dfrac{L}{\operatorname{lcm}(4,6)}+\dfrac{L}{\operatorname{lcm}(2,4,6)}\) ,(奇加偶减)。其中\(lcm\)表示最小公倍数

  • 利用容斥原理,我们就可以很轻松地求出区间 \([1,L-1]\) 和 \([1,R]\) 的答案

代码

#include <bits/stdc++.h>
#define LL long long

using namespace std;

const int N=20;
int G,n;
LL l,r,ans,a[N];

LL gcd(LL a,LL b)
{
	if(b==0)
		return a;
	return gcd(b,a%b);
}

LL lcm(LL a,LL b)
{
	return a*b/gcd(a,b);
}

void dfs(int level,int k,LL multi,LL m) //level表示枚举到的a数组的下标,
{										//k表示选了多少数,multi表示最小公倍数,m表示区间右端点
	if(level==n+1)
		return;
		
	dfs(level+1,k,multi,m);
	if(lcm(multi,a[level])<=m)
	{
		k++;
		multi=lcm(multi,a[level]);
		if(k&1) //奇数加偶数减
			ans+=m/multi;
		else
			ans-=m/multi;
		dfs(level+1,k,multi,m); 
	}
}

int main()
{
	cin>>G;
	
	while(G--)
	{
		memset(a,0,sizeof(a));
		
		cin>>n>>l>>r;
		for(int i=1; i<=n; i++)
			cin>>a[i];
		
		LL sa,sb;
		dfs(1,0,1,l-1);
		sa=ans;  ans=0;
		dfs(1,0,1,r);
		sb=ans;  ans=0;
		
		cout<<sb-sa<<endl; 
	}
	
	return 0;
}

【练习题】Cowpatibility G

(题目传送门)

题目大意

研究证明,有一个因素在两头奶牛能否作为朋友和谐共处这方面比其他任何因素都来得重要——她们是不是喜欢同一种口味的冰激凌!

Farmer John 的 \(N\) 头奶牛(\(2\le N\le 5\times 10^4\) )各自列举了她们最喜欢的五种冰激凌口味的清单。为使这个清单更加精炼,每种可能的口味用一个不超过 \(10^6\) 的正整数 \(\texttt{ID}\) 表示。如果两头奶牛的清单上有至少一种共同的冰激凌口味,那么她们可以和谐共处。

请求出不能和谐共处的奶牛的对数。

解题思路

  • 我们可以反向考虑,设 \(f(i)\) 表示前 \(i-1\) 头奶牛中有多少头奶牛和第 \(i\) 头奶牛有至少一种共同口味。那么,不能和谐共处的奶牛对数就是 \(C^2_n-\sum\limits_{i=1}^nf(i)\)

  • 现在我们来考虑如何求出 \(f(i)\) ,我们考虑容斥原理,分别地求出有1种口味相同的,2种口味相同的……5种口味相同的,再利用奇加偶减的方法求出答案

  • 那为了达到这个效果,我们可以考虑用二进制来枚举第 \(i\) 头奶牛所有口味的选择情况。对于每一种情况,我们可以将选择的口味用字符串连接起来。我们事先建立一个 \(map\) 储存前 \(i-1\) 头奶牛每一种选择的情况的个数,这样就可以轻松地求出 \(f(i)\)

  • 枚举完每一种情况后,我们还需要将它加进去 \(map\) 里,方便之后奶牛的操作

注意事项

  • 在读入第 \(i\) 头奶牛的5种口味后,我们需要将它们排个序,否则就会出现两头奶牛口味分别是"2,3,5"和"5,3,2",却把他们当作不一样的情况

  • 用字符串连接选择情况时要注意中间加间隔符

代码

#include <bits/stdc++.h>
using namespace std;

long long n,ans; //ans是对所有f(i)的求和
string a[10];
map <string,long long> f; //这里的f并不是真正意义上的f(i),而是前i-1头奶牛中每种口味选择情况的个数

int main()
{
	cin>>n;
	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=5; j++)
			cin>>a[j];
			
		sort(a+1,a+1+5); //排序
		
		for(int j=1; j<(1<<5); j++) //枚举第i头奶牛选择情况
		{
			int cnt=0;
			string s="";
			
			for(int k=1; k<=5; k++)
			{
				if(j&(1<<(k-1)))
				{
					cnt++;
					s+=a[k]+','; //用带间隔符的字符串连接
				}
			}
			
			if(cnt&1) //奇加偶减
				ans+=f[s];
			else
				ans-=f[s];
			f[s]++; //更新map
		} 
	}
	
	cout<<n*(n-1)/2-ans;
	
	return 0;
}

【练习题】完全平方数

题目传送门

题目大意

询问第k个不是完全平方数或完全平方数整数倍的整数。

1不视作完全平方数。

解题思路

  • 首先看到这么大的数据,我们考虑二分答案,求出区间 \([1,mid]\) 里有多少个不是完全平方数或完全平方数的倍数。注意,区间上界最大为 \(2*k\) ,读者可自行思考原因

  • 但我们很难直接求出答案,于是我们反向考虑,求出“是”的,再用”总“的减去“是”的

  • 因为任意一个完全平方数 \(x^2\) 都可以表示成若干个质数的平方的乘积,即 \(x^2=(p_1*p_2*……*p_t)^2\),我们就可以考虑容斥原理,通过对于区间 \([1,\sqrt{mid}]\) 里的质数的选择再根据每个 \(x\) 所对应的 \(t\) 的奇偶性求出答案。即“是”的= \(\sum{}^{}(-1)^{t+1}mid/x^2\)

  • 但是,由于质数的数量非常多,利用dfs或者二进制枚举肯定会超时,所以我们要换一个角度去考虑。我们不难发现,有些质数的乘积的平方是会超过 \(2*k\) 的范围的,即 \(x=p_1*p_2*……*p_t>\sqrt{2*k}\),这种情况可以舍去,而且我们计算时考虑的是 \(x\) 和 \(x\) 的质因子个数,所以我们其实可以从 \(1\) 枚举到 \(\sqrt{2*k}\) ,对于其中的每个数进行质因数分解,如果它存在某个质因子的指数大于 \(1\),则舍去,否则就将它加入我们待操作的数里面,这样便可以有效的解决问题

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=50010;
LL t,k;
LL tot,a[N]; 

bool check(LL mid)
{
	LL sum=0;
	
	for(int i=1; i<=tot && a[i]*a[i]<=mid; i++)
		sum+=mid/(a[i]*abs(a[i]));
	
	return mid-sum>=k; //"总"的减去"是"的
}

int find() //二分答案
{
	LL lo=0,hi=k<<1,mid; 
	
	while(lo+1<hi)
	{
		mid=(lo+hi)>>1;
		if(check(mid))
			hi=mid;
		else
			lo=mid;
	}
	
	return hi;
}

void fir_make() //对1~根号k里的数进行质因数分解
{
	for(int i=2; i<=44721; i++) //44721是不大于根号2*10^9的最大整数
	{
		bool flag=1;
		int cnt=0,ii=i;
		
		for(int j=2; j*j<=i; j++)
		{
			if(!(ii%(j*j))) //如果某个质因子的指数大于2则舍去
			{
				flag=0;
				break;
			}
			if(!(ii%j))
				cnt++,ii/=j;
		}
		
		if(ii>1)
			cnt++;
		if(flag)
		{
			if(cnt&1) //奇加偶减
				a[++tot]=i;
			else
				a[++tot]=-i;
		}
		
	}
}

int main()
{
	fir_make(); //预处理
	
	cin>>t;
	
	while(t--)
	{
		cin>>k;
		
		cout<<find()<<endl;
	}
	
	return 0;
}

【扩展题】扮演方案

题目大意

  • FJ有 \(N(1\le N \le 50)\) 头奶牛,第i头奶牛的体重是 \(w[i](0 \le w[i] \le 1048575)\)。现在FJ要把这 \(N\) 头奶牛分成两堆,扮演警察和小偷的游戏。
  • 每头奶牛要么扮演警察要么扮演小偷。扮演警察的至少要有一头奶牛,扮演小偷的奶牛也至少要有一头。
  • 扮演警察的所有奶牛聚在一起,会产生一个“合作指数”,
    “合作指数”的值是所有扮演警察的奶牛的体重按照二进制数展开后,再进行二进制 \(AND\) 操作的结果。
  • 同样,扮演小偷的奶牛们也有“合作指数”,也是同样的计算方法。
  • 为了使得游戏好玩,FJ决定,扮演警察的奶牛的“合作指数”和扮演小偷的奶牛的“合作指数”要相等。
  • 问题是:有多少种“不同的扮演方案”?
    下面定义不同的“扮演方案”,假设A、B是两种扮演方案,如果至少存在一头奶牛(不妨假设是奶牛X),奶牛X在方案A中扮演的角色和在方案B中扮演的角色不同,那么方案A和方案B就是不同的方案。

解题思路

  • 我们可以将问题转化成求奶牛与警察“合作指数”不相等的方案,再用总方案数减去它得到答案

  • 但是求指数不相等的方案仍十分困难。我们发现 \(w[i]\) 有 \(1048576\) 即 \(2^{20}\) 这么多,因此我们先考虑只有 \(1\) 位的情况。、

  • 只有 \(1\) 位时,我们可将数分为 \(0\) 和 \(1\) 两种。很明显,要想让两个指数不相等,则所有的 \(0\) 都要放在一起,否则两边的指数都为 \(0\)。这时,我们就对剩下的 \(1\) 进行分析,对于任意一个 \(1\) ,它放在哪边都对结果没有影响,所以令 \(1\) 的个数为 \(x\) ,则 \(1\) 的方法数有 \(2^x\),但由于不能把所有 \(1\) 和 \(0\) 都放在一起,所以方法数为 \(2^x-1\)。又由于 \(0\) 也有两种方式,所以总方案数为 \(2*(2^x-1)=2^{x+1}-2\)

  • 我们既然可以求出有 \(1\) 位不相等的方案,那我们也可以求出 \(2\) 不相等的方案,\(3\) 位不相等的方案……。那么根据容斥原理,我们对奇数位不相等的方案要加上,偶数位不相等的方案要减去

  • 那么问题是,我们怎么求出同时满足好几位指数不相等的方案数呢?先来考虑只有两位同时不相等的情况,假设共有 \(6\) 个数,他们展开二进制后是:\(00,01,01,10,11,11\)。第一位(右往左数)为 \(0\) 的是第一、四个,第二位为 \(0\) 的是第一、二、三个。我们之前已经说过,同一位的 \(0\) 必须全部在同一个集合里面。所以第一、四个必须在同一个集合里,第一、二、三个也必须在同一个集合里面,也就是这四个元素都必须在同一个集合里面。所以我们完全可以把这四个元素看成一个“大元素”。因此这个六个数实际上是 \((00,01,01,10),11,11\) 这三个元素。方案数也很简单:\(2^3-2=6\)(所有2是减去数都在同一个集合的两种情况)

  • 这时候,我们就需要利用并查集来帮助我们判断几个元素是否在同一集合内。将同一位里面的是 \(0\) 的元素连边,然后找一下一共有多少个不同的集合,设集合数为 \(t\),则方案数为 \(2^t-2\)

注意事项

  • 当同一位之中没有 \(0\),全是 \(1\) 时,显然按位与之后两个集合内这一位都是 \(1\),不满足“同时满足每一位按位并后不相等“”的情况,可直接pass掉。当所有的元素的某一位中全部都是 \(0\),那么合并之后肯定只剩下一个集合,也可以pass掉。对于这两种情况,我们可以给 \(i\) 加上 \(lowbit(i)\)(感性理解一下即可)

  • 在二进制枚举之前预处理每一位中有哪些元素是 \(0\),到时候枚举时就可以很快速地连边

  • 注意开long long

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN=30,N=60;

int G,n,w[N];
int zero[MAXN][N],len[MAXN],fa[N]; //zero[i][j]表示第i位为0的是第几个,len[i]表示第i位是0的有几个
long long ans; //不相等的方案数

int lowbit(int x)
{
	return x&(-x);
}

int get(int x)
{
	if(fa[x]==x)
		return x;
	return fa[x]=get(fa[x]);
}

void merge(int x,int y)
{
	fa[get(x)]=get(y);
}

int main()
{
	cin>>G; //多组测试数据

	while(G--)
	{
		memset(w,0,sizeof(w));
		memset(len,0,sizeof(len));
		memset(zero,0,sizeof(zero));
		ans=0;

		cin>>n;
		for(int i=1; i<=n; i++)
			cin>>w[i];

		for(int i=0; i<20; i++)
			for(int j=1; j<=n; j++)
				if(!(w[j]&(1<<i)))
					zero[i][++len[i]]=j; //预处理每一位为0的是哪几个数

		for(int i=1; i<=1048575; i++) //二进制枚举所有选择情况
		{
			int tot=0,cnt=0;
			bool flag=1;

			for(int j=1; j<=n; j++)
				fa[j]=j; //并查集初始化

			for(int j=0; j<20; j++) //枚举选择的位
			{
				if(i&(1<<j)) //选了第j位
				{
					tot++; //计数器++

					if(!len[j]) //这一位没有0
					{
						flag=0; //pass掉
						break;
					}

					for(int k=1; k<len[j]; k++) //并查集连边
						merge(zero[j][k],zero[j][k+1]);
				}
			}

			for(int j=1; j<=n; j++) //查询集合个数
				if(fa[j]==j)
					cnt++;

			if(!flag || cnt==1) //感性理解
			{
				i=i+lowbit(i)-1;
				continue;
			}

			if(tot&1) //奇加偶减
				ans+=(1LL<<cnt)-2;
			else
				ans-=(1LL<<cnt)-2;
		}

		cout<<((1LL<<n)-2-ans)<<endl; //总的减去不相等的
	}

	return 0;
}

【扩展题】 跳跃

题目大意

  • 有一只青蛙在点 \((0,0)\) 处,它要跳 \(R\) 步跳到点 \((T_x,T_y)\)。青蛙每一步是这样跳的:假设青蛙现在所在的点坐标是 \((x_1, y_1)\),那么他一步可以跳到点 \((x_2, y_2)\),但是 \(x_2\) 和 \(y_2\) 要满足如下两个条件:
  • 1、\(0\le x_2-x_1 \le M_x\),\(0\le y_2-y_1 \le M_y\),且点 \((x_2, y_2)\) 和点 \((x_1, y_1)\) 不是同一个点。
    2、输入数据会给出一个数组 \(bad[1..n]\), 对于所有的 \(1 \le i \le n\),\((x_2, y_2)\) 和 \((x_1+bad[i],y_1+bad[i])\) 必须是不同的点。
  • 输入数据保证 \(bad[i]\) 一定是 \(10\) 的整数倍。

解题思路

(感谢wzr同学的帮助)

  • 首先将问题转化成求不合法的方案数,再用总的减去不合法的求出合法的

  • 假设不考虑 \(bad[i]\) 的限制,考虑用最简单的 \(DP\) 算法:设 \(F[r][x][y]\) 表示跳 \(r\) 步后到达 \((x,y)\) 的方案数。则有:

\[F[r][x][y]=sum\{F[r-1][x'][y']\},0≤x-x'≤Mx,0≤y-y'≤My \]

  • 但这样会超时,我们可以把 \(2\) 个状态 \(x\) 和 \(y\) 拆出来,形成 \(Fx\) 和 \(Fy\) 的 \(2\) 个动态规划数组。则有:

\[Fx[r][x]=sum\{Fx[r-1][x']\},0≤x-x'≤Mx \]

\[Fy[r][y]=sum\{Fy[r-1][y']\},0≤y-y'≤My \]

  • 我们再接着考虑 \(0\) 的限制。在计算的时候,要保证 \((x,y)\) 和 \((x',y')\) 是不同的 \(2\) 个点,这时想到,可以直接令 \(bad[n+1]=0\)

  • 再来考虑 \(bad[i]\) 的限制,我们知道:正确答案 = 不考虑限制的答案 - 不合法的答案。考虑跳跃的过程,可以得到等式:

\[x_1+x_2+x_3+...+x_R=Tx \]

\[y_1+y_2+y_3+...+y_R=Ty \]

其中 \(x_1,x_2,...,x_R,y_1,y_2,...,y_R\) 为每次跳跃的距离。
只要有一对 \((x_i,y_i)(1≤i≤R)\) 符合 \(x_i=y_i\) 且为 \(bad\) 中的一个数,那么整个跳跃的过程都不合法。

  • 设 \(dp[i][j]\) 表示至少有 \(i\) 对 \((x,y)\) 不合法,其不合法的每个 \(x\) 的和为 \(j\) 时的方案数。则有:

\[dp[i][j]=sum\{dp[i-1][j-bad[k]\},bad[k]≤j,1≤k≤n \]

  • 设 \(illgeal[i]\) 表示至少有 \(i\) 对 \((x,y)\) 不合法的方案数。则有:

\[illgeal[i]=C^i_n*sum\{dp[i][j]*Fx[R-i][Tx-j]*Fy[R-i][Ty-j]\},0≤j≤min\{Tx,Ty\},1≤i≤R \]

  • 根据容斥原理,不合法总方案数为:

\[illgeal[1]-illgeal[2]+illgeal[3]-illgeal[4]+...+(-1)^R*illgeal[R] \]

代码

#include<bits/stdc++.h>
using namespace std;

const int N=60,M=900,R=1700,MOD=10007;

int n,tx,ty,mx,my,r,bad[N];
int fx[R][M],fy[R][M],sum[M],f[R][R];
int dp[R][M],illgeal[R],ans;

void make_triangle()
{
	for(int i=0; i<=r; i++)
		f[i][0]=f[i][i]=1;
		
	for(int i=1; i<=r; i++)
		for(int j=1; j<i; j++)
			f[i][j]=(f[i-1][j]+f[i-1][j-1])%MOD;		
}

void fir_DP()
{
	fx[0][0]=fy[0][0]=1;
	
	for(int i=1; i<=r; i++)
	{
		memset(sum,0,sizeof(sum));
		
		for(int j=0; j<=tx; j++)
		{
			if(j) //前缀和优化
				sum[j]=sum[j-1];
			fx[i][j]=sum[j]=(sum[j]+fx[i-1][j])%MOD;
			if(j>mx)
				fx[i][j]=(fx[i][j]-sum[j-mx-1]+MOD)%MOD;
		}
		
		memset(sum,0,sizeof(sum));
		
		for(int j=0; j<=ty; j++)
		{
			if(j)
				sum[j]=sum[j-1];
			fy[i][j]=sum[j]=(sum[j]+fy[i-1][j])%MOD;
			if(j>my)
				fy[i][j]=(fy[i][j]-sum[j-my-1]+MOD)%MOD;
		}
	}
}

void sec_DP()
{
	bad[++n]=0;
	dp[0][0]=1;
	 
	for(int i=1; i<=r; i++)
	{
		for(int j=0; j<=min(tx,ty); j+=10)
		{
			for(int k=1; k<=n; k++)
			{
				if(j>=bad[k])
					dp[i][j]=(dp[i][j]+dp[i-1][j-bad[k]])%MOD;
			}
		}
	}
}

void make_ans()
{
	ans=(fx[r][tx]*fy[r][ty])%MOD;
	
	for(int i=1; i<=r; i++)
	{
		for(int j=0; j<=min(tx,ty); j+=10)
			illgeal[i]=(illgeal[i]+dp[i][j]%MOD*fx[r-i][tx-j]%MOD*fy[r-i][ty-j]%MOD+MOD)%MOD;
		
		illgeal[i]=(illgeal[i]*f[r][i])%MOD;
		
		if(i&1) //容斥原理
			ans=(ans-illgeal[i]+MOD)%MOD;
		else
			ans=(ans+illgeal[i])%MOD;
	}
}

int main()
{
	cin>>tx>>ty>>mx>>my>>r>>n;
	for(int i=1; i<=n; i++)
		cin>>bad[i];
		
	make_triangle(); //预处理求出组合数
	
	fir_DP();
	
	sec_DP();
	
	make_ans();
	
	cout<<ans;

	return 0;
}

标签:方案,int,LL,容斥,bad,原理,奶牛,sum
From: https://www.cnblogs.com/xishanmeigao/p/17610164.html

相关文章

  • 如何将 dubbo filter 拦截器原理运用到日志拦截器中?
    业务背景我们希望可以在使用日志拦截器时,定义属于自己的拦截器方法。实现的方式有很多种,我们分别来看一下。拓展阅读java注解结合springaop实现自动输出日志java注解结合springaop实现日志traceId唯一标识java注解结合springaop自动输出日志新增拦截器与过滤器......
  • NFS快速入门(一):简介、原理
    NFS网络文件共享存储什么是NFSNFS是NetworkFileSystem的缩写,中文意思是网络文件系统。它的主要功能是通过网络(一般是局域网)让不同主机系统之间可以共享文件或目录。NFS客户端(一般为web服务器)可以通过挂载(mount)方式将NFS服务器端共享的数据目录挂载到客户端某一个挂载......
  • 深度 Q 网络(deep Q network,DQN)原理&实现
    深度Q网络(deepQnetwork,DQN)原理&实现1Q-Learning算法1.1算法过程Q-learning是一种用于解决强化学习问题的无模型算法。强化学习是一种让智能体学习如何在环境中采取行动以最大化某种累积奖励的机器学习方法。在Q-learning中,智能体根据称为Q-values的函数来选择行动。Q-v......
  • 笔记|数据库设计——《数据库原理》
    数据库结构设计包括⚫需求分析阶段:综合各个用户的应用需求⚫概念结构设计:形成独立于各个DBMS概念模式,如E-R图⚫逻辑结构设计:形成数据库逻辑模式与外模式,用(基本)数据模型描述,例基本表、视图等⚫物理结构设计:形成数据库内模式,如DB文件或目录、索引一.需求分析......
  • 单片机原理1:指令系统
    电路结构: P0,P1,P2,P3四个并行的IO口P0口复用为低8位地址线和数据线P1口复用为高8位地址线P2口双向IO端口P3口通信,中断等第二功能  指令:程序存储器中从IO口读取数据前,必须先给IO拉高,全置为1(why?使内部的FET截止,再读入引脚的状态)时钟电路与复位电路:复位条件:RST引脚持......
  • 从 Pulsar Client 的原理到它的监控面板
    背景前段时间业务团队偶尔会碰到一些Pulsar使用的问题,比如消息阻塞不消费了、生产者消息发送缓慢等各种问题。虽然我们有个监控页面可以根据topic维度查看他的发送状态,比如速率、流量、消费状态等信息。但也有几个问题:无法在应用维度查看他所依赖的所有topic的各种......
  • java中ReentrantLock底层实现原理
    ReentrantLock是Java中提供的一种可重入的互斥锁,它具有与synchronized关键字相似的功能,但更加灵活和可控。下面是ReentrantLock底层实现原理的简要解释:ReentrantLock的底层实现主要依赖于AbstractQueuedSynchronizer(AQS)类。AQS是一个用于构建锁和其他同步器的框架,它提供了一种基于......
  • OpenERP的生产成本的计算原理
      生产订单的跟踪是对生产订单从订单启动到产品入库整个过程中的跟踪与控制。它主要包括Q(Quality品质)、C(Cost成本)、D(DeliveryTime交货期)三个方面的内容,品质合格、低成本、准时交货是生产型企业中十分关键的要素,它制约着企业在市场上的综合竞争力。一个好的生产管理系统应该辅......
  • 前端学习笔记202307学习笔记第六十一天-拦截器工作原理3
         ......
  • 前端学习笔记202307学习笔记第六十三天-redux单项数据流和中间件原理12
          ......