[ 一些题 ]

http://www.tuicool.com/articles/mEzqeaM

二分

1
Give you three sequences of numbers A, B, C, then we give
you a number X. Now you need to calculate if you can find
the three numbers Ai, Bj, Ck, which satisfy the formula
Ai+Bj+Ck = X.
1 ≤ L, N, M ≤ 500, 1 ≤ T ≤ 1000

枚举ai+bj,枚举k,再在ai+bj中二分找对应值。

2
你有 N 个物品,每个物品有 Ai,Bi 属性,要求选出 K 个物
品,使得
∑ i ϵ k A i ∑ i ϵ k B i \frac{\sum_{i\epsilon k} A_i}{\sum_{i\epsilon k} B_i} iϵkBiiϵkAi
取max。

上述式子等价于 ∑ A i − B i ∗ a n s \sum A_i-B_i*ans AiBians,于是我们先二分出 a n s ans ans,然后我们计算1~n的 V i = A i − B i ∗ a n s V_i = A_i-B_i*ans Vi=AiBians,最后取最大的k个 V i V_i Vi,求和即可。

整体二分

将询问集合二分到底层

莫队算法

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define reps(i,a,b) for(int i=a;i>=b;i--)
#define db(x) if(DEBUG) cout<<"{"<<"="<<(x)<<"}"
#define edl if(DEBUG) cout<<endl
//#define int long long
#define ll long long 
using namespace std;
const bool DEBUG = 1;
const int N = 50005;
int cnt[N]={0},a[N]={0},pos[N]={0};
int n,m,ans=0;

int rd(){
	int ans=0;
	char p=getchar();
	while(p>'9'||p<'0') p=getchar();
	while(p>='0'&&p<='9') ans=ans*10+p-'0',p=getchar();
	return ans;
}

struct que{
	int l,r,id;
} qu[N];

bool cmp(que a,que b){
	//printf("{%d %d %d}",a.id,a.l,a.r);
	if(pos[a.l]==pos[b.l])  
        return a.r<b.r;  
    return pos[a.l]<pos[b.l];  
}

void update(int x,int v){
	ans-=cnt[a[x]]*cnt[a[x]];
	cnt[a[x]]+=v;
	ans+=cnt[a[x]]*cnt[a[x]];
}

ll gcd(ll m,ll n){
	while(n!=0){
		ll t=m%n;
		m=n;
		n=t;
	}
	return m;
}

ll u[N],v[N];

int main(){
	cin>>n>>m;
	int q1,q2,pl=1,pr=0;
	int bk=ceil(sqrt(1.0*n));
	rep(i,1,n) a[i]=rd(),pos[i]=(i-1)/bk;//,cout<<","<<pos[i]<<",";
	rep(i,1,m){
		q1=rd(),q2=rd();
		qu[i]=(que){q1,q2,i};
	}
	sort(qu+1,qu+1+m,cmp);
	rep(i,1,m){
		int id=qu[i].id;
		if(qu[i].l==qu[i].r) {
			u[id]=0,v[id]=1;
			continue;
		}
		if(pr<qu[i].r)
			rep(j,pr+1,qu[i].r)
				update(j,1);
		else reps(j,pr,qu[i].r+1)
				update(j,-1);
		pr=qu[i].r;
		
		if(pl<qu[i].l)
			rep(j,pl,qu[i].l-1)
				update(j,-1);
		else reps(j,pl-1,qu[i].l)
				update(j,1);
		pl=qu[i].l;
		ll aa=ans-qu[i].r+qu[i].l-1;
		ll bb=(ll)(qu[i].r-qu[i].l+1)*(qu[i].r-qu[i].l);
		ll cc=gcd(aa,bb);
		aa/=cc,bb/=cc;
		u[id]=aa,v[id]=bb;
	}
	rep(i,1,m) printf("%lld/%lld\n",u[i],v[i]);	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值