您的位置:首页 > 运维架构

2014-2015 Northwestern European Regional Contest (NWERC 2014)【solved:7 / 11】

2017-09-04 19:31 981 查看
说实话 我觉得k是还能抢救一下的那种

update:2017年10月17日22:48:45

C - Cent Savings (DP)

题意:让你分d次,问你一个序列被分成d+1段后,每段内部加和,四舍五入,然后统计所有段的加和的最小值是多少。n≤2000,d≤20。

思路:简单dp。注意切d刀是d+1段。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2000 + 5;
const int INF = 0x3f3f3f3f;
int a[maxn], sum[maxn], dp[maxn][25];
int calc(int lb, int rb)
{
int temp = sum[rb] - sum[lb - 1];
return (temp + 5) / 10 * 10;
}

int main()
{
int n, d;
scanf("%d%d", &n, &d);
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
sum[i]
4000
= sum[i - 1] + a[i];
}
memset(dp, INF, sizeof(dp));
for(int i = 1; i <= n; i++) dp[i][1] = calc(1, i);
for(int i = 1; i <= n; i++)
{
for(int j = 2; j <= d + 1; j++)
{
for(int k = 1; k < i; k++)
{
dp[i][j] = min(dp[i][j], dp[k][j - 1] + calc(k + 1, i));
}
}
}
int ans = calc(1, n);
for(int i = 1; i <= d + 1; i++) ans = min(ans, dp
[i]);
printf("%d\n", ans);
return 0;
}


D - Digi Comp II (DAG)

题意:给你一张有向图,有m个顶点有左右两条有向边(m≤5e5),每个顶点有个初始状态L/R,每当有一个小球从顶点1落下,他将通过经过的顶点的状态决定前进方向,并改变这些顶点的状态。

思路:显然若它的初始态为L,则它向右儿子提供的改变状态次数将是它的状态次数/2,左儿子是上取整。所以这其实是一个DAG,每个顶点在入度为0的时候才计算它的终止态翻转多少次,所以使用一个拓扑排序即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 500000 + 5;
vector<int>G[maxn];
int in[maxn];
char state[maxn];
long long dp[maxn];

int main()
{
long long n, m;
scanf("%I64d%I64d", &n, &m);
for(int i = 1; i <= m; i++) dp[i] = in[i] = 0;
for(int i = 1; i <= m; i++)
{
char ch;
int x, y;
getchar();
scanf("%c%d%d", &state[i], &x, &y);
G[i].push_back(x);
G[i].push_back(y);
in[x]++, in[y]++;
}
queue<int>que;
for(int i = 1; i <= m; i++)
if(in[i] == 0)  que.push(i);
dp[1] = n;
while(que.size())
{
int cur = que.front();que.pop();
int lson = G[cur][0], rson = G[cur][1];
if(state[cur] == 'L')
{
if(lson)    dp[lson] += dp[cur] - dp[cur] / 2;
if(rson)    dp[rson] += dp[cur] / 2;
}
else if(state[cur] == 'R')
{
if(rson)    dp[rson] += dp[cur] - dp[cur] / 2;
if(lson)    dp[lson] += dp[cur] / 2;
}
in[lson]--, in[rson]--;
if(lson != 0 && in[lson] == 0)   que.push(lson);
if(rson != 0 && in[rson] == 0 && lson != rson)   que.push(rson);
}
for(int i = 1; i <= m; i++)
{
if(dp[i] % 2 == 0 && state[i] == 'L')   putchar('L');
else if(dp[i] % 2 == 1 && state[i] == 'L')   putchar('R');
else if(dp[i] % 2 == 0 && state[i] == 'R')   putchar('R');
else if(dp[i] % 2 == 1 && state[i] == 'R')   putchar('L');
}
puts("");
return 0;
}


E - Euclidean TSP (二分)

题意:给你个函数,仅有一个未知参数C,问你这个C取何值的时候,函数值最小。输出函数值和C。

思路:求个导,发现单调,二分一下就行。

#include <bits/stdc++.h>
using namespace std;
double n, p, s, v;
const double sqrt2 = sqrt(2);
double f(double c)
{
return -1.0 * s / v / c / c + n * sqrt2 * ( pow(log2(n), (c * sqrt2))) * log(log2(n)) / (p * 1e9);
}
double getAns(double c)
{
return 1.0 * s / v * (1.0 + 1.0 / c) + n * (pow(log2(n), sqrt2 * c)) / (p * 1e9);
}
int main()
{
cin >> n >> p >> s >> v;
double temp;
double lb = 0, rb = 1e9;
for(int i = 0; i < 200; i++)
{
double mid = (lb + rb) / 2;
if(f(mid) > 0) rb = mid;
else lb = mid;
}
double c = rb;
printf("%.10f %.10f\n", getAns(c), c);
return 0;
}


F - Finding Lines (随机算法)

题意:二维平面上有n个点(n≤1e5),问你能否找到一条直线,使得有至少p%的点在这条直线上。

思路:随机得到两个点,构成一条直线,O(n)check是否满足题意,获得正解的概率应该是p2,最低应该是1/25。emmm。可我不知道为什么要随机这么多次才能过….

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
using namespace std;
const int maxn = 1e5 + 5;
const int repeatTimes = 300;
pair<int, int>nodes[maxn];

double x1, x2, y1, y2;
bool judge(double fx, double fy)
{
if(fabs(1.0 * (y1 - y2) / (x1 - x2) * (fx - x1) + y1 - fy) < 1e-8)   return true;
return false;
}
int main()
{
int n, p;
scanf("%d%d", &n, &p);
int limit = (p * n + 99) / 100;
for(int i = 1, x, y; i <= n; i++) scanf("%d%d", &x, &y), nodes[i] = {x, y};
for(int k = 1; k <= repeatTimes; k++)
{
x1 = nodes[1].first, y1 = nodes[1].second;
x2 = nodes[2].first, y2 = nodes[2].second;
int cnt = 2;
for(int i = 3; i <= n; i++)
{
if(x1 == x2 && nodes[i].first == x1)    cnt++;
else if(y1 == y2 && nodes[i].second == y1)   cnt++;
else if(judge(nodes[i].first, nodes[i].second))   cnt++;
}
if(cnt >= limit)
{
puts("possible");
return 0;
}
random_shuffle(nodes + 1, nodes + n);
}
puts("impossible");
return 0;
}


H - Hyacinth (构造)

题意:给你一棵树,每个树有两个频道,相邻结点至少有一个频道相同,使得相邻结点的相同的频道的集合尽量的大。输出方案。第一个样例的集合大小为2,第二个样例大小的集合大小为6。

思路:题意杀….懂题意就很好写了啊。。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10000 + 5;
pair<int, int>ans[maxn];
vector<int>G[maxn];
int cnt, vis[maxn];
void dfs(int cur, int fa, int v1, int v2)
{
int siz = G[cur].size(), sons = 0;
ans[cur] = {v1, v2};
for(int i = 0; i < siz; i++)
{
int to = G[cur][i];
if(to ==  fa)    continue;
sons++;
if(G[to].size() == 1)   vis[v1] = vis[v2] = 1, dfs(to, cur, v1, v2);
else if(vis[v1] == 0)  vis[v1] = 1, dfs(to, cur, v1, cnt++);
else vis[v2] = 1, dfs(to, cur, v2, cnt++);
}
}

int main()
{
int n;
scanf("%d", &n);
for(int i = 0; i < n - 1; i++)
{
int x, y;
scanf("%d%d", &x, &y);
G[x].push_back(y);
G[y].push_back(x);
}
cnt = 3;
dfs(1, -1, 1, 2);
ans[1] = {1, 2};
for(int i = 1; i <= n; i++) printf("%d %d\n", ans[i].first, ans[i].second);
return 0;
}


I - Indoorienteering (折半搜索)

题意:给一个n*n的邻接矩阵 代表 俩俩顶点之间的距离。一共n个点。然后问你。长度为w的回路是否存在,就是从u出发,最多每条边只能过一次最终回到u。(1\len,w≤1e15)

http://blog.csdn.net/qq_29556211/article/details/78267854

J - Judging Troubles (water)

….不小心数组开小了。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int a[maxn], b[maxn];
map<string , int>ma;
int main()
{
int n;
scanf("%d", &n);
int cnt = 1;
char ss[100];
for(int i = 0; i < n; i++)
{
scanf("%s", ss);
string s = ss;
if(ma[s] == 0)   ma[s] = cnt++;
a[ma[s]]++;
}
for(int i = 0; i < n; i++)
{
scanf("%s", ss);
string s = ss;
if(ma[s] == 0)   ma[s] = cnt++;
b[ma[s]]++;
}
int ans = 0;
for(int i = 1; i < cnt; i++)    ans += min(a[i], b[i]);
printf("%d\n", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐