# 分块

## 莫队算法

// 求区间内任选两个数字相同的概率	洛谷 P1494
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL k[50005],w[50005],tw[50005];
struct query{
LL l, r, id;
LL a, b;
bool operator <(const query &a)const{
return k[l] < k[a.l] || k[l] == k[a.l] && r < a.r;
}
}q[50005];	// 精髓就是这个分块排序

bool cmpid(const query &a,const query &b){
return a.id < b.id;
}

LL gcd(LL x,LL y){
return y == 0 ? x : gcd(y, x % y);
}

int change(LL &ans, LL pos, int flag){
pos = tw[pos];
if(flag){
ans += 2*w[pos];
w[pos]++;
}else{
ans += 2*(1-w[pos]);
w[pos]--;
}
}

int main(){
int n, m, i;
cin >> n >> m;
int kuai = (int)sqrt(double(n) + 0.5);
for(i = 1; i <= n; i++)
k[i] = (i - 1)/kuai + 1;
for(i = 1; i <= n; i++)
cin >> tw[i];
for(i = 1; i <= m; i++){
cin >> q[i].l >> q[i].r;
q[i].id=i;
}
sort(q + 1, q + 1 + m);
LL ans = 0;
LL l = 1, r = 0, a;
for(i = 1; i <= m; i++){
while(q[i].r > r)
change(ans, ++r, 1);
while(q[i].r < r)
change(ans, r--, 0);
while(q[i].l > l)
change(ans, l++, 0);
while(q[i].l < l)
change(ans, --l, 1);
if(q[i].r! = q[i].l){
q[i].a = ans;
q[i].b = (q[i].r - q[i].l + 1)*(q[i].r - q[i].l);
a = gcd(q[i].a, q[i].b);
q[i].a /= a;
q[i].b /= a;
}else{
q[i].a = 0;
q[i].b = 1;
}
}
sort(q + 1, q + 1 + m, cmpid);
for(i = 1; i <= m; i++)
cout << q[i].a << "/" << q[i].b) << endl;
return 0;
}


# 启发式搜索（玄学）

## 模拟退火

// 说实话这种玄学东西，我是挺讨厌的
// 洛谷 P1337
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 1e3 + 1;
double randrand(){return (double)rand()/RAND_MAX;}
double coor[maxn][10], w[maxn], LR[10][3];
int n;
double f(double x, double y){
double sumx = 0, sumy = 0, d;
for(int i = 1; i <= n; i++){
d = sqrt((x - coor[i][1])*(x - coor[i][1]) + (y - coor[i][2])*(y - coor[i][2]));
if(d == 0)continue;
sumx += (coor[i][1] - x)/d*w[i];
sumy += (coor[i][2] - y)/d*w[i];
}
return fabs(sumx) + fabs(sumy);
}
void sa(double &x, double &y, double &ans){
double t = 3000, eps = 1e-15;
while(t > eps){
double xtemp = x + (2*rand() - RAND_MAX)*t;
double ytemp = y + (2*rand() - RAND_MAX)*t;
if(xtemp < LR[1][1] || xtemp > LR[1][2])xtemp = LR[1][1] + randrand()*(LR[1][2] - LR[1][1]);
if(ytemp < LR[2][1] || ytemp > LR[2][2])ytemp = LR[2][1] + randrand()*(LR[2][2] - LR[2][1]);
double now = f(xtemp,ytemp);
if(now < ans){
ans = now;
x = xtemp;
y = ytemp;
}else if(exp((ans-now)/t) > randrand()){
x = xtemp;
y = ytemp;
}
t *= 0.98;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout << fixed << setprecision(3);
cin >> n;
for(int i = 1; i <= 2; i++)LR[i][1] = 10000, LR[i][2] = -10000;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= 2; j++){
cin >> coor[i][j];
LR[j][1] = min(LR[j][1], coor[i][j]);
LR[j][2] = max(LR[j][2], coor[i][j]);
}
cin >> w[i];
}
double x = LR[1][1] + randrand()*(LR[1][2] - LR[1][1]), y = LR[2][1] + randrand()*(LR[2][2] - LR[2][1]);
double ans = f(x,y);
sa(x, y, ans);
cout << x << " " << y << endl;

return 0;}


## 差分进化算法

// 洛谷 p1337
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<iomanip>
#include<time.h>
#include<math.h>
using namespace std;
#define endl '\n'
int n,ra[10],tol=2,np=20;   //tol是函数的自变量数量,np是种群总数，10*自变量数量
double xl[11],xr[11],cf=0.5,cr=0.5;  //xl，xr函数边界；

double randrand(){return (double)rand()/RAND_MAX;}

struct point{
double x[11],w;
void sub(point &a){for(int i=1;i<=tol;i++)x[i]-=a.x[i];}
void mul(double c){for(int i=1;i<=tol;i++)x[i]*=c;}
void cpy(point &a){for(int i=1;i<=tol;i++)x[i]=a.x[i];}
double disto(point &a){
double sum=0;
for(int i=1;i<=tol;i++)sum+=(x[i]-a.x[i])*(x[i]-a.x[i]);
return sqrt(sum);
}
void random(){for(int i=1;i<=tol;i++)x[i]=xl[i]+randrand()*(xr[i]-xl[i]);}
bool isover(){
for(int i=1;i<=tol;i++)
if(x[i]<xl[i]||x[i]>xr[i])
return true;
return false;
}
}po[1005],an[40],van[40];

double f(point &a){
double sumx=0,sumy=0,temp;
for(int i=1;i<=n;i++){
temp=a.disto(po[i]);
if(temp==0)continue;
sumx+=(po[i].x[1]-a.x[1])/temp*po[i].w;
sumy+=(po[i].x[2]-a.x[2])/temp*po[i].w;
}
return fabs(sumx)+fabs(sumy);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
double x[11],ans,ansx[11];
cout<<fixed<<setprecision(3);
cin>>n;
for(int i=1;i<=tol;i++)xl[i]=10000,xr[i]=-10000;
for(int i=1;i<=n;i++){
for(int j=1;j<=tol;j++){
cin>>po[i].x[j];
xl[j]=min(xl[j],po[i].x[j]);
xr[j]=max(xr[j],po[i].x[j]);
}
cin>>po[i].w;
}
for(int i=1;i<=np;i++)an[i].random();
ans=f(an[1]);
for(int i=1;i<=tol;i++)ansx[i]=an[1].x[i];
double oldone,newone;
int flag;
for(int tt=1;tt<=300&&ans>0.00001;tt++){
for(int i=1;i<=np;i++){
for(int j=0;j<=2;j++)
ra[j]=(int)round(randrand()*(np-1))+1;
van[i].cpy(an[ra[1]]);
van[i].sub(an[ra[2]]);
van[i].mul(cf*pow(2,exp(1.0-(double)tt/(303-tt))));
if(van[i].isover())van[i].random();
}
for(int i=1;i<=np;i++){
flag=(int)round(randrand()*1)+1;
for(int j=1;j<=2;j++)
if(flag==j)continue;
else if(randrand()>cr)van[i].x[j]=an[i].x[j];
}
for(int i=1;i<=np;i++){
newone=f(van[i]),oldone=f(an[i]);
if(newone<oldone){
oldone=newone;
an[i].cpy(van[i]);
}
if(oldone<ans){
ans=oldone;
for(int j=1;j<=tol;j++)ansx[j]=an[i].x[j];
}
}
}
cout<<ansx[1]<<" "<<ansx[2]<<endl;
return 0;
}



05-06 26
05-04 133
05-16 111
07-07 291