整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


目录

  • A、(2018 ACM-ICPC Shenyang J)How Much Memory Your Code Is Using?
  • B、(2018 ACM-ICPC Shenyang C)Insertion Sort
  • C、(2018 ACM-ICPC Shenyang G)Best ACMer Solves the Hardest Problem
  • D、(2018 ACM-ICPC Shenyang K)Let the Flames Begin
  • L、(2018 ACM-ICPC Shenyang E) The Kouga Ninja Scrolls
  • F、(2018 ACM-ICPC Shenyang L)Machining Disc Rotors
  • G、2018 ACM - ICPC shenyang I)Distance Between Sweethearts
  • H、(2018 ACM-ICPC Shenyang F)Counting Sheep in Ami Dongsuo
  • I、(2018 ACM-ICPC Shenyang M)Renaissance Past in Nancy

192队,除去打星186队 正式队伍
4题手速金(前18名),5题稳金(前12名)
3题手速银(前55名),4题稳银(前28名)
2题手速铜(前111名),3题稳铜(前73名)
这场体验极差,题太难,题太长,六级人何苦为难六级人(bushi) ,题长就算了,那么老长的好几大段话还都是有用的是最气的…

太难了太难了,拖了好几天也只做了9题…

我怎么感觉这套题是:签到 - 金牌

  • J 签到题(字符串模拟)0.5
  • C 组合计数(组合数学)2.5
  • G 思维,枚举(思维题)3
  • K 约瑟夫环(思维题)3.5
  • E 曼哈顿距离转切比雪夫(线段树)4
  • L 旋转卡壳(计算几何)4.5
  • I 数学期望 + 组合计数 + 快速沃尔什变换(FWT)5 +
  • F 多项式插值(多项式)5 +
  • M 可逆背包 + 生成函数(生成函数)4.5

比赛链接:https://codeforces.com/gym/101955

A、(2018 ACM-ICPC Shenyang J)How Much Memory Your Code Is Using?

Link

HDU - 6457

Problem

题目太长,不想翻译了…

Solution

签到题,字符串模拟。

bool 1
char 1
int 4
long long 8
__int128 16
float 4
double 8
long double 16

round up 是上取整

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>using namespace std;
typedef long long ll;
typedef int itn;
const int N = 2e5 + 7;
const ll INF = 4e18;int n, m, t;
int a[N], b, k1, k2, kcase;
string s;void solve()
{scanf("%d\n", &n);int ans = 0;while(n -- ) {getline(cin, s);//cout << s << endl;int type = 0, len = s.length();int num = 0;bool flag = false, vis = 0;for(int i = 0; i < len; ++ i) {if(s[i] == ']') {flag = 0;}if(flag) {num = num * 10 + s[i] - '0';}if(s[i] == '[') {flag = 1;}}if(s[0] == 'i')type = 4;else if(s[0] == 'b')type = 1;else if(s[0] == 'c')type = 1;else if(s[0] == '_')type = 16;else if(s[0] == 'l' && s[5] == 'l')type = 8;else if(s[0] == 'l' && s[5] == 'd')type = 16;else if(s[0] == 'f')type = 4;else if(s[0] == 'd')type = 8;if(num == 0) num = 1;ans += type * num;}ans = ceil((double)ans / 1024);//cout << ans <<endl;printf("Case #%d: %d\n", ++ kcase, ans);
}
/*
int 4
long long 8
__int128 16
float 4
double 8
long double 16
*/
int main()
{scanf("%d", &t);while(t -- ) {solve();}
}

B、(2018 ACM-ICPC Shenyang C)Insertion Sort

HDU - 6450

Problem

太长了…

Translation

题意就是,输入 n,k,pn,k,pn,k,p,你需要构造一个 111 到 nnn 的全排列,它会帮你把前 kkk 个数排序,也就是前 kkk 个数你不管构造的是啥,它都帮你变成上升序列,你需要保证这个全排列是一个近似上升序列,其中近似上升序列是指, 一个长度为 nnn 的序列,至少存在长度为 n−1n-1n−1 的上升子序列则称它为近似上升序列。问构造出这个长度为 nnn 的排列的方案数。ppp 是模数。

Solution

先是给了你一个特殊的插入排序的伪代码,发现这个排序算法只能排前 kkk 个数,也就是题目能保证前 kkk 个数不管被你糟蹋成啥都帮你排好序,所以我们前 kkk 个数可以乱放,也就是一共 k!k!k! 种方案数。

首先我们看这 kkk 个数就比较蹊跷, 若 k>nk>nk>n ,显然总方案数为 n!n!n!,特判一下就好。

然后我们来分析题意,发现我们需要构造一个近似上升序列,也就意味着有一个数是可以违反上升的规则,或者一个都没有,其余的数构造的时候必须满足上升并且因为整个序列是整体的,所以前面的数也不能大于后面的数。并且因为是 1∼n1 \sim n1∼n 的全排列所以不存在相同的数。所以我们只需要分析这个特殊的数的情况即可。

  • 特殊的数在后面

因为此时特殊的数在后面,也就意味着前 kkk 个数是1∼k1 \sim k1∼k,那么若后面的数有序是 111 种方案,一个数违反上升规则,即从 n−kn-kn−k 个数里选出一个数,插入到剩下的 n−k−1n − k − 1n−k−1 个空(那之前是 n−k+1n-k+1n−k+1 个空,拿走一个数,带走两个空),这种情况一共 (n−k−1)×(n−k)( n − k − 1 ) \times( n − k )(n−k−1)×(n−k) 种方案。考虑有没有重复。我们发现对于相邻的两个数A<BA<BA<B ,把 AAA 插到 BBB 的后面和 BBB 插入到 AAA 的前面是等价的(相邻两个数交换是一种方案)。所以还要减掉 (n−k−1)( n − k − 1 )(n−k−1) 种重复的情形,最后前 kkk 个数的方案数为 k!k!k!,综上所诉,在这种情况下,总方案数为 k!×[(n−k−1)×(n−k)−(n−k−1)]k!\times [(n-k-1)\times(n-k)-(n-k-1)]k!×[(n−k−1)×(n−k)−(n−k−1)]。

  • 特殊的数在前面

现在只剩下特殊的数在前面这种情况,也就是说我们在后面( k+1∼nk+1\sim nk+1∼n )中挑一个数,放到前面。

我们发现一个数放到前面,也就意味着有一个数被移到后面,而一个很小的数放到后面,放到前面的数被buff了,但是有这个很小的数在,序列就不满足近似升序了。所以发现只有中间的这两个数 kkk 和 k+1k + 1k+1 比较特殊。

所以我们考虑,若将 k+1k+1k+1 与前面的数交换, k+1k+1k+1 可以不占用 buff 的名额,将这个buff给前面的那个数,这样前面 kkk 个数排序以后,满足升序,也意味着前 kkk 个数可以任选一个数与 k+1k+1k+1 交换,并放到后面 n−kn-kn−k 个空里,前 kkk 个数 k!k!k! 种任意排列,此时的总方案数为 k!×(k(n−k))k!\times (k(n-k))k!×(k(n−k))。

若将一个大于 k+1k+1k+1 的数放到前面,很明显,我们只能将这个数与 kkk 交换,这样将 kkk 放到后面 n−kn-kn−k 个数的最前面,仅这一种情况,才能保证升序,后面 n−kn-kn−k 个数可选,前 kkk 个数 k!k!k! 种任意排列,此时的总方案数为 k!×(n−k)×1=k!×(n−k)k!\times (n-k)\times 1=k!\times (n-k)k!×(n−k)×1=k!×(n−k)。

综上所述,根据加法原理,总方案数为 [k!×[(n−k−1)×(n−k)−(n−k−1)]]+[k!×(k(n−k))]+[k!×(n−k)]=k!×[(n−k)×(n−1)+1][k!\times [(n-k-1)\times(n-k)-(n-k-1)]] + [k!\times (k(n-k))]+[k!\times (n-k)]=k!\times[(n-k)\times(n-1)+1][k!×[(n−k−1)×(n−k)−(n−k−1)]]+[k!×(k(n−k))]+[k!×(n−k)]=k!×[(n−k)×(n−1)+1]

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>using namespace std;
typedef long long ll;
typedef int itn;
const int N = 2e4 + 7;
const ll INF = 4e18;int n, m, t, kcase, p, k;int x[N], y[N];void solve()
{scanf("%d%d%d", &n, &k, &p);ll ans = 1;if(k > n) {for(int i = 1; i <= n; ++ i) ans = ans * i % p;printf("Case #%d: %lld\n", ++ kcase, ans);return ;}for(int i = 1; i <= k; ++ i) ans = ans * i % p;ans = ans * ((n - k) * (n - 1) + 1) % p;printf("Case #%d: %lld\n", ++ kcase, ans);
}int main()
{scanf("%d", &t);while(t -- ) {solve();}
}

C、(2018 ACM-ICPC Shenyang G)Best ACMer Solves the Hardest Problem

Problem

太长了…有意思吗?

Translation

一个 X,YX,YX,Y 轴平面中有若干个带权点, 首先加入 nnn 个点, mmm次操作。

操作一:新加入一个坐标为 xi,yix_i, y_ixi​,yi​ ,权值为www 的点。

操作二:删除一个坐标为 xi,yix_i, y_ixi​,yi​ 的点。

操作三:将与 xi,yix_i, y_ixi​,yi​ 之间距离为 k\sqrt kk​ 点的权值加上 www。

操作四:输出 与 xi,yix_i, y_ixi​,yi​ 之间距离为 k\sqrt kk​ 的点的权值之和。

1≤n,m≤105,1≤x,y,w≤60001 \le n, m \le 10^5,1 \le x, y, w \le 60001≤n,m≤105,1≤x,y,w≤6000

Solution

对每个 k 预处理 xx+yy=k 的所有 (x,y) 。
那么每次修改和查询时可以暴力枚举所有符合条件的点,且在 sqrt(k)<=3200 的时间内完成 。用unordered_map维护即可。

Code

D、(2018 ACM-ICPC Shenyang K)Let the Flames Begin

Problem

太长了…

Translation

Solution

约瑟夫环
待更…

Code

L、(2018 ACM-ICPC Shenyang E) The Kouga Ninja Scrolls

Problem

太长了…

Translation

Solution

曼哈顿距离转切比雪夫距离,线段树维护

Code
待更…

F、(2018 ACM-ICPC Shenyang L)Machining Disc Rotors

HDU - 6450

Problem

太长了…

Translation

用n个不相交的圆去切割一个圆S,求S剩余部分中最远的两个点的距离

Solution

当答案小于直径时,距离最远的两个点必然为圆的交点,(画画图就知道了)
当答案等于直径时,我们可以枚举圆的交点,求出交点对应的直径的直线与圆的另一个交点,判断一下该交点是否被其他圆覆盖,若没有则答案为直径
当交点个数小于2时答案为直径

Code

#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-11; //避免浮点精度误差
const double PI = acos(-1);
int dcmp(double x)
{if(fabs(x)<=eps)return 0;return x>0?1:-1;
}//点
struct Point
{double x,y;Point()=default;Point(double x,double y):x(x),y(y){}Point operator + (const Point& a)const{return Point(x+a.x,y+a.y);}Point operator - (const Point& a)const{return Point(x-a.x,y-a.y);}Point operator * (double k)const{return Point(x*k,y*k);}Point operator / (double k)const{return Point(x/k,y/k);}double operator * (const Point& a)const{return x*a.x+y*a.y;}; //点积double operator ^ (const Point& a)const{return x*a.y-y*a.x;}; //叉积bool operator < (const Point& a)const{return (x!=a.x)?x<a.x:y<a.y;} //bool operator == (const Point& a)const{return !dcmp(x-a.x)&&!dcmp(y-a.y);}
};
typedef Point Vector;
double lenth(Vector a){return sqrt(a*a);}
Vector rot(const Vector a,const double d){return Vector(a.x*cos(d)-a.y*sin(d),a.y*cos(d)+a.x*sin(d));
} //向量旋转
double S_sjx(Point a,Point b,Point c){return ((b-a)^(c-a))/2;   //可能为负;
}
Vector Nol(const Vector a){return Vector(-a.y,a.x)/lenth(a);}//法向量
double ang(const Vector a){return atan2(a.y,a.x);} //点的极角
double ang(const Vector a,const Vector b){return acos(a*b/lenth(a)/lenth(b));} //向量极角
//线
struct Line  //点斜式
{Point x; Vector v;Line()=default;Line(const Point &x,const Vector &y):x(x),v(y){}
};
Point P_L(Point p,Line l)   //求直线垂足
{return l.x+l.v*(((p-l.x)*l.v)/(l.v*l.v));
}
Point L_L(Line a,Line b)  //直线求交点 。
{double t = (b.v^(b.x-a.x))/(b.v^a.v);return a.x+a.v*t;
}double dis_p_l(Point a,Line l) //点到直线距离
{return fabs(l.v^(a-l.x))/lenth(l.v);
}
double dis_p_s(Point p,Point a,Point b) //点到线段的距离
{if(a==b)return lenth(p-a);Vector v1 = b-a,v2 = p-a,v3 = p-b;if(v1*v2<=0)return lenth(v2);if(v1*v3>=0)return lenth(v3);return (v1^v2)/lenth(v1);
}
bool S_S(Point a1,Point a2,Point b1,Point b2) //线段是否相交
{double d1 = (a2-a1)^(b1-a1),d2 = (a2-a1)^(b2-a1);double d3 = (b2-b1)^(a1-b1),d4 = (b2-b1)^(a2-b1);return dcmp(d1)*dcmp(d2)<0&&dcmp(d3)*dcmp(d4)<0;
}
bool P_S(Point p,Point a,Point b)  //点在线段内
{Vector A = a-p,B = b-p;return dcmp(A*B)==0&&dcmp(A^B)<0;
}//圆:struct Circle
{Point p;double r;Circle(){}Circle(Point p,double r):p(p),r(r){}Point point(double rad){return Point(p.x+r*cos(rad),p.y+r*sin(rad));}
};int L_C(Line l,Circle c,vector<Point>&ve)  //圆与直线求交点
{Point p = c.p;double r = c.r,dis = dis_p_l(p,l);if(dcmp(dis-r)>0)return 0;else if(!dcmp(dis-r)){ve.push_back(P_L(p,l));return 1;}Point h = P_L(p,l);Vector tmp = Nol(h-p);double len = sqrt(r*r-dis*dis);if(len==r)tmp=l.v/lenth(l.v);ve.push_back(h+tmp*len);ve.push_back(h-tmp*len);return 2;
}
int C_C(Circle a,Circle b,vector<Point>&ve)  //圆与圆求交点
{double dis = lenth(a.p-b.p);if(!dcmp(dis)){if(!dcmp(a.r-b.r))return -1;return 0;}if(dcmp(a.r+b.r-dis)<0)return 0;double rad = ang(b.p-a.p);double dlt = acos((a.r*a.r+dis*dis-b.r*b.r)/(2*a.r*dis));Point p1 = a.point(rad+dlt),p2 = a.point(rad-dlt);if(p1==p2){ve.push_back(p1);return 1;}else{ve.push_back(p1);ve.push_back(p2);return 2;}
}
int C_C_pos(Circle a,Circle b){double dist = lenth(a.p-b.p);if(fabs(dist-a.r-b.r)>=0)return -1; //相离int tmp = dcmp(fabs(dist-a.r)-(a.r+b.r));if(tmp>=0)return 0;  //内含return 1; //相交
}void solve(int cs)
{int n,r;scanf("%d%d",&n,&r);Circle s(Point(0,0),r);double x,y,z;vector<Circle>a(n+1);bool use[n+1];memset(use,1,sizeof(use));for(int i = 1;i <= n;++i){scanf("%lf%lf%lf",&x,&y,&z);a[i] = Circle(Point(x,y),z);}sort(a.begin()+1,a.end(),[](Circle a,Circle b)->bool{return a.r<b.r;});for(int i = 1;i <= n;++i){for(int j = i+1;j <= n;++j){if(C_C_pos(a[i],a[j])==0){use[i] = 0;}}if(C_C_pos(a[i],s)==0){use[i] = 0;}}vector<Circle>tmp;for(int i = 1;i <= n;++i){if(use[i]==1)tmp.push_back(a[i]);}a = tmp;vector<Point>inter; //求圆与圆交点for(auto &x:a){vector<Point>tmp;C_C(s,x,tmp);for(auto &y:tmp)inter.push_back(y);}double ans = 0;if(inter.size()<2){ans = s.r*2;}else{for(auto &x:inter){for(auto &y:inter){ans = max(ans,lenth(x-y));}}for(auto &x:inter){Line tmp = Line(x,Vector(x.x,x.y));vector<Point>in;L_C(tmp,s,in);Point ano;if(in[0]==x)ano=in[1];else ano = in[0];bool ok = true;for(auto &y:a){double dis = lenth(ano-y.p);if(dcmp(dis-y.r)<0){ok=false;break;}}if(ok){ans = s.r*2;break;}}}printf("Case #%d: %.15f\n",cs,ans);
}int main()
{int t;scanf("%d",&t);int cs = 0;while(t--){cs++; solve(cs);}return 0;
}

G、2018 ACM - ICPC shenyang I)Distance Between Sweethearts

Link

Link

HDU 6456

Problem

太长不看

给定6个不超过 2000 的整数: UIboy,UAboy,UGboyUI_{boy}, UA_{boy}, UG_{boy}UIboy​,UAboy​,UGboy​ 和 UIgirl,UAgirl,UGgirlUI_{girl}, UA_{girl}, UG_{girl}UIgirl​,UAgirl​,UGgirl​

定义 Igirl,Agirl,GgirlI_{girl}, A_{girl}, G_{girl}Igirl​,Agirl​,Ggirl​ 和 Iboy,Aboy,GboyI_{boy}, A_{boy}, G_{boy}Iboy​,Aboy​,Gboy​。

给出了以下公式来测量我的爱人和我的心之间的距离:

distance(boy,girl)=max⁡{∣Iboy−Igirl∣,∣Aboy−Agirl∣,∣Gboy−Ggirl∣}⊕Iboy⊕Aboy⊕Gboy⊕Igirl⊕Agirl⊕Ggirldistance(boy, girl) = \max\{|I_{boy} - I_{girl}|, |A_{boy} - A_{girl}|, |G_{boy} - G_{girl}|\} \oplus I_{boy} \oplus A_{boy} \oplus G_{boy} \oplus I_{girl} \oplus A_{girl} \oplus G_{girl}distance(boy,girl)=max{∣Iboy​−Igirl​∣,∣Aboy​−Agirl​∣,∣Gboy​−Ggirl​∣}⊕Iboy​⊕Aboy​⊕Gboy​⊕Igirl​⊕Agirl​⊕Ggirl​

其中maxSmax{S}maxS、∣x∣|x|∣x∣ 和 ⊕⊕⊕ 分别对应S的最大值、x的绝对值和位异或运算符。

它们满足以下限制条件:

0≤Igirl≤UIgirl,0≤Agirl≤UAgirl,0≤Ggirl≤UGgirl0 \le I_{girl} \le UI_{girl}, 0 \le A_{girl} \le UA_{girl}, 0 \le G_{girl} \le UG_{girl}0≤Igirl​≤UIgirl​,0≤Agirl​≤UAgirl​,0≤Ggirl​≤UGgirl​

0≤Iboy≤UIboy,0≤Aboy≤UAboy,0≤Gboy≤UGboy0 \le I_{boy} \le UI_{boy}, 0 \le A_{boy} \le UA_{boy}, 0 \le G_{boy} \le UG_{boy}0≤Iboy​≤UIboy​,0≤Aboy​≤UAboy​,0≤Gboy​≤UGboy​

它们的任意值在其限制条件下都可以是具有相同概率的整数。

现在我需要你的帮助来计算我们这对依然热恋的情侣的心之间距离的期望。

请你输出 (1+UIboy)(1+UAboy)(1+UGboy)(1+UIgirl)(1+UAgirl)(1+UGgirl)(1 + UI_{boy}) (1 + UA_{boy}) (1 + UG_{boy}) (1 + UI_{girl}) (1 + UA_{girl}) (1 + UG_{girl})(1+UIboy​)(1+UAboy​)(1+UGboy​)(1+UIgirl​)(1+UAgirl​)(1+UGgirl​) 与距离的期望的乘积(保证答案一定是一个整数)。

保证答案在 264−12^{64} - 1264−1 以内。

Sample Input

3
3 1 2 4 3 3
1 2 1 2 1 3
3 2 5 4 3 5

Sample Output

Case #1: 3880
Case #2: 369
Case #3: 24728

Solution

啊我讲的太清楚了,这道题我已经懂的透透的了

确实是好题,而且不算太难,读清题意之后挺板子的 hhh

但是能不能别搞这么长的题!!!


题目要求的是期望,但是没有给权重,所以不能用期望公式 E(X)=∑pi×xiE(X)=\sum p_i\times x_iE(X)=∑pi​×xi​ 来算,因为题目中说了每个任意值在限制条件下都是具有相同概率的整数,所以实际上这道题就是求平均值。

也就是例如:设随机变量 XXX 表示掷一个骰子的点数,显然期望为 E(X)=1+2+3+4+5+66=3.5E(X)=\cfrac{1+2+3+4+5+6}{6}=3.5E(X)=61+2+3+4+5+6​=3.5

期望的性质:E(aX+bY)=a×E(X)+b×E(Y)E(aX+bY)=a\times E(X)+b\times E(Y)E(aX+bY)=a×E(X)+b×E(Y)


我们知道距离的期望 ans=∑(distance×方案数)总个数ans= \frac{\sum (distance \times\text{方案数})}{总个数}ans=总个数∑(distance×方案数)​

而总个数等于 (1+UIboy)(1+UAboy)(1+UGboy)(1+UIgirl)(1+UAgirl)(1+UGgirl)(1 + UI_{boy}) (1 + UA_{boy}) (1 + UG_{boy}) (1 + UI_{girl}) (1 + UA_{girl}) (1 + UG_{girl})(1+UIboy​)(1+UAboy​)(1+UGboy​)(1+UIgirl​)(1+UAgirl​)(1+UGgirl​) ,因为每个数 III 的范围都是 0∼U0\sim U0∼U。

题目要求的是 (1+UIboy)(1+UAboy)(1+UGboy)(1+UIgirl)(1+UAgirl)(1+UGgirl)(1 + UI_{boy}) (1 + UA_{boy}) (1 + UG_{boy}) (1 + UI_{girl}) (1 + UA_{girl}) (1 + UG_{girl})(1+UIboy​)(1+UAboy​)(1+UGboy​)(1+UIgirl​)(1+UAgirl​)(1+UGgirl​) 与距离的期望的乘积,也就是答案 ans=∑(distance×方案数)ans=\sum (distance \times\text{方案数})ans=∑(distance×方案数)。

所以这是一个计数问题!实际上这道题就是让你求所有能组成的 distance 以及组成这个distance 的方案数!这不就跟上一题一样吗!

考虑 FWT。

所以我们尽量将找一个数组,使得公式中想要进行异或卷积的那些数是这个数组的下标!

所以我们来一步一步分析题目。先来分析一下 Max\text{Max}Max ,若三个绝对值分别为 (x,y,z)(x,y,z)(x,y,z),则 Max=max⁡{x,y,z}\text{Max} = \max\{x,y,z\}Max=max{x,y,z}

我们知道这三个绝对值的实际意义就是 boyboyboy 与 girlgirlgirl 之间的差值。假设男生属性值都低于女生(对输入的数据交换一下就行了),则可得到:

distance=max⁡{x,y,z}⊗Iboy⊗(Iboy+x)⊗Aboy⊗(Aboy+y)⊗Gboy⊗(Gboy+z)distance = \max\{x,y,z\} \otimes I_{boy} \otimes (I_{boy}+x) \otimes A_{boy} \otimes (A_{boy} + y) \otimes G_{boy} \otimes (G_{boy} + z)distance=max{x,y,z}⊗Iboy​⊗(Iboy​+x)⊗Aboy​⊗(Aboy​+y)⊗Gboy​⊗(Gboy​+z)

注意输入的六个整数 UIboy,UAboy,UGboyUI_{boy}, UA_{boy}, UG_{boy}UIboy​,UAboy​,UGboy​ 和 UIgirl,UAgirl,UGgirlUI_{girl}, UA_{girl}, UG_{girl}UIgirl​,UAgirl​,UGgirl​ 均为 Igirl,Agirl,GgirlI_{girl}, A_{girl}, G_{girl}Igirl​,Agirl​,Ggirl​ 和 Iboy,Aboy,GboyI_{boy}, A_{boy}, G_{boy}Iboy​,Aboy​,Gboy​ 的范围,也就是关键在于
0≤Igirl≤UIgirl,0≤Agirl≤UAgirl,0≤Ggirl≤UGgirl0 \le I_{girl} \le UI_{girl}, 0 \le A_{girl} \le UA_{girl}, 0 \le G_{girl} \le UG_{girl}0≤Igirl​≤UIgirl​,0≤Agirl​≤UAgirl​,0≤Ggirl​≤UGgirl​

0≤Iboy≤UIboy,0≤Aboy≤UAboy,0≤Gboy≤UGboy0 \le I_{boy} \le UI_{boy}, 0 \le A_{boy} \le UA_{boy}, 0 \le G_{boy} \le UG_{boy}0≤Iboy​≤UIboy​,0≤Aboy​≤UAboy​,0≤Gboy​≤UGboy​

而 UUU 小于 200020002000,所以我们就可以枚举。

我们统计出每种 Iboy⊗IgirlI_{boy} \otimes I_{girl}Iboy​⊗Igirl​ ( ∣Iboy−Igirl∣≤x|I_{boy} - I_{girl}| ≤ x∣Iboy​−Igirl​∣≤x ) ,也就是枚举差值 x,y,zx,y,zx,y,z 的最大值 Max\text{Max}Max ,三个差值最大值为 Max\text{Max}Max,也就意味着 boyboyboy 与 girlgirlgirl 之间的最大差值也不会超过 Max\text{Max}Max 。所以我们在枚举到某个 Max\text{Max}Max 值时预处理出所有差值为 Max\text{Max}Max 且异或值为 ttt 的数对有多少个存到数组中,注意记住保留这个值,这样我们计算到 Max\text{Max}Max 时就说明把 1∼Max1\sim \text{Max}1∼Max 的所有差值都加在了这个数组中,也就是所有情况都有了。至此,我们知道了每个属性差值最大为 Max\text{Max}Max 时每个异或值有多少种可能,总共产生三个 cnt 数组 cntI,cntA,cntGcnt_I,cnt_A,cnt_GcntI​,cntA​,cntG​。

显然根据乘法原理,我们可以求出 Max=Iboy⊗(Iboy+x)⊗Aboy⊗(Aboy+y)⊗Gboy⊗(Gboy+z)\text{Max} = I_{boy} \otimes (I_{boy}+x) \otimes A_{boy} \otimes (A_{boy} + y) \otimes G_{boy} \otimes (G_{boy} + z)Max=Iboy​⊗(Iboy​+x)⊗Aboy​⊗(Aboy​+y)⊗Gboy​⊗(Gboy​+z) 的方案数为:

∑(cntI[Iboy⊗(Iboy+x)]×cntA[Aboy⊗(Aboy+y)]×cntG[Gboy⊗(Gboy+z)])∑ (cnt_I[ I_{boy} \otimes (I_{boy}+x) ] \times cnt_A[A_{boy} \otimes (A_{boy} + y)] \times cnt_G[G_{boy} \otimes (G_{boy} + z)])∑(cntI​[Iboy​⊗(Iboy​+x)]×cntA​[Aboy​⊗(Aboy​+y)]×cntG​[Gboy​⊗(Gboy​+z)])

这样我们就将数值的异或操作 Iboy⊗(Iboy+x)I_{boy} \otimes (I_{boy}+x)Iboy​⊗(Iboy​+x) 转换为了数组的下标,这样我们就可以使用 FWT 加速异或卷积了。

但我们还要计算 Max\text{Max}Max,那么在 Max\text{Max}Max 值固定的情况下,也就是 x,y,zx,y,zx,y,z 至少有一个等于定值 Max\text{Max}Max,因为 Max=max⁡{x,y,z}\text{Max}=\max\{x,y,z\}Max=max{x,y,z} 嘛。那么这样的方案数如何统计呢?

考虑容斥,令一种方案为 Iboy,Igirl=(Iboy+x),Aboy,Agirl=(Aboy+y),Gboy,Ggirl=(Gboy+z)I_{boy} ,I_{girl} = (I_{boy}+x), A_{boy} , A_{girl} =(A_{boy} + y) , G_{boy} ,G_{girl} = (G_{boy} + z)Iboy​,Igirl​=(Iboy​+x),Aboy​,Agirl​=(Aboy​+y),Gboy​,Ggirl​=(Gboy​+z) ,记作 (x,y,z)(x,y,z)(x,y,z)

因为我们的条件是至少有一个数 等于 Max\text{Max}Max,如果我们计算出来了 x≤Max &&y≤Max &&z≤Maxx\le \text{Max}\ \&\&\ y\le\text{Max}\ \&\&\ z\le \text{Max}x≤Max && y≤Max && z≤Max 的方案数 AAA(满足条件上界),又计算出了 x<Max &&y<Max &&z<Maxx<\text{Max}\ \&\&\ y<\text{Max}\ \&\&\ z <\text{Max}x<Max && y<Max && z<Max 的方案数 BBB (不满足条件的下界), 上述的方案数就等于 A−BA - BA−B。我们怎么计算这个差值呢?很明显因为我们是枚举 Max\text{Max}Max 计算的,所以我们用前缀和维护,pre[i]pre[i]pre[i] 表示三个数都大于等于 Max=i\text{Max}=iMax=i,pre[i−1]pre[i - 1]pre[i−1] 就表示三个数都大于等于 i−1i-1i−1,即三个数都小于 Max\text{Max}Max。 我们将二者相减即为答案 A−BA-BA−B。


总结一下思路:

枚举 Max\text{Max}Max, 把每个绝对值展开,用 cntcntcnt 数组记录个数。后面的异或看作 FWT 下标,FWT 之后,即可求出 Max\text{Max}Max 里面三个绝对值恰好都小于等于 Max\text{Max}Max 的方案数。由于题目中要求的是至少一个绝对值小于等于 Max\text{Max}Max。所以用前缀和, preprepre 数组记录之前 FWT 的结果,每次 FWT 后,减掉 preprepre ,就是至少一个小于等于 Max\text{Max}Max 的方案数。distance = Max ^ i,其中 distance 就是题目公式中的 distance,Max 是枚举到的 Max\text{Max}Max,iii 是枚举到的异或值(异或值转成下标了)

顺带一提,保证答案在 264−12^{64} - 1264−1 以内,所以我们最后的答案 ans 要用 unsigned long long 存,用 cout 输出。

Code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>using namespace std;
typedef long long ll;
typedef int itn;
typedef unsigned long long ull;
const int N = 2048 + 7, mod = 1e9 + 7;
const ll INF = 4e18;
itn dcnt;
#define de(x) cout << x << " x" << endl
#define de1() cout << ++ dcnt << "ok" << endl
itn t;
ll a[5][N], cnt[5][N];
ll pre[N];void XOR(ll *f, int n, int x = 1)
{for(int o = 2; o <= n; o <<= 1) {for(int i = 0, k = o >> 1; i < n; i += o) {for(int j = 0; j < k; ++ j) {ll X = f[i + j];ll Y = f[i + j + k];f[i + j] = X + Y;f[i + j + k] = X - Y;if(x == -1) {f[i + j] = (X + Y) / 2;f[i + j + k] = (X - Y) / 2;}}}}
}void update(int n, int m, int d, int id)
{for(int i = 0; i <= n && i + d <= m; ++ i) {cnt[id][i ^ (i + d)] ++ ;//boy ^ girl}if(d) {//不等于0说明有两个,一个 boy 一个 girlfor(int i = 0; i <= m && i + d <= n; ++ i) {cnt[id][i ^ (i + d)] ++ ;}}
}ll uib, uab, ugb, uig, uag, ugg;
int kcase;int main()
{scanf("%d", &t);while(t -- ) {memset(pre, 0, sizeof pre);memset(a, 0, sizeof a);memset(cnt, 0, sizeof cnt);scanf("%lld%lld%lld%lld%lld%lld", &uib, &uab, &ugb, &uig, &uag, &ugg);if(uib > uig) swap(uib, uig);if(uab > uag) swap(uab, uag);if(ugb > ugg) swap(ugb, ugg);int maxx = max({uig, uag, ugg});int tmp = maxx;itn n = 1;ull ans = 0;while(tmp) {tmp >>= 1;// 2的整数幂n <<= 1;}for(int Max = 0; Max <= maxx; ++ Max) { //枚举距离dupdate(uib, uig, Max, 0);update(uab, uag, Max, 1);update(ugb, ugg, Max, 2);for(int i = 0; i < n; ++ i) {//赋值,准备卷a[0][i] = cnt[0][i];a[1][i] = cnt[1][i];a[2][i] = cnt[2][i];}XOR(a[0], n);XOR(a[1], n);XOR(a[2], n);for(int i = 0; i < n; ++ i)a[0][i] = a[0][i] * a[1][i] * a[2][i];XOR(a[0], n, -1);for(int i = 0; i < n; ++ i) {ll distance = 1ll * (Max ^ i);ans += 1ull * (a[0][i] - pre[i]) * distance;//根据容斥,减掉前面的贡献pre[i] = a[0][i];}}cout << "Case #" <<  ++ kcase<< ": " << ans << endl;}return 0;
}

H、(2018 ACM-ICPC Shenyang F)Counting Sheep in Ami Dongsuo

Problem

太长了…

Translation

Solution

题意

有一张 nnn 个点的拓扑图,每个点有个权值,权值不超过 www。

有三个人要从同一个点出发,走三条不同的路线。这种方案的权值就是他们最后停在的那三个点的权值和。

对于 k=0∼30000k=0\sim 30000k=0∼30000,问权值为 kkk 的方案有多少种。膜 109+710^9+7109+7。

范围

n≤10000,m≤30000,w≤400n\le 10000,\space m\le 30000,\space w\le 400n≤10000, m≤30000, w≤400

题解

三条路线要不同的限制,只要容斥一下就行了。

考虑求从一个点出发,三个结束点权值为 www 的方案数。

直接做就是个卷积,O(mwlog(w))O(mwlog(w))O(mwlog(w))。

可以把 1∼3w1\sim 3w1∼3w 拿进去求点值,

Code

https://blog.csdn.net/wxh010910/article/details/84488248?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.control&dist_request_id=a3ae9509-4477-4352-a94d-db6f2c839234&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.control

https://www.cnblogs.com/ShichengXiao/p/10444214.html#autoid-8-3-0

I、(2018 ACM-ICPC Shenyang M)Renaissance Past in Nancy

Problem

太长了…

Translation

Solution

可逆背包

https://blog.csdn.net/algor_pro_king_john/article/details/97533115

https://kimoyami.github.io/2019/10/05/2018-2019-ACM-ICPC-Asia-Shenyang-Regional-Contest-M-Renaissance-Past-in-Nancy/

2018 ACM-ICPC Asia Shenyang Regional Contest 题解(9 / 13)【每日亿题2021/2/24】相关推荐

  1. 2017 ACM ICPC Asia Shenyang Regional Contest 题解(10 / 13)【每日亿题2 / 16】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 A.(2017 ICPC shenyang I)Little Boxes B.(2017 ICP ...

  2. 2016 ACM / ICPC Asia dalian Regional Contest 题解(11 / 11)【每日亿题2021 / 2 / 17】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 A .(2017 ACM ICPC dalian H)To begin or not to be ...

  3. 2018-2019 ACM-ICPC, Asia Shenyang Regional Contest题解

    以下所有AC题解代码来自"仙客传奇"团队. AC题数:4/13 CGJK A. Sockpuppets B. Sequences Generator C. Insertion So ...

  4. 【题目记录】——The 2021 ICPC Asia Jinan Regional Contest

    文章目录 C Optimal Strategy 组合数 H Game Coin K Search For Mafuyu 欧拉序列 题目集地址 The 2021 ICPC Asia Jinan Regi ...

  5. 2018 ICPC Asia Jakarta Regional Contest

    2018 ICPC Asia Jakarta Regional Contest 题号 题目 知识点 难度 A Edit Distance B Rotating Gear C Smart Thief D ...

  6. The 2020 ICPC Asia Shenyang Regional Programming Contest I题 Rise of Shadows(数论)

    题目链接The 2020 ICPC Asia Shenyang Regional Programming Contest 题目大意: 一天内有H小时,每小时M分钟,时针分针以恒定速率旋转. 现在若时针 ...

  7. 2018-2019 ACM-ICPC, Asia Nanjing Regional Contest题解

    以下所有AC题解程序来自"仙客传奇"团队. AC题数:6/13 ADGIJK A. Adrien and Austin AC的C++语言程序: #include <iostr ...

  8. The 2019 ICPC Asia Shanghai Regional Contest

    The 2019 ICPC Asia Shanghai Regional Contest 题号 题目 知识点 A Mr. Panda and Dominoes B Prefix Code C Maze ...

  9. 2018 ACM-ICPC Asia Beijing Regional Contest题解

    以下所有AC题解程序来自"仙客传奇"团队. A. Jin Yong's Wukong Ranking List AC的C++语言程序: #include <iostream& ...

最新文章

  1. 2018 ICPC 徐州网络赛 D. Easy Math(思维,反演,杜教筛)
  2. 32位so库兼容64位使用
  3. Git checkout:更新路径与切换分支不兼容
  4. 特权级——保护模式的特权级检查 DPL,RPL,CPL, 一致代码段,非一致代码段
  5. CentOS 7 NAT软路由
  6. django的命令, 配置,以及django使用mysql的流程
  7. Android ViewDragHelper的简单分析(一)
  8. 如何解密网易ncm/qq音乐的qmcflac/酷狗kgm等加密格式转换成MP3
  9. python正则去空格_python使用正则表达式去除中文文本多余空格,保留英文之间空格方法详解...
  10. idou老师教你学istio2:监控能力介绍
  11. 在浏览器输入URL,按下回车之后的流程
  12. 计算机毕业设计ssm吃到撑零售微商城
  13. java520.1314表白_数学学霸表白方程式520.1314
  14. 学校无线网络覆盖方案
  15. 数据分析报告怎么写(三)
  16. YUV图片查看器以及测试文件(YUV420)
  17. 计算机的外存与I/O设备
  18. Android apk瘦身之使用TinyPng压缩图片
  19. take sth. with a grain of salt
  20. oracle11g r2 64 补丁,win10系统下oracle11g R2的64位版本安装教程

热门文章

  1. 实例分割最新最全面综述:从Mask R-CNN到BlendMask
  2. Pytorch 深度学习实战:视频自动打码
  3. 传统图像处理与深度学习又一结合:时空多尺度非局部自相似集成视频超分
  4. 三维重建新应用:精确还原凶杀现场细节!
  5. postgresql之数据库管理
  6. 《大规模Scrum:More with LeSS》访谈
  7. wget使用代理下载
  8. 【分享】博客美化(6)为你的博文自动添加目录
  9. android java.lang.IllegalArgumentException: Comparison method violates its general contract! 问题
  10. 增加ESXI中虚拟机CENTOS系统分区容量