无论你愿意不愿意,明天开学了!!!
【题意】:
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(ai≤3×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 这两只兔子交换了颜色
对于每次操作询问答案
【数据范围】:
【思路】:
令 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;
}
【题意】:
你有 n ( n ≤ 50 ) n(n\leq 50) n(n≤50)块蛋糕,每块蛋糕有单独的大小 ( x ≤ 32767 ) (x\leq 32767) (x≤32767),你要满足 m ( m ≤ 1000 ) m(m\leq 1000) m(m≤1000)个人,每个人想恰好吃到 a i a_i ai大小的蛋糕,你可以任意分割蛋糕,但不能合并,求最多能满足多少人
【思路】:
首先,本题的答案满足单调性,即可以满足 k k k个人,一定可以满足 k − 1 k-1 k−1个人。所以我们使用二分,二分答案 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 -waste
剪枝 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;
}