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

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

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


目录

  • A 、(2017 ACM ICPC dalian H)To begin or not to begin
  • B 、(2017 ACM ICPC dalian I) Convex
  • C、(2017 ACM ICPC dalian J)Find Small A
  • D、(2017 ACM ICPC dalian D)A Simple Math Problem
  • E、(2017 ACM ICPC dalian A)Wrestling Match
  • F、(2017 ACM ICPC dalian F)Detachment
  • G、(2017 ACM ICPC dalian C)Game of Taking Stones
  • H、(2017 ACM ICPC dalian E)Aninteresting game
  • I、(2017 ACM ICPC dalian G)Garden of Eden
  • J、(2017 ACM ICPC dalian B)Regular Number
  • K、(2017 ACM ICPC dalian K)Guess the number

好家伙,这套题有点离谱,不敢写了…
一晃以为我是在打校赛…签到题有点多了,体验极差。题目描述很难看懂…好好的一个博弈论还必须用 Java 高精,有意思吗?连该有的special judge 都没有,题面也不说要按字典序小的输出 ?真就不说就必须和样例一样 ?
这套题挺简单的,区分度不太好,有四个队AK… 清华北大被踩到脚下…
(AC:11/11)

  • H 签到(博弈论?)1
  • I 签到(计算几何?)1
  • J 阅读理解(模拟)1.5
  • D 思维,gcd、lcm,解方程(数论)2.5
  • A 二分图,思维(图论)2
  • F 思维,二分,阶乘,乘法逆元(数论)3.5
  • C 威佐夫博弈,Java高精,手写开根函数,牛顿迭代(Java,博弈论)4.5
  • E 思维,树状数组(数据结构)3.5
  • G 树上点分治(图论,数据结构)3.5
  • B shiftandshiftandshiftand 算法(字符串)4
  • K 思维,DP,阅读理解(动态规划)4.5

A 、(2017 ACM ICPC dalian H)To begin or not to begin

HDU -

Problem

A box contains black balls and a single red ball. Alice and Bob draw balls from this box without replacement, alternating after each draws until the red ball is drawn. The game is won by the player who happens to draw the single red ball. Bob is a gentleman and offers Alice the choice of whether she wants to start or not. Alice has a hunch that she might be better off if she starts; after all, she might succeed in the first draw. On the other hand, if her first draw yields a black ball, then Bob’s chances to draw the red ball in his first draw are increased, because then one black ball is already removed from the box. How should Alice decide in order to maximize her probability of winning? Help Alice with decision.

Translation

懒 ~

Solution

签到题 ~

1个红球,kkk 个黑球,若等概率输出 000,先手优输出 111,先手差输出 222,很明显先手不可能比后手差,所以不会输出 222,然后等概率说明是偶数个嘛,所以 kkk 是奇数,+1 变成偶数,等概率输出 000 ,否则 k+1k+1k+1 是奇数,先手优,输出 111。

Code

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
const int N = 3e5 + 7, mod = 1e9 + 7;
typedef long long ll;
typedef int itn;
typedef pair<int, int> PII;
#define step first
#define pos seconditn n, m, t, kcase;
int a[N];
int vis[N];
char s[N], ans[N];int main()
{while(scanf("%d", &n) != EOF) {if(n & 1) puts("0");else puts("1");}return 0;
}

B 、(2017 ACM ICPC dalian I) Convex

HDU -

Problem

We have a special convex that all points have the same distance to origin point.
As you know we can get N segments after linking the origin point and the points on the convex. We can also get N angles between each pair of the neighbor segments.
Now give you the data about the angle, please calculate the area of the convex

Translation

定义特殊多边形是所有端点到原点的距离相等,给定这个多边形的点数,连接 nnn 个端点与原点的连线,给出所有连线之间的夹角,求多边形的面积。

Sample Input

4 1
90 90 90 90
6 1
60 60 60 60 60 60

Sample Output

2.000
2.598

Solution

小学数学题 ~

注意是所有端点到原点的距离相等,不是多边形中点,所以不一定是正多边形,有夹角,所有的线段把整个图形分成了若干个三角形,我们用公式求一下三角形的面积累加即可。

S=12absin⁡cS=\cfrac{1}{2}ab\ \sin cS=21​ab sinc

注意给的是角度,C++里的sin函数是用的弧度制,也就是角度 α×π180°\alpha\times \cfrac{\pi}{180°}α×180°π​

Code

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef int itn;
const int N = 5e5 + 7, M = 1e6 + 7, mod = 1e9 + 7;
const int INF = 1e9 + 7;
const double PI = acos(-1);
int n, m, t, k, q;
double d;
double a;int main()
{while(scanf("%d%lf", &n, &d) != EOF) {double ans = 0;for(int i = 1; i <= n; ++ i)scanf("%lf", &a), ans += d * d * sin(a / 180 * PI) / 2;printf("%.3f\n", ans);}return 0;
}

C、(2017 ACM ICPC dalian J)Find Small A

HDU - 5980

Problem

As is known to all,the ASCII of character ‘a’ is 97. Now,find out how many character ‘a’ in a group of given numbers. Please note that the numbers here are given by 32 bits’ integers in the computer.That means,1digit represents 4 characters(one character is represented by 8 bits’ binary digits).

Translation

字符“ a”的ASCII是97。现在,找出一组给定数字中的字符“ a”。请注意,这里的数字是由计算机中的32位整数给出的。也就是说,1位数字表示4个字符(一个字符由8位的二进制数字表示)。

Solution

看懂题了嘛?

它实际上是说,给定的每一个整数,不是普通的整数,而是32位bit的整数,每个数分成 444 个字符,每个字符占 888 位二进制 bit ,也就是将这个数转换为二进制,每 8 位拆开,看看是不是 979797 的二进制数。统计有多少个 888 位是 979797。当然我们转换为二进制有点麻烦,实际上我们只需要每次对 28=2562^8=25628=256 取模,看余数是否为 979797 就行了。

Code

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
const int N = 3e3 + 7, M = 5e4 + 7, mod = 1e9 + 7;
typedef long long ll;
typedef int itn;
typedef pair<int, int> PII;int n, m, t, k;
int a[N];int main()
{scanf("%d", &n);ll ans = 0;for(int i = 1; i <= n; ++ i) {ll x;scanf("%lld", &x);while(x) {if(x % 256 == 97) {ans ++ ;}x /= 256;}}printf("%lld\n", ans);return 0;
}

D、(2017 ACM ICPC dalian D)A Simple Math Problem

HDU - 5974

Problem

Given two positive integers a and b,find suitable X and Y to meet the conditions:
X+Y=a
Least Common Multiple (X, Y) =b

(1≤a≤2∗104),b(1≤b≤109)(1≤a≤2*10^4),b(1≤b≤10^9)(1≤a≤2∗104),b(1≤b≤109)

Translation

给定正整数 a,ba,ba,b 求正整数 X,YX,YX,Y 满足 X+Y=a,LCM(X,Y)=bX+Y=a,LCM(X,Y)=bX+Y=a,LCM(X,Y)=b。

Solution

开始推式子 ~

我们知道 gcd⁡(X,Y)×lcm(X,Y)=X×Y\gcd(X,Y)\times \text lcm(X,Y)=X\times Ygcd(X,Y)×lcm(X,Y)=X×Y。

我们先设 gcd⁡(X,Y)=g\gcd(X,Y)=ggcd(X,Y)=g

因为我们知道 a,ba,ba,b 想要推出来 X,YX,YX,Y ,而得到解往往是通过解方程得出,所以我们尝试设未知量看看能不能解出来:

假设我们已经知道了 ggg,则很明显根据 gcd⁡\gcdgcd 的性质有:

k1×g=Xk_1\times g=Xk1​×g=X

k2×g=Yk_2\times g=Yk2​×g=Y

并且 k1k_1k1​ 与 k2k_2k2​ 互质。

代入最上面的 lcm\text lcmlcm 经典公式:

g×b=g×k1×g×k2g\times b=g\times k_1\times g\times k_2g×b=g×k1​×g×k2​

b=g×k1×k2b=g\times k_1\times k_2b=g×k1​×k2​

a=X+Y=g×k1+g×k2=g×(k1+k2)a=X+Y=g\times k_1+g\times k_2=g\times (k_1+k_2)a=X+Y=g×k1​+g×k2​=g×(k1​+k2​)

欸,一个二元一次方程组,解一下即可。

但是我们不知道 ggg 是啥,所以考虑找出这个 g=gcd⁡(X,Y)g=\gcd(X,Y)g=gcd(X,Y) 。

我们知道一个性质:

若 k1k1k1 与 k2k2k2 互质,则 k1×k2k1\times k2k1×k2 与 k1+k2k1+k2k1+k2 互质。

也就是可以推出 ag\cfrac{a}{g}ga​ 与 bg\cfrac{b}{g}gb​ 互质。

故 gcd⁡(a,b)=g\gcd(a,b) = ggcd(a,b)=g 。(最大公约数的性质)

故 g=gcd⁡(X,Y)=gcd⁡(a,b)g=\gcd(X,Y)=\gcd(a,b)g=gcd(X,Y)=gcd(a,b),有了 ggg ,我们就得到了两个二元一次方程,联立解方程即可:

k2=bg×k1k_2=\cfrac{b}{g\times k_1}k2​=g×k1​b​

k1+bg×k1=ak_1+\cfrac{b}{g\times k_1}=ak1​+g×k1​b​=a

gk12−ak1+b=0gk_1^2-ak_1+b=0gk12​−ak1​+b=0

Δ=b2−4ac=a2−4bg\Delta = \sqrt{b^2-4ac}=\sqrt{a^2-4bg}Δ=b2−4ac​=a2−4bg​,注意要判断 Δ\DeltaΔ 是否大于等于 000 。

k1=−b±b2−4ac2ak_1=\cfrac{-b± \sqrt{b^2-4ac}}{2a}k1​=2a−b±b2−4ac​​

这里取正负哪一个都行,反正有 special judge。(当我没说,竟然没有 ? 神经病啊 ~ 好的,应该是我的问题,既然都没说有special judge,说明就是没有,也就意味着必须和样例相同,同理,哪怕说了有 special judge 也要尽量与样例相同,不然没地儿哭去 ~ )

最后得 k1=a±a2−4bg2gk_1=\cfrac{a± \sqrt{a^2-4bg}}{2g}k1​=2ga±a2−4bg​​

然后判断无解的情况,首先就是方程无解,也就是 Δ<0\Delta<0Δ<0。

然后就是不符合题意,也就是我们得到的不是整数,很好判断,因为不是整数取整的时候有误差,所以只需要判断一下下式是否成立即可:

b=g×k1×k2b=g\times k_1\times k_2b=g×k1​×k2​

a=g×(k1+k2)a= g\times (k_1+k_2)a=g×(k1​+k2​)

Code

#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;
ll a, b, k1, k2;int main()
{while(scanf("%lld%lld", &a, &b) != EOF) {ll g = __gcd(a, b);ll delta = a * a - 4 * b * g;if(delta < 0) {puts("No Solution");continue;}k1 = (a - (ll)sqrt(delta)) / (2 * g);k2 = a / g - k1;ll X = k1 * g;ll Y = k2 * g;if(k1 * k2 * g != b || g * (k1 + k2) != a) puts("No Solution");else printf("%lld %lld\n", X, Y);}return 0;
}

E、(2017 ACM ICPC dalian A)Wrestling Match

HDU - 5971

Problem

Problem Description
Nowadays, at least one wrestling match is held every year in our country. There are a lot of people in the game is "good player”, the rest is "bad player”. Now, Xiao Ming is referee of the wrestling match and he has a list of the matches in his hand. At the same time, he knows some people are good players,some are bad players. He believes that every game is a battle between the good and the bad player. Now he wants to know whether all the people can be divided into “good player” and “bad player”.

Translation

一场摔跤比赛,有很多人是“好玩家”,其余的是“坏玩家”。现在,小明是摔跤比赛的裁判,并且他手里拿着比赛清单。同时,他知道有些人是好球员,有些人是坏球员。他认为,每场比赛都是好与坏玩家之间的较量。现在他想知道所有人是否都可以分为“好玩家”和“坏玩家”。

输入包含多组数据。对于每组数据,第一行中有四个数字:N(1≤N≤1000),M(1≤M≤10000),X,Y(X +Y≤N) ,以显示玩家数量(编号1至N),比赛数量,已知的“好玩家”数量和已知的“坏玩家”数量。在接下来的M行中,每行都有两个数字a,b (a≠b),表示在a和b之间有一个游戏。下一行有X个不同的数字。每个数字都称为“好玩家”数字。最后一行包含Y个不同的数字。每个数字代表一个已知的“坏人”号码。数据保证不会有好人,也不会是坏人。

如果所有人都可以分为“好玩家”和“坏玩家”,则输出“是”,否则输出“否”。

Sample Input

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

Sample Output

NO
YES

Word

Solution

题目要求的是所有人是否都可以分为“好玩家”和“坏玩家”。给出了一些人PK的名单,并且好玩家必须和坏玩家打,分成了两部分,每部分内部不能打架,也就是不能有连线,很明显就是一个二分图,我们只需要直接用染色法判断是否为二分图即可。并且题目会告诉我们一部分人的情况,所以我们先根据这个数据,给定的颜色先染色,然后把所有对战关系这 mmm 条边里没有被染到的随机染色(直接从1开始染色1就行了)。最后若有孤立点,没有被染色,说明有人被孤立了,不知道它是好是坏,输出 NO

Code

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
const int N = 3e3 + 7, M = 5e4 + 7, mod = 1e9 + 7;
typedef long long ll;
typedef int itn;
typedef pair<int, int> PII;int n, m, head[N], ver[M], nex[M], edge[M], from[N], tot;
int k, t, X, Y;
int vis[N];
int col[N];void init()
{memset(head, -1, sizeof head);memset(col, 0, sizeof col);tot = 0;
}void add(int x, int y)
{ver[tot] = y;from[tot] = x;nex[tot] = head[x];head[x] = tot ++ ;
}bool dfs(int x, int color)
{col[x] = color;for(int i = head[x]; ~i; i = nex[i]) {int y = ver[i];if(col[y]) {if(col[y] == color) return false;}else if(!dfs(y, -color)) return false;}return true;
}void solve()
{init();for(int i = 1; i <= m; ++ i) {int x, y;scanf("%d%d", &x, &y);add(x, y);add(y, x);}bool flag = true;for(int i = 1; i <= X; ++ i) {int x;scanf("%d", &x);if(flag) {if(col[x] == -1) {flag = false;}flag = dfs(x, 1);}}for(int i = 1; i <= Y; ++ i) {int y;scanf("%d", &y);if(flag) {if(col[y] == 1) {flag = false;}flag = dfs(y, -1);}}if(flag == false) {puts("NO");return ;}for(int i = 0; i < tot; ++ i) {if(col[ver[i]] == 0 && col[from[i]] == 0) {flag = dfs(ver[i], 1);}}if(flag == false) {puts("NO");return ;}for(int i = 1; i <= n; ++ i) {if(col[i] == 0) {puts("NO");return ;}}puts("YES");return ;
}int main()
{while(scanf("%d%d%d%d", &n, &m, &X, &Y) != EOF) {solve();}
}

F、(2017 ACM ICPC dalian F)Detachment

HDU - 5976

Problem

In a highly developed alien society, the habitats are almost infinite dimensional space.
In the history of this planet,there is an old puzzle.
You have a line segment with x units’ length representing one dimension.The line segment can be split into a number of small line segments: a1,a2, … (x= a1+a2+…) assigned to different dimensions. And then, the multidimensional space has been established. Now there are two requirements for this space:
1.Two different small line segments cannot be equal ( ai≠aj when i≠j).
2.Make this multidimensional space size s as large as possible (s= a1∗a2*…).Note that it allows to keep one dimension.That’s to say, the number of ai can be only one.
Now can you solve this question and find the maximum size of the space?(For the final number is too large,your answer will be modulo 10^9+7)

Translation

给定 nnn ,将 nnn 拆成a1+a2+a3+…+axa_1+a_2+a_3+…+a_xa1​+a2​+a3​+…+ax​ 的形式(且对于任意的 i≠ji≠ji​=j,保证 ai≠aja_i≠a_jai​​=aj​),让a1×a2×a3×…×axa_1\times a_2\times a_3\times …\times a_xa1​×a2​×a3​×…×ax​的值最大,求这个最大值。

Solution

手玩样例,发现如果允许 ai=aj&&i≠ja_i=a_j\ \&\&\ i≠jai​=aj​ && i​=j ,则将所有的数拆成 222 和 333 是最优的解法。然后没什么用,因为不能存在两个数相等hhh。

然后我们知道对于一个数 nnn ,n!n!n! 是最大的,所以我们按照这个思路,将给定的数 nnn 拆成 2×3×⋯×x2\times 3\times \cdots \times x2×3×⋯×x,使得 2+3+⋯+x=n2+3+\cdots+x=n2+3+⋯+x=n 即可。
这是一个等差数列,我们可以直接使用等差数列求和公式,这里顺便复习一下等差数列和等比数列的求和公式:

等差数列:


通项公式:

若一个等差数列的首项为 a1a_1a1​ ,末项为 ana_nan​ 那么该等差数列和表达式为:

前 nnn 项和公式:

等比数列:

通项公式

推广式

求和公式



所以我们是用公式得到 2+3+⋯+x=(x+2)(x−1)2=x2+x−22=n2+3+\cdots+x=\cfrac{(x+2)(x-1)}{2}=\cfrac{x^2+x-2}{2}=n2+3+⋯+x=2(x+2)(x−1)​=2x2+x−2​=n

我们可以直接二分得到这个 xxx (当然直接解方程也一样)。

然后开始分析:

我们知道对于任意给定的 nnn 不一定一定能拆成 2+3+⋯+x2+3+\cdots+x2+3+⋯+x 的形式,

我们可以计算一下拆完之后剩下多少,设为 moremoremore ,我们来分析一下剩下的这个数怎么分配会使得答案最优。很明显将他们平均分配肯定会比分给一个数会更优,并且优先分配给小的会更优,因为一个数 +1+1+1 ,相当于总权值加上剩下的数,也就是多了剩下的数的乘积的一倍,而把这个数分配给后面的,也就是大的数,加的是前面小一点的数的一倍,分配给前面的数,加的是后面大一点的数的一倍,所以如果没有限制的话,直接全部加给 222 是最优的,但是有限制,因为每一个数最后不能一样,如果全部加到前面,相当于前面的数右移,会重复,所以我们发现,当 moremoremore 等于区间长度+1也就是找到的那个 xxx 的时候,我们就可以将多出来的数平均地加到每一个数的身上,也就是整体右移一位,这样答案最优。

当不等于的时候,我们可以证明 more≤xmore\le xmore≤x,因为我们二分找到的方程的解一定是右边的正数。

所以当不相等的时候,more≤xmore\le xmore≤x ,因为不能重复,所以我们只能先把右半部分整体的右移,也就是整体 +1。

最后求答案即可。因为要求的是阶乘,数据比较大,我们可以先预处理一下阶乘和阶乘的逆元,因为我们是预处理的,所以右移的时候不能暴力右移,我们需要将一段右移 111 也就是可以直接用移动后的右端 x+1x+1x+1 的位置的阶乘除去左半部分+1的阶乘,得到实际移动后的右半部分的阶乘,然后再乘上左半部分的阶乘也就得到了去掉中间空了的以后的答案。除可以直接乘上逆元,消除精度误差。

Code

#include <cstring>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>using namespace std;
typedef long long ll;
const int N = 5e5 + 7, mod = 1e9 + 7;ll n, m, x, t;
ll F[N], Finv[N], inv[N];bool check(ll n)
{return (n * n + n - 2) / 2 <= x;
}void init(int n)
{inv[1] = 1;for(int i = 2; i <= n; ++ i) {inv[i] = (mod - mod / i) * 1ll * inv[mod % i] % mod;}F[1] = Finv[1] = 1;for(int i = 2; i <= n; ++ i) {F[i] = F[i - 1] * 1ll * i % mod;Finv[i] = Finv[i - 1] * 1ll * inv[i] % mod;}
}void solve()
{scanf("%lld", &x);if(x < 5) {printf("%lld\n", x);return ;}ll l = 2, r = 45000, pos;while(l < r) {ll mid = (l + r) >> 1;if(check(mid)) l = mid + 1, pos = mid;else r = mid;}ll ans;ll more = x - (pos * pos + pos - 2) / 2;if(more == pos)ans = F[pos + 2] * inv[2] % mod * inv[pos + 1] % mod;else ans = F[pos + 1] * Finv[pos - more + 1] % mod * F[pos - more] % mod;//只能从右往左加,因为左边在右边没有动的情况下加不了,加了就重复了printf("%lld\n", ans);
}int main()
{scanf("%d", &t);init(45000);while(t -- ) {solve();}
}

G、(2017 ACM ICPC dalian C)Game of Taking Stones

HDU - 5973

Problem

Two people face two piles of stones and make a game. They take turns to take stones. As game rules, there are two different methods of taking stones: One scheme is that you can take any number of stones in any one pile while the alternative is to take the same amount of stones at the same time in two piles. In the end, the first person taking all the stones is winner.Now,giving the initial number of two stones, can you win this game if you are the first to take stones and both sides have taken the best strategy?

a,b≤10100a,b\le10^{100}a,b≤10100

Translation

给你两个石堆的石头数量,两个人轮流拿,两人轮流从任意一堆取至少一个或者从两堆取同样多的物品。问你先手获胜还是后手胜。

Solution

经典威佐夫博弈 ,需要搞高精…

1010010^{100}10100,普通的C++高精会炸,所以直接用Java就行了(而且Java比C++高精好写多了 ~ )

我们直接用 Java 二分求出 5\sqrt{5}5​,设 b>ab>ab>a 计算 (b−a)×(5+1)2\cfrac{(b-a)\times (\sqrt{5}+1)}{2}2(b−a)×(5​+1)​ 即可。

讲一下Java吧。

ctrl+shift+o--- 加包 ctrl +shift+f--- 调整格式

三种取整函数:

舍掉小数取整:Math.floor(3.5)=3
四舍五入取整:Math.rint(3.5)=4
进位取整 :Math.ceil(3.1)=4

BigDecimal.setScale (精度:小数点后多少位,舍入方式)

setScale(0, BigDecimal.ROUND_DOWN); 设置精度

各种 roundingMode

ROUND_UP:非0时,舍弃小数后(整数部分)加1,比如12.49结果为13,-12.49结果为 -13
ROUND_DOWN:直接舍弃小数
ROUND_CEILING:如果 BigDecimal 是正的,则做 ROUND_UP 操作;如果为负,则做 ROUND_DOWN 操作 (一句话:取附近较大的整数)
ROUND_FLOOR: 如果 BigDecimal 是正的,则做 ROUND_DOWN 操作;如果为负,则做 ROUND_UP 操作(一句话:取附近较小的整数)
ROUND_HALF_UP:四舍五入(取更近的整数)
ROUND_HALF_DOWN:跟 ROUND_HALF_UP 差别仅在于0.5时会向下取整
ROUND_HALF_EVEN:取最近的偶数
ROUND_UNNECESSARY:不需要取整,如果存在小数位,就抛出 ArithmeticException 异常

Code

import java.math.*;
import java.util.*;public class Main {public static void main(String[] args) {BigDecimal one = BigDecimal.valueOf(1);BigDecimal two = BigDecimal.valueOf(2), five = BigDecimal.valueOf(5);BigDecimal t = one.add(sqrt(five, 500)).divide(two);Scanner sc = new Scanner(System.in);while (sc.hasNext()) {BigDecimal a, b, tmp = null;a = sc.nextBigDecimal();b = sc.nextBigDecimal();if (a.compareTo(b) > 0) {tmp = a;a = b;b = tmp;}if (b.subtract(a).multiply(t).setScale(0, BigDecimal.ROUND_DOWN).equals(a)) {System.out.println(0);} elseSystem.out.println(1);}sc.close();}private static BigDecimal sqrt(BigDecimal x, int n) {BigDecimal l = BigDecimal.ZERO, r = x, mid;BigDecimal two = BigDecimal.valueOf(2);for (int i = 0; i <= n; i++) {mid = l.add(r).divide(two);if (mid.pow(2).compareTo(x) <= 0)l = mid;elser = mid;}return l;}
}

H、(2017 ACM ICPC dalian E)Aninteresting game

HDU 5975

Problem

Translation

Solution

Code

待更…

I、(2017 ACM ICPC dalian G)Garden of Eden

要用到树上点分治,我不会,丢给队友写了,待更… 队友写的题解 @ld

Translation

求树上覆盖 1−k1-k1−k 种颜色的路径总数

Solution

经典树上点对计数问题 ,点分治即可 时间复杂度上限 O(n×logn×1024)O(n\times logn\times 1024)O(n×logn×1024)

Code

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e4+5;
vector<int>v[maxn];
vector<int>state;
int a[maxn];
bool vis[maxn];
int size[maxn],maxson[maxn];
int root,maxsize,mx;
int cnt[1024];
int val;
long long ans;
void getroot(int now,int pre)
{maxson[now] = 0;size[now] = 1;for(auto x:v[now]){if(x==pre||vis[x])continue;getroot(x,now);size[now] += size[x];maxson[now] = max(maxson[now],size[x]);}maxson[now] = max(maxson[now],mx-size[now]);if(maxson[now] < maxsize){maxsize = maxson[now];root = now;}
}
void getsta(int now,int pre,int sta)
{state.push_back(sta);for(auto x:v[now]){if(x==pre||vis[x])continue;getsta(x,now,sta|(1<<a[x]));}
}long long Cal(int now,int st)
{memset(cnt,0,sizeof(cnt));state.clear();getsta(now,-1,(1<<a[now])|st);long long ans = 0;int n = state.size();for(auto x:state)cnt[x]++;for(int i = 0;i < n;++i){int s = state[i];cnt[s]--;ans += cnt[val-1];for(int j = s;j;j = s&(j-1)){ans += cnt[(val-1)^j];}cnt[s]++;}return ans;
}
void Divide(int now)
{ans += Cal(now,0);vis[now]=1;for(auto x:v[now]){if(vis[x])continue;ans -= Cal(x,1<<a[now]);maxsize = 1e9;mx = size[x];getroot(x,now);Divide(root);}
}int main()
{int n,k;while(~scanf("%d%d",&n,&k)){ans = 0;for(int i = 1;i <= n;++i)scanf("%d",&a[i]),v[i].clear(),a[i]--;for(int i = 1,a,b;i < n;++i){scanf("%d%d",&a,&b);v[a].push_back(b);v[b].push_back(a);}if(k==1){printf("%lld\n",1ll*n*n);continue;}val = 1<<k;maxsize = 1e9;mx = n;memset(vis,0,sizeof(vis));memset(size,0,sizeof(size));memset(maxson,0,sizeof(maxson));getroot(1,-1);Divide(root);printf("%lld\n",ans);}return 0;
}

J、(2017 ACM ICPC dalian B)Regular Number

HDU - 5972

shiftandshiftandshiftand,字符串匹配 + bitset 队友写的题解 @ld

Problem

Using regular expression to define a numeric string is a very common thing. Generally, use the shape as follows:
(0|9|7) (5|6) (2) (4|5)
Above regular expression matches 4 digits:The first is one of 0,9 and 7. The second is one of 5 and 6. The third is 2. And the fourth is one of 4 and 5. The above regular expression can be successfully matched to 0525, but it cannot be matched to 9634.
Now,giving you a regular expression like the above formula,and a long string of numbers,please find out all the substrings of this long string that can be matched to the regular expression.

Translation

给定一个模式串 TTT,模式串的每一位可以匹配多个数字,求原串 SSS 所有匹配上的字符串。

Solution

shiftandshiftandshiftand 算法模板题,用一个 bitset D 的第 iii 位为 0/10/10/1 来表示模式串的前缀 S1−iS_{1-i}S1−i​ 是否为当前匹配串的一个后缀。

从前往后枚举原串的每一位,设当前枚举到第 xxx 位,考虑如何更新 DDD。

显然当前 DDD 保留着匹配到 x−1x-1x−1 的信息,那么满足一个模式串的前缀 iii 是当前原串的后缀当且仅当 D[i-1]=1 && T[i]=S[i]

更新后如果第n位为1则代表以x为结尾的子串匹配成功。

时间复杂度:O(n×∣S∣64)O(\cfrac{n\times |S|}{64})O(64n×∣S∣​)

Code

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1001;
bitset<maxn>bit[10],now,tmp;
char s[5000005];
int main()
{int n;scanf("%d",&n);for(int i = 1,a,b;i <= n;++i){scanf("%d",&a);for(int j = 1;j <= a;++j){scanf("%d",&b);bit[b].set(i);}}scanf("%s",s+1);int m = strlen(s+1);for(int i = 1;i <= m;++i){now = now<<1;now.set(1);now = now&(bit[s[i]-'0']);if(now[n]==1){char tmp = s[i+1];s[i+1] = '\0';printf("%s\n",s+i+1-n);s[i+1] = tmp;}}return 0;
}

K、(2017 ACM ICPC dalian K)Guess the number

HDU - 5981

丢给队友写了,待更… 队友写的题解 @wk

Problem

AOA just met a problem when he attended an interview, as shown below:
A and B two people play guessing games. A thinks of a number x between a and b randomly in his mind, and he lets B to guess this number. A will say too small if B’s guess is less than x and A will say yes if B’s guess is just x.Once B’sguess is bigger than x,A won’t speak any more.After that,A just nods his head if B’s guess is just x,otherwise shakes his head.The problem is that how many kinds of best guess strategies to make the least number of guesses in the worst situation?

Translation

A在 [l,r][l,r][l,r] 中随机选择一个数 xxx , B来猜这个数,若猜的数比 xxx 小,则A告诉B小了,若等于 xxx ,游戏结束,若大于 xxx ,则之后猜的数A只告诉B猜的对不对。

问最坏情况下最少需要猜多少次,和猜测次数满足小于上述次数的猜中的方案数。

Solution

(这不就是高楼扔俩鸡蛋问题嘛)

首先题的答案与 lll ,rrr 的大小并无关系,仅与 lll ~ rrr 的长度,即 r−l+1r-l+1r−l+1 有关。

反向考虑,若猜k次,则最多可以猜多少个数。

假设l = 1, r = len, 考虑第一次猜测,若第一次猜测大于x则接下来的数只能从第一次猜测的数向下逐一猜测,所以第一次猜测的数最大为k, 此时我们已经排除 [1,k][1,k][1,k] ,还有 k−1k-1k−1 次可以使用,同理,第二次猜测的数应为 k+k−1k + k-1k+k−1 ,第三次猜测为 k+k−1+k−2k + k-1 + k-2k+k−1+k−2 ,直到 k=0k=0k=0 。故最多可以猜测 rrr 为 ∑i=1k=k∗(k+1)/2\sum\limits_{i=1}^{k} = k * (k + 1) / 2i=1∑k​=k∗(k+1)/2

根据上述方法考虑状态转移,当我们选择第一个数后,则将其划分为了两部分,转化成了选择 k−1k-1k−1 次的子问题,答案即是所有符合条件的选择 k−1k-1k−1 次所有情况的和,考虑何时符合条件,由于第一次选择的数最大为 kkk ,所以,子问题长度最小情况是第一个数选择在 kkk ,长度为len-k-1,最大情况则是选择 k−1k-1k−1 次时的最长长度,即代码中的 mp[i] ,只需在计算方案数时保存前缀和即可 O(1)O(1)O(1) 得到所有子问题方案和。

故状态转移方程为

k=最坏情况下最少猜测次数dp[len]=sum[mp[k−1]]−sum[len−k−1]k = 最坏情况下最少猜测次数 \\ dp[len] = sum[mp[k-1]] - sum[len - k - 1] k=最坏情况下最少猜测次数dp[len]=sum[mp[k−1]]−sum[len−k−1]

Code

#include <bits/stdc++.h>
#define reg register
#define ios ios::sync_with_stdio(false)
using namespace std;typedef long long ll;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const double eps = 1e-10;
const int maxn = 5e6 + 10;
const double pi = acos(-1.0);
const ll mod = 100000073;int res[maxn];
int mp[maxn];
int dp[maxn];
int sum[maxn];int main()
{ios;int now = 1;mp[1] = 1;for(int i = 1;i < maxn;++i){if(i <= now * (now + 1) / 2) res[i] = now;else{mp[now] = i - 1;now++;res[i] = now;}}dp[1] = 1,dp[2] = 2;sum[1] = 1,sum[2] = 3;for(int i = 3;i < maxn;++i){dp[i] = (sum[mp[res[i] - 1]] - sum[i - res[i] - 1] + mod) % mod;sum[i] = (sum[i-1] + dp[i]) % mod;}int l,r;while(cin>>l>>r){int n = r - l + 1;printf("%d %d\n",res[n],dp[n]);}return 0;
}

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

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

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

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

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

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

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

  4. The 2019 ICPC Asia Shanghai Regional Contest

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

  5. 2018 ICPC Asia Jakarta Regional Contest

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

  6. 2016 ACM ICPC Asia Region - Tehran

    2016 ACM ICPC Asia Region - Tehran A - Tax 题目描述:算税. solution 模拟. B - Key Maker 题目描述:给出\(n\)个序列,给定一个序 ...

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

    以下所有AC题解程序来自"仙客传奇"团队. A. Xu Xiake in Henan Province AC的C++语言程序: #include<iostream> # ...

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

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

  9. 2019-2020 ICPC Asia Xuzhou Regional Contest【徐州现场赛】

    题目: 209-2020 ICPC Asia Xuzhou Regional Onsite Contest E. Multiply 题意: 找到最大的 i 使得 z*x^i 是 y! 的因子 分析: ...

最新文章

  1. python获取数据类型_python数据类型详解
  2. 面向 Java 开发人员的 Ajax: 构建动态的 Java 应用程序
  3. SVN 文件的解锁方法
  4. 九度互动社区IT名企招聘上机考试热身赛
  5. sqoop增量导出mysql_sqoop定时增量导入导出
  6. dcs服务器性能指标,第6章DCS的性能指标.PDF
  7. C语言实例解析精粹学习笔记——36(模拟社会关系)
  8. python 赋值、浅拷贝、深拷贝学习实践
  9. python界面打开为什么是黑的_Pycharm设置界面全黑的方法
  10. 京东商城,超大型电商系统架构设计原则与实践!8页ppt详解
  11. 多项式函数的极值点与拐点判别及个数公式
  12. QT 信号与槽不在同一个线程 connect
  13. php自我介绍50字,【自我介绍50字左右】自我介绍50字
  14. 给十二星座的12封信,句句说中你们的心理要害!
  15. iOS-关于微信支付
  16. 如何在富文本中插入表情,word文档,及数学公式?
  17. Linux 搭建NodeBB社区,搭建CAS登录认证平台,实现Nodebb接入企业CAS认证(一)
  18. 斯隆论社会责任:德鲁克日志之四月二十五日
  19. 一篇高中生都能看懂的MySQL入门博客(长文)
  20. 6本豆瓣高分书,国内外的技术大牛都在看!

热门文章

  1. 卧槽!阿里《算法进阶指南》火了,完整版 开放下载!
  2. 官方 | TensorFlow 2.0分布式训练教程
  3. 自定义Android注解Part3:绑定
  4. python 易错总结
  5. 【安全牛学习笔记】字典、在线密码破解-hydra
  6. Zookeeper工作原理
  7. RequireJS示例
  8. [WebService]之代码优先方法与契约优先方法
  9. SharePoint 2013 调用WCF服务简单示例
  10. 基本lnmp平台的搭建(源码编译)