您的位置:首页 > 大数据 > 人工智能

Hdu 2015 Multi-University Training Contest1

2015-07-22 14:13 477 查看

1001

题面

Problem Description

OO has got a array A of size n ,defined a function f(l,r) represent the number of i (l<=i<=r) , that there’s no j(l<=j<=r, j != i) satisfy ai mod aj=0,now OO want to know:

∑i=1n∑j=inf(i,j)mod(109+7)\sum_{i = 1}^n \sum_{j = i}^nf(i, j) mod (10^9 + 7)

Input

There are multiple test cases. Please process till EOF.

In each test case:

First line: an integer n(n<=10^5) indicating the size of array

Second line:contain n numbers ai( 0 < ai<= 10000)

Output

For each tests: ouput a line contain a number ans.

Sample Input

5

1 2 3 4 5

Sample Output

23

题意

有点难懂- -

有一个n(10^5)的一维数组。

函数f(l,r)的返回值是:

所有属于[l , r]区间的i,枚举其中属于区间[l, r] 且 != i

的 j,使得其中不存在a[i] % a[j] == 0的 i 的个数。

然后求:

∑i=1n∑j=inf(i,j)mod(109+7)\sum_{i = 1}^n \sum_{j = i}^nf(i, j) mod (10^9 + 7)

的值是多少。

解析

n方的算法是过不了的,所以下午连tle都没交。

所以先枚举n,然后再枚举sqrt(a[i])。

首先先理解一个贡献度的问题:

假设有如下样例:

数字 3 2 3 4 3 3 3 2,

下标 1 2 3 4 5 6 7 8,

此时求数字4对以上问题的贡献度。

求法是直接找到距离 4 最近的左右两边的他的因子,假设此时4所在位置为下标i,则左边离他最近的因子是2,下标设为l,(2).

右边最近的因子也是2,下标设为r,(8)。

此时他的贡献度是:(i - l) * (r - i)。仔细想想就是i左边取多少个数与右边取多少个数的问题。

所以,扩展到这题,只需要找出下标为i的数的左边和右边离它最近的它的因子,并用l[i], r[i]保存下来,最后直接累加(i - l[i]) * (r[i] - i)即可。

这题一直wa的原因是在枚举a[i]的因子的时候漏掉了一半的因子,欲哭无泪啊。

见以下注释。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
const int mod = 1e9 + 7;

int a[maxn];
int l[maxn];
int r[maxn];
int pos[maxn];
vector<int> num[maxn];
//vector<int> lis[maxn];
//void init()
//{
//    for (int i = 1; i < maxn; i++)
//    {
//        for (int j = 1; j * j <= i; j++)
//        {
//            if (i % j == 0)
//            {
//                lis[i].push_back(j);
//                lis[i].push_back(i / j);
//            }
//        }
//    }
//}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int n;
//    init();
while (~scanf("%d", &n))
{
for (int i = 0; i < maxn; i++)
{
num[i].clear();
}
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
num[a[i]].push_back(i);
}
//        for (int i = 1; i <= n; i++)
//        {
//            l[i] = 0;
//            r[i] = n + 1;
//            int sz = lis[a[i]].size();
//            int t = sqrt(a[i]);
///            for (int j = 0; j < sz; j++) //wa的原因是因子我只从1枚举到sqrt(a[i])。
//            {
//                int x = lis[a[i]][j];
//                if (a[i] % x == 0 && num[x].size())
//                {
//                    for (int k = 0; k < num[x].size(); k++)
//                    {
//                        int nowPos = num[x][k];
//                        if (nowPos < i)
//                        {
//                            if (l[i] < nowPos)
//                            {
//                                l[i] = nowPos;
//                            }
//                        }
//                        else if (i < nowPos)
//                        {
//                            if (nowPos < r[i])
//                            {
//                                r[i] = nowPos;
//                            }
//                        }
//                    }
//                }
//            }
//        }
for (int i = 1; i <= n; i++)
{
l[i] = 0;
r[i] = n + 1;
int t = sqrt(a[i]);
for (int j = 1; j <= t; j++)
{
if (a[i] % j == 0)
{
for (int k = 0; k < num[j].size(); k++)
{
int nowPos = num[j][k];
if (nowPos < i)
{
if (l[i] < nowPos)
{
l[i] = nowPos;
}
}
else if (i < nowPos)
{
if (nowPos < r[i])
{
r[i] = nowPos;
}
}
}
///漏了下面这个情况,没有枚举出所有a[i]的因子故wa
/////////////////////////////////
int g = a[i] / j;
for (int k = 0; k < num[g].size(); k++)
{
int nowPos = num[g][k];
if (nowPos < i)
{
if (l[i] < nowPos)
{
l[i] = nowPos;
}
}
else if (i < nowPos)
{
if (nowPos < r[i])
{
r[i] = nowPos;
}
}
}
////////////////////////////////
}
}
}
LL ans = 0;
for (int i = 1; i <= n; i++)
{
//            cout << l[i] << " " << r[i] << endl;
ans = (ans + (LL)(i - l[i]) * (r[i] - i)) % mod;
}
printf("%I64d\n", ans);
}
return 0;
}


1002

题面

Problem Description

Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n in this company, and every staff has a ability. Now, Tom is going to assign a special task to some staffs who were in the same group. In a group, the difference of the ability of any two staff is less than k, and their numbers are continuous. Tom want to know the number of groups like this.

Input

In the first line a number T indicates the number of test cases. Then for each case the first line contain 2 numbers n, k (1<=n<=100000, 0 < k<=10^9),indicate the company has n persons, k means the maximum difference between abilities of staff in a group is less than k. The second line contains n integers:a[1],a[2],…,a[ n ] (0<=a[i]<=10^9),indicate the i-th staff’s ability.

Output

For each test,output the number of groups.

Sample Input

2

4 2

3 1 2 4

10 5

0 3 4 5 2 1 6 7 8 9

Sample Output

5

28

Hint

First Sample, the satisfied groups include:[1,1]、[2,2]、[3,3]、[4,4] 、[2,3]

题意

有n(10^5)个员工,他们的编号分别为1.2.3……n,每个员工都有一个工作能力值ai。

现在给一个差异度k,并分配这些员工分组做工作。

要求是编号连续的员工可以同在一个组里,并且同一个组里面的员工的工作能力的差异值要< k。

问有多少种分组方法。

解析

首先,n的值到达了10^5,枚举起点和终点是要超时的。

然后先是想怎么分配这些组,如果找出了一段连续的x个人可以在一个组里面,他们的分组方法是:

LL fun(LL x)
{
LL res = x * (x - 1) / 2;
return res;
}


然后下午卡就卡在了这个类似尺取的地方,每次x蠕动到的下个位置是改变了当前最大值,或者最小值中小的一个id的地方。

这样就可以减小复杂度了。

把所有的区间搞定,然后按照起点排序。

最后计算交叉的点,如果有交叉,说明这些地方的值重复了,减掉就行了。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int n, k;
int a[maxn];
LL fun(LL x) { LL res = x * (x - 1) / 2; return res; }

struct Node
{
int fr, to;
} e[maxn];

bool cmp(Node a, Node b)
{
return a.fr < b.fr;
}

int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase;
scanf("%d", &ncase);
while (ncase--)
{
scanf("%d%d", &n, &k);
LL ans = n;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}

int cnt = 0;
for (int x = 1; x <= n; x++)
{
int minn = a[x];
int maxx = a[x];
int idmax = x;
int idmin = x;
for (int y = x + 1; y <= n; y++)
{
if (maxx < a[y])
{
maxx = a[y];
idmax = y;
}
if (a[y] < minn)
{
minn = a[y];
idmin = y;
}
if (maxx - minn >= k)
{
e[cnt].fr = x;
e[cnt++].to = y - 1;
x = idmin < idmax ? idmin: idmax;
break;
}
if (y == n)
{
e[cnt].fr = x;
e[cnt++].to = y;
x = n;
break;
}
}
}

sort(e, e + cnt, cmp);
ans += fun(e[0].to - e[0].fr + 1);
for (int i = 1; i < cnt; i++)
{
// cout << e[i].fr << " " << e[i].to << endl;
if (e[i].fr < e[i - 1].to)
{
ans -= fun(e[i - 1].to - e[i].fr + 1);
}
ans += fun(e[i].to - e[i].fr + 1);
}

printf("%I64d\n", ans);

}
return 0;
}


1007

题面

Problem Description

Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu’s at the entrance of the tomb while Dumb Zhang’s at the end of it. The tomb is made up of many chambers, the total number is N. And there are M channels connecting the chambers. Innocent Wu wants to catch up Dumb Zhang to find out the answers of some questions, however, it’s Dumb Zhang’s intention to keep Innocent Wu in the dark, to do which he has to stop Innocent Wu from getting him. Only via the original shortest ways from the entrance to the end of the tomb costs the minimum time, and that’s the only chance Innocent Wu can catch Dumb Zhang.

Unfortunately, Dumb Zhang masters the art of becoming invisible(奇门遁甲) and tricks devices of this tomb, he can cut off the connections between chambers by using them. Dumb Zhang wanders how many channels at least he has to cut to stop Innocent Wu. And Innocent Wu wants to know after how many channels at most Dumb Zhang cut off Innocent Wu still has the chance to catch Dumb Zhang.

Input

There are multiple test cases. Please process till EOF.

For each case,the first line must includes two integers, N(<=2000), M(<=60000). N is the total number of the chambers, M is the total number of the channels.

In the following M lines, every line must includes three numbers, and use ai、bi、li as channel i connecting chamber ai and bi(1<=ai,bi<=n), it costs li(0 < li<=100) minute to pass channel i.

The entrance of the tomb is at the chamber one, the end of tomb is at the chamber N.

Output

Output two numbers to stand for the answers of Dumb Zhang and Innocent Wu’s questions.

Sample Input

8 9

1 2 2

2 3 2

2 4 1

3 5 3

4 5 4

5 8 1

1 6 2

6 7 5

7 8 1

Sample Output

2 6

题意

给一张n(2000)个节点的无向图,其中共有m(60000)条边,然后起点在1点,终点在n点。

现在,每次从起点到终点走的都是最短路。

然后询问,在走最短路的前提下,最小删掉几条边,从起点到达不了终点;最多删掉几条边,还能够到达终点。

解析

注意题目是在走最短路的前提条件下来求解这些问题的。

所以先用spfa将多条最短路标记出来:

其中,到达终点、是最短路 并且 走过变数最少的step为minn,总边数减掉minn就为第二问的答案。

然后将spfa标记出来的最短路建一个新的网络流的图,流量为1,注意在建图的时候不用正反建图,因为遍历边的时候自然就已经正反建图了。

我的spfa的模板建图有问题- - 然后网络流建图建了反边 所以一直wa。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 2e3 + 10;
const int inf = 0x3f3f3f3f;

vector<pair<int, int> > g[maxn];
int n, m;

int dis[maxn];
bool inQue[maxn];
int step[maxn];

void spfa(int s, int t)
{
memset(dis, inf, sizeof(dis));
memset(step, inf, sizeof(step));
memset(inQue, false, sizeof(inQue));
queue<int> q;
dis[s] = 0;
step[s] = 0;
inQue[s] = true;
q.push(s);

while (!q.empty())
{
int u = q.front();
q.pop();
inQue[u] = false;
int sz = g[u].size();
for (int i = 0; i < sz; i++)
{
int v = g[u][i].first;
if (dis[v] == dis[u] + g[u][i].second)
{
step[v] = min(step[v], step[u] + 1);
}
if (dis[u] + g[u][i].second < dis[v])
{
dis[v] = dis[u] + g[u][i].second;
step[v] = step[u] + 1;
if (!inQue[v])
{
q.push(v);
inQue[v] = true;
}
}
}
}
return;
}

int cap[maxn][maxn];
int flow[maxn][maxn];
int lev[maxn];
int a[maxn];

void buildGraph()
{
memset(cap, 0, sizeof(cap));
for (int u = 1; u <= n; u++)
{
int sz = g[u].size();
for (int j = 0; j < sz; j++)
{
int v = g[u][j].first;
if (dis[v] == dis[u] + g[u][j].second)
{
///因为遍历了所有的边,所以不必要反向建图。
///cap[v][u] += 1;
cap[u][v] += 1;
}
}
}
}

//bfs找层次网络,一次寻找多条增广路径
//st最小顶点编号,ed最大顶点编号,s源点,t汇点
bool bfs(int st, int ed, int s, int t)
{
memset(lev, inf, sizeof(lev));
queue<int> q;
q.push(s);
lev[s] = 0;
while (!q.empty())
{
int t = q.front();
q.pop();
for (int i = st; i <= ed; i++)
{
if (flow[t][i] < cap[t][i])
{
if (lev[t] + 1 < lev[i])
{
lev[i] = lev[t] + 1;
q.push(i);
}
}
}
}
return lev[t] < inf;
}

//利用层次网络进行增广,每次dfs寻找的是从该点出发进行dfs增加的总量
//a表示从源点到该节点可增广流量
int dfs(int v, int st, int ed, int s, int t)
{
int res = 0;
if (v == t)
return a[t];
for (int i = st; i <= ed; i++)
{
if (a[v] == 0)
break;
if (flow[v][i] < cap[v][i] && lev[v] + 1 == lev[i])
{
a[i] = min(a[v], cap[v][i] - flow[v][i]);
int temp = dfs(i, st, ed, s, t);
res += temp;
a[v] -= temp;
flow[v][i] += temp;
flow[i][v] -= temp;
}
}
if (res == 0)
{
lev[v] = inf;
}
return res;
}

int dinic(int st, int ed, int s, int t)
{
memset(flow, 0, sizeof(flow));
int res = 0;
while (bfs(st, ed, s, t))
{
memset(a, inf, sizeof(a));
int temp = dfs(s, st, ed, s, t);
if (temp == 0)
break;
res += temp;
}
return res;
}

int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
while (~scanf("%d%d", &n, &m))
{
for (int i = 1; i <= n; i++)
g[i].clear();
for (int i = 0; i < m; i++)
{
int fr, to, value;
scanf("%d%d%d", &fr, &to, &value);
g[fr].push_back(make_pair(to, value));
g[to].push_back(make_pair(fr, value));
}
int s = 1, t = n;
spfa(s, t);
buildGraph();
//        for (int i = 1; i <= n; i++)
//        {
//            for (int j = 1; j <= n; j++)
//            {
//                if (i != j && cap[i][j])
//                {
//                    cout << i << "   " << j << endl;
//                }
//            }
//        }
//        cout << "------" << endl;
printf("%d %d\n", dinic(1, n, s, t), m - step[t]);
}
return 0;
}


1012

题面

Problem Description

There are n circles on a infinitely large table.With every two circle, either one contains another or isolates from the other.They are never crossed nor tangent.

Alice and Bob are playing a game concerning these circles.They take turn to play,Alice goes first:

1、Pick out a certain circle A,then delete A and every circle that is inside of A.

2、Failling to find a deletable circle within one round will lost the game.

Now,Alice and Bob are both smart guys,who will win the game,output the winner’s name.

Input

The first line include a positive integer T<=20,indicating the total group number of the statistic.

As for the following T groups of statistic,the first line of every group must include a positive integer n to define the number of the circles.

And the following lines,each line consists of 3 integers x,y and r,stating the coordinate of the circle center and radius of the circle respectively.

n≤20000,|x|≤20000,|y|≤20000,r≤20000。

Output

If Alice won,output “Alice”,else output “Bob”

Sample Input

2

1

0 0 1

6

-100 0 90

-50 0 1

-20 0 1

100 0 90

47 0 1

23 0 1

Sample Output

Alice

Bob

题意

有一些在坐标系上的圆,他们只有相互包含或者相离的关系。

现在俩人来拿圆,可以拿走当前这个圆里面覆盖的所有圆。

谁先没有东西拿谁输。

现在问谁赢得了比赛。

解析

扫描线 + sg函数博弈论

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 50000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
//////////////////////////////
const int UP = 0;
const int DOWN = 1;
const int IN = 0;
const int OUT = 1;
//////////////////////////////
int nowLineX;

struct Circle
{
int x, y, r;

void read()
{
scanf("%d%d%d", &x, &y, &r);
}

int getX(int tag)
{
if (tag == IN)
return x - r;
return x + r;
}

double getY(int tag)
{
double d = sqrt(r * 1.0 * r - (nowLineX - x) * 1.0 * (nowLineX - x));
if (tag == UP)
return y + d;
return y - d;
}
} circle[maxn];

int lineNum;
struct Line
{
int x, y;
int id;
int tag;
void read(int _x, int _y, int _id, int _tag)
{
x = _x;
y = _y;
id = _id;
tag = _tag;
}
bool operator < (const Line &b)const
{
return (x < b.x) || (x == b.x && y > b.y);
}
} line[maxn << 1];

struct Node
{
int id;
int tag;
Node(){}
Node(int _id, int _tag)
{
id = _id;
tag = _tag;
}
bool operator < (const Node &b)const
{
double ya = circle[id].getY(tag);
double yb = circle[b.id].getY(b.tag);
return (ya > yb) || (ya == yb && tag < b.tag);
}
};

set<Node> lines;
set<Node>::iterator st, ed, it;
vector<int> edge[maxn];
int p[maxn];

int rt;
int n;

void addEdge(int a, int b)
{
edge[a].push_back(b);
edge[b].push_back(a);
}

void scanLine()
{
lines.clear();
rt = n;
for (int i = 0; i < lineNum; i++)
{
nowLineX = line[i].x;
if (line[i].tag == OUT)
{
lines.erase(Node(line[i].id, UP));
lines.erase(Node(line[i].id, DOWN));
}
else
{
///插入完毕后,返回当前插入的这个元素的迭代器
it = lines.insert(Node(line[i].id, UP)).first;
st = ed = it;
ed++;
int id = it->id;
//最外圆
if (st == lines.begin() || ed == lines.end())
{
addEdge(id, rt);
p[id] = rt;
}
else
{
st--;
//包含在此圆内
if (st->id == ed->id)
{
addEdge(id, st->id);
p[id] = st->id;
}
else
{
//与这些圆为兄弟圆
if (p[st->id] == p[ed->id])
{
addEdge(id, p[st->id]);
p[id] = p[st->id];
}
else
{
//父子圆
if (circle[st->id].r < circle[ed->id].r)
{
addEdge(id, p[st->id]);
p[id] = p[st->id];
}
else
{
addEdge(id, p[ed->id]);
p[id] = p[ed->id];
}
}
}
}
lines.insert(Node(line[i].id, DOWN));
}
}
}

int dfs(int u, int fa)
{
int sg = 0;
int sz = edge[u].size();
for (int i = 0; i < sz; i++)
{
if (edge[u][i] != fa)
{
sg ^= (dfs(edge[u][i], u) + 1);
}
}
return sg;
}

int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase;
scanf("%d", &ncase);
while (ncase--)
{
scanf("%d", &n);
lineNum = 0;
for (int i = 0; i <= n; i++)
{
edge[i].clear();
p[i] = -1;
}
for (int i = 0; i < n; i++)
{
circle[i].read();
line[lineNum++].read(circle[i].getX(IN), circle[i].y, i, IN);
line[lineNum++].read(circle[i].getX(OUT), circle[i].y, i, OUT);
}
sort(line, line + lineNum);
scanLine();
int ans = dfs(rt, -1);
if (ans)
printf("Alice\n");
else
printf("Bob\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: