2019.10.07日常总结

无论你愿意不愿意,明天开学了!!!

洛谷P3939:

【题意】:
n n n 只兔子,颜色分别是 a 1 a_1 a1 a n ( a i ≤ 3 × 1 0 5 ) a_n(a_i\leq 3 \times 10^5) an(ai3×105)
m m m次操作,每次操作
1 1 1 l l l r r r c c c:询问 [ l , r ] [l,r] [l,r]区间有多少颜色为 c c c 的兔子
2 2 2 x x x x x x x + 1 x+1 x+1 这两只兔子交换了颜色
对于每次操作询问答案
【数据范围】:
2019.10.07日常总结_第1张图片
【思路】:
g [ x ] g[x] g[x]记录所有颜色为 x x x的兔子的位置

输入部分:

for(i=1;i<=n;i++){
	a[i]=read();
	g[a[i]].push_back(i);
}

对于操作 1 1 1

y=read();z=read();
int k1=lower_bound(g[z].begin(),g[z].end(),x)-g[z].begin();
int k2=upper_bound(g[z].begin(),g[z].end(),y)-g[z].begin()-1;
if (k1>k2) printf("0\n");//注意特判
else printf("%d\n",k2-k1+1);

对于操作 2 2 2

if (a[x]==a[x+1]) continue;
int k1=lower_bound(g[a[x]].begin(),g[a[x]].end(),x)-g[a[x]].begin();
g[a[x]][k1]++;
int k2=lower_bound(g[a[x+1]].begin(),g[a[x+1]].end(),x+1)-g[a[x+1]].begin();
g[a[x+1]][k2]--;
swap(a[x],a[x+1]);

【代码】:

#include 
using namespace std;
#define gc getchar()
#define g(c) isdigit(c)
inline int read(){
	char c=0;int x=0;bool f=0;
	while (!g(c)) f=c=='-',c=gc;
	while (g(c)) x=x*10+c-48,c=gc;
	return f?-x:x;
}
const int N=3e5+1e3;
vector<int> g[N];
int a[N],i,x,y,z,n,m,opt;
int main(){
	freopen("t1.in","r",stdin);
	n=read();m=read();
	for(i=1;i<=n;i++){
		a[i]=read();
		g[a[i]].push_back(i);
	}
	for(i=1;i<=m;i++){
		opt=read();x=read();
		if (opt==1){
			y=read();z=read();
			int k1=lower_bound(g[z].begin(),g[z].end(),x)-g[z].begin();
			int k2=upper_bound(g[z].begin(),g[z].end(),y)-g[z].begin()-1;
			if (k1>k2) printf("0\n");
			else printf("%d\n",k2-k1+1);
		}
		else{
			if (a[x]==a[x+1]) continue;
			int k1=lower_bound(g[a[x]].begin(),g[a[x]].end(),x)-g[a[x]].begin();
			g[a[x]][k1]++;
			int k2=lower_bound(g[a[x+1]].begin(),g[a[x+1]].end(),x+1)-g[a[x+1]].begin();
			g[a[x+1]][k2]--;
			swap(a[x],a[x+1]);
		}
	}
	return 0;
}

P1528 切蛋糕 P2329 栅栏

(两题本质是一样的,所以我一起写了)

【题意】:
你有 n ( n ≤ 50 ) n(n\leq 50) n(n50)块蛋糕,每块蛋糕有单独的大小 ( x ≤ 32767 ) (x\leq 32767) (x32767),你要满足 m ( m ≤ 1000 ) m(m\leq 1000) m(m1000)个人,每个人想恰好吃到 a i a_i ai大小的蛋糕,你可以任意分割蛋糕,但不能合并,求最多能满足多少人
【思路】:
首先,本题的答案满足单调性,即可以满足 k k k个人,一定可以满足 k − 1 k-1 k1个人。所以我们使用二分,二分答案 m i d mid mid,表示可以满足 m i d mid mid个人
考虑使用 d f s dfs dfs判断 m i d mid mid是否可行
当然,原始的 d f s dfs dfs T T T,所以我们要剪枝
剪枝 1 1 1:按每个人需要的蛋糕从小到大排序,因为满足小的肯定比满足大的优
剪枝 2 2 2:记录一个浪费值 w a s t e waste waste,当一个蛋糕被分了后<最小的蛋糕需要,则 w a s t e + = waste+= waste+=蛋糕剩余大小。当所有蛋糕 − w a s t e < m i d -wastewaste<mid个人的需要,则剪枝
剪枝 3 3 3:当两个人的需要一样时,只考虑一个人即可。
(注:本思路为 P 1528 P1528 P1528题的思路,对于 P 2329 P2329 P2329题,请读者自己理解)
【代码】:

#include 
using namespace std;
int len[55],t[55];
int waste,need[1010];
int a[1010],sum,n,m;
int l,r,mid,ans,i;
bool dfs(int x,int part){
	if (x==0) return true;
	if (sum-waste<a[mid])
		return false;
//	剪枝1:当总量-浪费<需要时,剪枝 
	for(int i=part;i<=n;i++)
	if (t[i]>=need[x]){
		t[i]-=need[x];
		if (t[i]<need[1])
			waste+=t[i];
//		当一个木板剩余长度<最小需要时,浪费 
		if (need[x]==need[x-1]){
			if (dfs(x-1,i)) return true;
		}
		else if (dfs(x-1,1)) return true;
		if (t[i]<need[1])
			waste-=t[i];
		t[i]+=need[x];
	}
	return false;
}
inline int binary_search(){
	l=mid=ans=0;r=m;
	while (l<=r){
		mid=(l+r)>>1;waste=0;
		memcpy(t,len,sizeof(t));
		if (dfs(mid,1)){
			l=mid+1;
			ans=mid;
		}
		else r=mid-1;
	}
	return ans;
}//笔者最推荐的二分写法
int main(){
//	freopen("t1.in","r",stdin);
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d",&len[i]);
		sum+=len[i];
	}
	scanf("%d",&m);
	for(i=1;i<=m;i++)
	scanf("%d",&need[i]);
	sort(need+1,need+m+1);
	while (sum<need[m]) m--;
	for(i=1;i<=m;i++)
	a[i]=a[i-1]+need[i];
	cout<<binary_search();
	return 0;
}

注:本日记的思路重要来源于洛谷网校老师的讲解,若有侵权,请联系笔者,笔者立即删除!

你可能感兴趣的:(原创)