Codeforces Round #757 (Div. 2)


A. Divan and a Store

給你\(N\)個物品,每個物品有相應的價格\(a_i\),你有\(K\)元,問最多能買多少個價格在\([l,r]\)之間的物品
\(1 \leq N \leq 100\)

\(N\)很小,將物品從小到大排序,依次購買即可。

\(code:\)

#include<bits/stdc++.h>
using namespace std;
int t,n,l,r,k;
const int MAX_N = 100 + 5;
int a[MAX_N];
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d%d",&n,&l,&r,&k);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		sort(a+1,a+1+n);
		int cnt=0;
		for(int i=1;i<=n;i++){
			if(a[i]>=l && a[i]<=r){
				if(k>=a[i]){
					k-=a[i];
					cnt++;
				}
				else break;
			}
		}
		printf("%d\n",cnt);
	}
	return 0;
}

B. Divan and a New Project

在坐標軸上,你需要確定\(N\)個點的坐標,每個點需要到達\(a_i\)次,從\(0\)號點到\(i\)號點的距離為\(2|x_0-x_i|\),問最少需要走多少距離,並構造出任意一種方案。

按權值(到達次數)從大到小排序,對於權值大的點放在離\(0\)號節點近的地方。

\(code:\)

#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 200000 + 5;
int t,n,ans[MAX_N];
struct node{
	int x,id;
}a[MAX_N];
bool cmpx(node a,node b){
	return a.x>b.x;
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i].x);
			a[i].id=i;
		}
		sort(a+1,a+1+n,cmpx);
		ans[0]=0;
		int cnt1=0,cnt2=0;
		for(int i=1;i<=n;i++){
			if(i&1) ans[a[i].id]=++cnt1;
			else ans[a[i].id]=--cnt2;
		}
//		printf("\n");
		long long res=0;
		for(int i=1;i<=n;i++){
			res+=2ll*abs(ans[a[i].id])*a[i].x;
		}
		printf("%lld\n",res);
		for(int i=0;i<=n;i++){
			printf("%d ",ans[i]);
		}
		printf("\n");
	}
	return 0;
}

C. Divan and bitwise operations

位運算你能不能去死啊!!!
一個長度為\(N\)的序列,但你不知道序列的具體元素,只知道\(m\)段區間按位或的值,求這個序列的子序列(子集)異或和的和。

自閉題
這是一個場上還原了序列但不會統計答案的SB。

當我們確定序列后,考慮如何計算答案。
發現,如果枚舉子集肯定是不合理的,也想不到什么方法可以優化,但求的是異或和的和,考慮二進制下每一位單獨考慮,對於第\(i\)位,序列中第\(i\)位為1的數有\(cnt1\)個,為0的有\(cnt2\)個,對於為0的情況,選或不選都行,貢獻為\(2^{cnt2}\),考慮為1的情況,發現只有當選擇個數為奇數時,該為才會為1,所以貢獻為\(C_{cnt1}^1+C_{cnt1}^3+...+C_{cnt1}^{2k-1} = 2^{cnt1-1}\),所以貢獻為\(2^{cnt1-1}*2^{cnt2}*2^i\)

考慮如何還原原序列,可以發現,題目給定的限制是區間按位或的值。因為是按位或,所以二進制為0的位置,這區間的數二進制下該位置一定都為0。

於是使這個數能為1的地方都為1,隨便拿個什么東西來維護就行了,例如:線段樹,對每一位差分數組....

時間復雜度\(O(nlogn)\)

但是,發現答案式子\(2^{cnt1-1}*2^{cnt2}*2^i = 2^{n-1}*2^i\)那么只要第\(i\)位,\(n\)個數不全是0,那么都是必定有貢獻的,所以將每個按位或和按位或起來,得到的\(X\)就等於\(\sum 2^i (第i位為1)\)

時間復雜度\(O(n)\)

\(code: O(nlogn)\)

#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 200000 + 5;
const int mod = 1e9 + 7;
int t,n,m,ans[MAX_N];
struct node{
	int l,r,x;
}p[MAX_N];
namespace SegmentTree{
	#define ls ((p)<<1)
	#define rs ((p)<<1|1)
	int lazy[MAX_N<<2];
	void build(int p,int l,int r){
		lazy[p]=(1<<30)-1;
		if(l==r){
			return;
		}
		int mid=l+r>>1;
		build(ls,l,mid);
		build(rs,mid+1,r);
	}
	void pushdown(int p,int l,int r){
		if(lazy[p]==(1<<30)-1) return;
		lazy[ls]&=lazy[p];
		lazy[rs]&=lazy[p];
		lazy[p]=(1<<30)-1;
	}
	void modify(int p,int l,int r,int L,int R,int x){
		if(L<=l && r<=R){
			lazy[p]&=x;
			return;
		}
		pushdown(p,l,r);
		int mid=l+r>>1;
		if(L<=mid) modify(ls,l,mid,L,R,x);
		if(mid<R) modify(rs,mid+1,r,L,R,x);
	}
	int query(int p,int l,int r,int x){
		if(l==r){
			return lazy[p];
		}
		pushdown(p,l,r);
		int mid=l+r>>1;
		if(x<=mid) return query(ls,l,mid,x);
		else return query(rs,mid+1,r,x);
	}
}
inline void add(int &x,int y){
	x+=y;
	if(x>=mod) x-=mod;
}
int x[MAX_N];
int ksm(int x,int y){
	int res=1;
	while(y){
		if(y&1) res=1ll*res*x%mod;
		x=1ll*x*x%mod;
		y>>=1;
	}
	return res;
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) ans[i]=(1<<30)-1;
		SegmentTree::build(1,1,n);
		for(int i=1;i<=m;i++){
			scanf("%d%d%d",&p[i].l,&p[i].r,&p[i].x);
			SegmentTree::modify(1,1,n,p[i].l,p[i].r,p[i].x);
		}
		for(int i=1;i<=n;i++) ans[i]=SegmentTree::query(1,1,n,i);
		int cnt[2];
		int Ans=0;
		for(int k=0;k<30;k++){
			cnt[0]=cnt[1]=0;
			int tmp=0;
			for(int i=1;i<=n;i++){
				cnt[(ans[i]>>k)&1]++;
			}
			if(cnt[1]) add(Ans,1ll*ksm(2,cnt[0])*ksm(2,cnt[1]-1)%mod*(1<<k)%mod);
		}
//		add(Ans,Ans);
		printf("%d\n",Ans);
	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM