自备ACM模板 —— 其他技巧

分块

莫队算法

// 求区间内任选两个数字相同的概率	洛谷 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 add(point &a){for(int i=1;i<=tol;i++)x[i]+=a.x[i];}
    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))));
            van[i].add(an[ra[0]]);
            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;
}

©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页