/*************************************************************************
> File Name: algo_1.cpp
> Author: gwq
> Mail: [email protected]
> Created Time: 2014年11月08日 星期六 12时58分31秒
************************************************************************/
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())
using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef long long ll;
const double esp = 1e-5;
#define N 1010
int num[N], tmp[N];
int findk(int k, int l, int r)
{
int key = tmp[l];
int i = l;
int j = r;
//当i==j的时候就找到了key在数组中的下标,就是i
while (i < j) {
while (i < j && tmp[j] >= key) {
--j;
}
tmp[i] = tmp[j];
while (i < j && tmp[i] <= key) {
++i;
}
tmp[j] = tmp[i];
}
tmp[i] = key;
if (i == k) {
return tmp[k];
} else if (i < k) {
return findk(k, i + 1, r);
} else {
return findk(k, l, r - 1);
}
}
int main(int argc, char *argv[])
{
int n, m, l, r, k;
while (scanf("%d", &n) != EOF) {
for (int i = 1; i <= n; ++i) {
scanf("%d", &num[i]);
}
scanf("%d", &m);
for (int i = 0; i < m; ++i) {
scanf("%d%d%d", &l, &r, &k);
int cnt = 0;
for (int j = l; j <= r; ++j) {
tmp[cnt++] = num[j];
}
//这种先排序,再取第k大的复杂度是mnlogn
//这里给的数据量小,可以忍受,还有一种方法
//是利用快排的思想,可以把复杂度降为mn,单次
//查询第k大的复杂度是logn。
//从小到大排序
//sort(tmp, tmp + cnt);
//第k大的下标就是cnt-k
//printf("%d\n", tmp[cnt - k]);
//需要寻找下标为cnt-k的数
printf("%d\n", findk(cnt - k, 0, cnt - 1));
}
}
return 0;
}
/*
算法训练 区间k大数查询
时间限制:1.0s 内存限制:256.0MB
问题描述
给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个。
输入格式
第一行包含一个数n,表示序列长度。
第二行包含n个正整数,表示给定的序列。
第三个包含一个正整数m,表示询问个数。
接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个。序列元素从1开始标号。
输出格式
总共输出m行,每行一个数,表示询问的答案。
样例输入
5
1 2 3 4 5
2
1 5 2
2 3 2
样例输出
4
2
数据规模与约定
对于30%的数据,n,m<=100;
对于100%的数据,n,m<=1000;
保证k<=(r-l+1),序列中的数<=10^6。
*/
/*************************************************************************
> File Name: algo_2.cpp
> Author: gwq
> Mail: [email protected]
> Created Time: 2014年11月08日 星期六 13时26分29秒
************************************************************************/
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())
using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef long long ll;
const double esp = 1e-5;
/*
* 这个在蓝桥杯的训练网站上只得到60分
* 不知道是什么原因。
*/
int main(int argc, char *argv[])
{
ll n;
while (cin >> n) {
ll ans;
if (n <= 2) {
//处理好特殊情况
ans = n;
} else if (n % 2 == 1) {
//当n为奇数时,n,n-1,n-2这三个数一定互质
//相邻的两个整数一定是互质的
ans = n * (n - 1) * (n - 2);
} else if (n % 3 != 0) {
//当n为偶数时,并且n不能被3整除,那么n,n-1,n-3
//这3个数一定互质,并且不能找到更大的数了
ans = n * (n - 1) * (n - 3);
} else {
//当n为偶数,并且能被3整除时,根据上边的说法,
//这个3个数互质,并且也不能找到更大的数了
ans = (n - 1) * (n - 2) * (n - 3);
}
cout << ans << endl;
}
return 0;
}
/*
算法训练 最大最小公倍数
时间限制:1.0s 内存限制:256.0MB
问题描述
已知一个正整数N,问从1~N中任选出三个数,他们的最小公倍数最大可以为多少。
输入格式
输入一个正整数N。
输出格式
输出一个整数,表示你找到的最小公倍数。
样例输入
9
样例输出
504
数据规模与约定
1 <= N <= 10^6。
*/
/*************************************************************************
> File Name: algo_3.cpp
> Author: gwq
> Mail: [email protected]
> Created Time: 2014年11月08日 星期六 20时32分00秒
************************************************************************/
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())
using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef long long ll;
const double esp = 1e-5;
#define N 110
#define MOD (1000000007)
//数位dp,dp[i][j]表示i位数最高位是j的符合题意的数的个数
int dp[N][N];
int main(int argc, char *argv[])
{
int K, L;
while (scanf("%d%d", &K, &L) != EOF) {
clr(dp, 0);
for (int i = 0; i < K; ++i) {
dp[1][i] = 1;
}
for (int i = 2; i <= L; ++i) {
for (int j = 0; j < K; ++j) {
for (int k = 0; k < K; ++k) {
if (k != j - 1 && k != j + 1) {
dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD;
}
}
}
}
int ans = 0;
for (int i = 1; i < K; ++i) {
ans = (ans + dp[L][i]) % MOD;
}
printf("%d\n", ans);
}
return 0;
}
/*
算法训练 K好数
时间限制:1.0s 内存限制:256.0MB
问题描述
如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,
那么我们就说这个数是K好数。求L位K进制数中K好数的数目。
例如K = 4,L = 2的时候,所有K好数为11、13、20、22、30、31、33 共7个。
由于这个数目很大,请你输出它对1000000007取模后的值。
输入格式
输入包含两个正整数,K和L。
输出格式
输出一个整数,表示答案对1000000007取模后的值。
样例输入
4 2
样例输出
7
数据规模与约定
对于30%的数据,KL <= 10^6;
对于50%的数据,K <= 16, L <= 10;
对于100%的数据,1 <= K,L <= 100。
*/
/*************************************************************************
> File Name: algo_4.cpp
> Author: gwq
> Mail: [email protected]
> Created Time: 2015年03月19日 星期四 14时04分19秒
************************************************************************/
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())
using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-5;
#define N 100010
int dp[N][2], n;
vector<int> edge[N];
void dfs(int u, int f)
{
for (int i = 0; i < sz(edge[u]); ++i) {
int v = edge[u][i];
if (f != v) {
dfs(v, u);
dp[u][1] += dp[v][0];
dp[u][0] += max(dp[v][0], dp[v][1]);
}
}
}
int main(int argc, char *argv[])
{
while (scanf("%d", &n) != EOF) {
clr(dp, 0);
for (int i = 1; i <= n; ++i) {
scanf("%d", &dp[i][1]);
}
for (int i = 1; i < n; ++i) {
int u, v;
scanf("%d%d", &u, &v);
edge[u].pb(v);
edge[v].pb(u);
}
dfs(1, -1);
printf("%d\n", dp[1][0]);
}
return 0;
}
/*
问题描述
有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,
那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
输入格式
第一行包含一个整数 n 。
接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。
接下来一共 n-1 行,每行描述树上的一条边。
输出格式
输出一个整数,代表选出的点的权值和的最大值。
样例输入
5
1 2 3 4 5
1 2
1 3
2 4
2 5
样例输出
12
样例说明
选择3、4、5号点,权值和为 3+4+5 = 12 。
数据规模与约定
对于20%的数据, n <= 20。
对于50%的数据, n <= 1000。
对于100%的数据, n <= 100000。
权值均为不超过1000的正整数。
*/
/*************************************************************************
> File Name: algo_5.cpp
> Author: gwq
> Mail: [email protected]
> Created Time: 2015年03月19日 星期四 14时58分31秒
************************************************************************/
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())
using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-5;
#define N 20010
struct Node {
int v, d;
};
int n, m, d[N], vis[N];
vector<Node> edge[N];
// 普通的dijkstra运行超时,得使用堆优化的dijkstra
void dijkstra(void)
{
clr(d, 0);
clr(vis, 0);
int s = 1;
for (int i = 1; i <= n; ++i) {
if (i == s) {
d[i] = 0;
} else {
d[i] = INF;
}
}
for (int i = 1; i <= n; ++i) {
int x;
int dis = INF;
for (int j = 1; j <= n; ++j) {
if (vis[j] == 0 && dis > d[j]) {
x = j;
dis = d[j];
}
}
vis[x] = 1;
// vector的下标是从0开始的
for (int j = 0; j < sz(edge[x]); ++j) {
int v = edge[x][j].v;
d[v] = min(d[v], d[x] + edge[x][j].d);
}
}
}
int main(int argc, char *argv[])
{
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = 0; i < m; ++i) {
int u, v, l;
scanf("%d%d%d", &u, &v, &l);
Node x;
x.v = v;
x.d = l;
edge[u].pb(x);
}
dijkstra();
for (int i = 2; i <= n; ++i) {
printf("%d\n", d[i]);
}
}
return 0;
}
/*
问题描述
给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。
请你计算从1号点到其他点的最短路(顶点从1到n编号)。
输入格式
第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。
输出格式
共n-1行,第i行表示1号点到i+1号点的最短路。
样例输入
3 3
1 2 -1
2 3 -1
3 1 2
样例输出
-1
-2
数据规模与约定
对于10%的数据,n = 2,m = 2。
对于30%的数据,n <= 5,m <= 10。
对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,
保证从任意顶点都能到达其他所有顶点。
*/
/*************************************************************************
> File Name: algo_5_heap.cpp
> Author: gwq
> Mail: [email protected]
> Created Time: 2015年03月19日 星期四 14时58分31秒
************************************************************************/
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())
using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-5;
#define N 20010
struct Node {
int v, d;
};
int n, m, d[N], vis[N];
vector<Node> edge[N];
void dijkstra(void)
{
clr(vis, 0);
for (int i = 1; i <= n; ++i) {
if (i == 1) {
d[i] = 0;
} else {
d[i] = INF;
}
}
priority_queue<pii, vector<pii>, greater<pii> > pq;
pq.push(make_pair(0, 1));
while (!pq.empty()) {
pii x = pq.top();
pq.pop();
int u = x.second;
if (vis[u]) {
continue;
}
vis[u] = 1;
for (int i = 0; i < sz(edge[u]); ++i) {
int v = edge[u][i].v;
if (d[v] > d[u] + edge[u][i].d) {
d[v] = d[u] + edge[u][i].d;
pq.push(make_pair(d[v], v));
}
}
}
}
int main(int argc, char *argv[])
{
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = 0; i < m; ++i) {
int u, v, l;
scanf("%d%d%d", &u, &v, &l);
Node x;
x.v = v;
x.d = l;
edge[u].pb(x);
}
dijkstra();
for (int i = 2; i <= n; ++i) {
printf("%d\n", d[i]);
}
}
return 0;
}
/*
问题描述
给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。
请你计算从1号点到其他点的最短路(顶点从1到n编号)。
输入格式
第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。
输出格式
共n-1行,第i行表示1号点到i+1号点的最短路。
样例输入
3 3
1 2 -1
2 3 -1
3 1 2
样例输出
-1
-2
数据规模与约定
对于10%的数据,n = 2,m = 2。
对于30%的数据,n <= 5,m <= 10。
对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,
保证从任意顶点都能到达其他所有顶点。
*/
/*************************************************************************
> File Name: algo_6.cpp
> Author: gwq
> Mail: [email protected]
> Created Time: 2015年03月20日 星期五 16时29分52秒
************************************************************************/
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())
using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef long long ll;
const double esp = 1e-5;
#define N 100010
int c[N], n, p, m[N];
struct Node {
int u, v, w;
void input(void)
{
scanf("%d%d%d", &u, &v, &w);
// 以这个为新的权值。再加上住处的时间就行了
w = 2 * w + c[u] + c[v];
}
}node[N];
bool cmp(Node u, Node v)
{
return u.w < v.w;
}
int find(int x)
{
return ((m[x] == x) ? x : (m[x] = find(m[x])));
}
int main(int argc, char *argv[])
{
while (scanf("%d%d", &n, &p) != EOF) {
int minn = INF;
for (int i = 1; i <= n; ++i) {
scanf("%d", &c[i]);
minn = min(minn, c[i]);
}
for (int i = 0; i < p; ++i) {
node[i].input();
}
sort(node, node + p, cmp);
for (int i = 1; i <= n; ++i) {
m[i] = i;
}
int ans = 0;
for (int i = 0; i < p; ++i) {
int x = find(node[i].u);
int y = find(node[i].v);
if (x != y) {
m[x] = y;
ans += node[i].w;
}
}
printf("%d\n", ans + minn);
}
return 0;
}
/*
问题描述
Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路。道路被用来连
接N个牧场,牧场被连续地编号为1到N。每一个牧场都是一个奶牛的家。FJ计划除去P条
道路中尽可能多的道路,但是还要保持牧场之间 的连通性。你首先要决定那些道路是
需要保留的N-1条道路。第j条双向道路连接了牧场Sj和Ej(1 <= Sj <= N; 1 <= Ej <= N;
Sj != Ej),而且走完它需要Lj的时间。没有两个牧场是被一条以上的道路所连接。奶牛
们非常伤心,因为她们的交通系统被削减了。你需要到每一个奶牛的住处去安慰她们。
每次你到达第i个牧场的时候(即使你已经到过),你必须花去Ci的时间和奶牛交谈。
你每个晚上都会在同一个牧场(这是供你选择的)过夜,直到奶牛们都从悲伤中缓过神来。
在早上 起来和晚上回去睡觉的时候,你都需要和在你睡觉的牧场的奶牛交谈一次。
这样你才能完成你的 交谈任务。假设Farmer John采纳了你的建议,请计算出使所有
奶牛都被安慰的最少时间。
输入格式
第1行包含两个整数N和P。
接下来N行,每行包含一个整数Ci。
接下来P行,每行包含三个整数Sj, Ej和Lj。
输出格式
输出一个整数, 所需要的总时间(包含和在你所在的牧场的奶牛的两次谈话时间)。
样例输入
5 7
10
10
20
6
30
1 2 5
2 3 5
2 4 12
3 4 17
2 5 15
3 5 6
样例输出
176
数据规模与约定
5 <= N <= 10000,N-1 <= P <= 100000,0 <= Lj <= 1000,1 <= Ci <= 1,000。
*/