Bestcoder Round #71
通过数:1(一题被叉)
Div2 的A:
斐波那契数列
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 1e5 + 5;
#define LL long long
int cnt;
LL fib[MAXN];
void init()
{
fib[1] = 1, fib[2] = 2;
cnt = 2;
while(fib[cnt] <= 1e18){
fib[cnt + 1] = fib[cnt] + fib[cnt - 1];
cnt++;
}
for(int i = 1 ; i <= cnt ; i++){
fib[i] += fib[i - 1];
if(fib[i] > 1e18){
cnt = i;
break;
}
}
}
int main()
{
init();
int T;
scanf("%d", &T);
while(T--){
LL n;
scanf("%I64d", &n);
int mark = upper_bound(fib + 1, fib + 1 + cnt, n) - fib;
printf("%d\n", mark - 1);
}
return 0;
}
A:
刚开始不知道怎么做。
然后发现换一个角度看问题。如果是直接算中间交点个数呢?因为任意三条线不会交于一点,所以两条线交点唯一。
然后再加上边界的n个点。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL unsigned long long
int main()
{
int T;
scanf("%d", &T);
while(T--){
LL n;
cin >> n;
// scanf("%I64d", &n);
LL ans1 = n;
// printf("%I64d\n", n * (n - 1) * (n - 2) * (n - 3));
LL t1 = n * (n - 1) / 2;
LL t2 = t1 * (n - 2) / 3;
LL t3 = (t2 * (n - 3)) / 4;
// printf("t1 = %llu, t2 = %llu, t3 = %llu\n", t1, t2, t3);
// LL ans2 = (n) * (n - 1) / 2 * (n - 2) / 3 * (n - 3) / 4;
// printf("%llu\n", ans1 + t3);
cout << ans1 + t3 << endl;
}
return 0;
}
B:
并不知道怎么写的一道题。
/*
把原图建成无向图染色问题
因为原图的特殊性(一个点只有一个出度),所以不会有环套环的存在。
因此,把图分成环和树分别讨论
环上对答案的贡献用dp[tcnt-1][0]表示
dp[i][j]表示环上第i个点,j=0表示颜色与第一个结点不同,j=1表示颜色与第一个结点不同
假设环上tcnt个点,对答案贡献ans * (dp[tcnt - 1][0] * m)
树上对答案贡献:因为子节点只要与父节点不同即可
故当父节点颜色确定,子节点贡献ans * (m-1)
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
#define LL long long
#define mod (1000000007)
const int MAXN = 100 + 5;
LL fac[MAXN], dp[MAXN][3];
int vis[MAXN];
int to[MAXN];
vector<int>lin[MAXN];
int n, m;
void init()
{
fac[0] = 1;
for(int i = 1 ; i < MAXN ; i++) fac[i] = (fac[i - 1] * (i)) % mod;
dp[0][1] = 1;
dp[0][0] = 0;
for(int i = 1 ; i < n ; i++){
dp[i][0] = (dp[i - 1][0] * (m - 2) % mod + dp[i - 1][1] * (m - 1) % mod) % mod;
dp[i][1] = dp[i - 1][0];
}
memset(vis, -1, sizeof(vis));
}
int main()
{
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
init();
for(int i = 0 ; i < n ; i++) scanf("%d", &to[i]);
LL ans = 1;
int cnt = 0;
for(int i = 0 ; i < n ; i++){
if(vis[i] == -1){
int u = i;
while(vis[u] == -1){
vis[u] = i;
u = to[u];
}
if(vis[u] == i){
int tcnt = 1;
int v = u;
u = to[u];
while(u != v){
u = to[u];
tcnt++;
}
// printf("i = %d, tcnt = %d\n", i, tcnt);
ans = (ans * ((dp[tcnt - 1][0] * m) % mod)) % mod;
cnt += tcnt;
}
}
}
for(int i = 0 ; i < n - cnt ; i++)
ans = (ans * (m - 1)) % mod;
printf("%I64d\n", ans);
}
return 0;
}
C:
赛中懒得dp直接上的记忆化搜索。
然后就被叉掉了。
Dp[i]表示取第i个数时,得到最大差值。转移方程dp[i] = max(a[i] - dp[i-1], dp[i-1)
/*
O(n)处理,保留一个前面最大的a[j] - dp[j - 1]值
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
#include <utility>
using namespace std;
const int MAXN = 50000 + 6;
#define LL long long
int a[MAXN];
LL dp[MAXN];
int main()
{
int T;
scanf("%d", &T);
while(T--){
int n;
scanf("%d", &n);
for(int i = 1 ; i <= n ; i++) scanf("%d", &a[i]);
sort(a + 1, a + 1 + n);
dp[0] = 0;
LL MMAX = 0;
for(int i = 1 ; i <= n ; i++){
LL temp = a[i] - dp[i - 1];
MMAX = max(MMAX, temp);
dp[i] = MMAX;
}
// for(int i = 1 ; i <= n ; i++)
// printf("dp[%d] = %I64d\n", i, dp[i]);
printf("%I64d\n", dp[n]);
}
return 0;
}
D:
算复杂度这个解法实际上不正确。
然而还没学LCT和次小生成树,所以就水一发好了。
暴力枚举最小边或最大边,然后做一遍kruskal最小生成树。注意枚举处有一个最优性剪枝。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
#define LL long long
const int MAXN = 2000 + 5;
const int MAXM = 15000 + 5;
struct Edge
{
int u, v;
int w;
}edge[MAXM];
int fa[MAXN];
int n, m;
int find_fa(int u){return u == fa[u] ? u : fa[u] = find_fa(fa[u]);}
bool cmp(Edge a, Edge b){return a.w > b.w;}
int main()
{
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
for(int i = 1 ; i <= m ; i++) scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
sort(edge + 1, edge + 1 + m, cmp);
// for(int i = 1 ; i <= m ; i++){
// printf("u = %d, v = %d, w = %d\n", edge[i].u, edge[i].v, edge[i].w);
// }
int ans = 0;
int cnt = 0;
for(int i = 1 ; i <= n ; i++) fa[i] = i;
// memset(visedge, 0, sizeof(visedge));
int st;
for(st = 1 ; st <= m ; st++){
int u = edge[st].u, v = edge[st].v, w = edge[st].w;
int fau = find_fa(u);
int fav = find_fa(v);
if(fau != fav){
fa[fau] = fav;
cnt++;
}
if(cnt == n - 1){
ans = edge[1].w - edge[st].w;
break;
}
}
if(st > m){
puts("-1");
continue;
}
///此处不能++
// st++;
for(; st <= m ; st++){
for(int i = 1 ; i <= n ; i++) fa[i] = i;
cnt = 0;
for(int j = st ; j >= 1 && ans > edge[j].w - edge[st].w ; j--){
int u = edge[j].u, v = edge[j].v, w = edge[j].w;
int fau = find_fa(u);
int fav = find_fa(v);
if(fau != fav){
fa[fau] = fav;
cnt++;
}
if(cnt == n - 1){
ans = min(ans, edge[j].w - edge[st].w);
// printf("st = %d, ans = %d\n", st, edge[j].w - edge[st].w);
break;
}
}
}
printf("%d\n", ans);
}
return 0;
}