为啥没F题?
有打野说是可持久化treap,我不会啊……还有讨论别的做法的,但是我都不会……也看不懂。
赛场上,最终AC也只有2个人,以后再补这道题。
题目大意:
给定一串数字,问其中连续的一段,单调递增的序列,最长的长度是多长。 是子数组,不是子序列哦!
f[i] = {f[j] + 1 | a[i]>a[j]} 否则为f[i]=1
转移即可。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std;
typedef long long LL;
const LL mod = 1000000007LL;
LL powMod( LL a , LL b , LL p = mod )//a^b % p
{
LL r = 1 ;
a %= p ;
while( b )
{
if( b&1 ) r = r*a%p ;
b >>= 1 ;
a = a*a%p ;
}
return r ;
}
int main()
{
int n;
int ans = 1;
scanf("%d", &n);
int now,pre;
scanf("%d", &pre);
int now_length=1;
for (int i = 2; i <= n; ++ i)
{
scanf("%d", &now);
if (now > pre)
{
++ now_length;
}
else now_length = 1;
swap(now, pre);
ans = max(ans, now_length);
}
printf("%d\n",ans);
return 0;
}
B题Powers of Two:题目大意
给一个 n,后面n个数字分别为a1,a2,a3...an
问,有多少个形如ai+aj = 2^x的式子。i,j不同
预处理所有2^x,预处理对于ai而言,他需要哪些数字可以组合出2^n
比如对于3,可以和1(组合出4),5(组合出8),和13(组合出16)…… 因为ai最大为1e9,所以能组合出的2^x的x不会太大。
然后用一个map,保存每个数字出现了多少次。 对于3的时候,直接查询有几个1,几个5,几个13…… 然后把答案累加即可。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <cstring>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
typedef long long LL;
LL ans = 0;
int n;
map<LL, LL>mp;
void ins(LL k)
{
if (mp.find(k) == mp.end())
{
mp[k] = 1;
}else mp[k] ++;
}
const int maxn = 100010;
LL a[35];
LL b[maxn];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++ i)
{
int t;
scanf("%d", &t);
ins(t);
b[i] = t;
}
a[0] = 1;
for (int i = 1; i <= 32; ++ i) a[i] = a[i - 1] * 2;
// for (int i = 1; i <= 32; ++ i) cout<< a[i] <<endl;
for (int i = 1; i <= n; ++ i)
{
for (int j = 1; j <= 32; ++ j)
{
LL tmp = a[j] - b[i];
if (mp.find(tmp) == mp.end()) continue;
ans += (mp[tmp]);
if (tmp == b[i]) ans--;
}
}
cout << ans / 2 << endl;
return 0;
}
C题Cellular Network:题目大意:
一条直线上,有若干个村庄,有若干个基站。
基站覆盖半径为k的时候,如果村庄距离基站的距离小于等于k的时候,则这个村庄被基站所覆盖。
为最小的k,可以让所有的村庄被覆盖。
二分答案,直接暴力判断即可。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std;
typedef long long LL;
const LL mod = 1000000007LL;
LL powMod( LL a , LL b , LL p = mod )//a^b % p
{
LL r = 1 ;
a %= p ;
while( b )
{
if( b&1 ) r = r*a%p ;
b >>= 1 ;
a = a*a%p ;
}
return r ;
}
LL d, k, a, b, t;
LL solve()
{
if (k >=d) return a * d;
if (k * a + t - k * b >= 0)
{
return d * b - k * b + k * a;
}
LL x = d / k - 1;
return d * b - k * b + k * a + x * (k * a + t - k * b);
}
LL get() //车结尾
{
if (k >= d) return a * d;
LL x = d / k;
LL s = d % k;
return (a * k + t) * x + s * a;
}
int main()
{
cin >> d >> k >> a >> b >> t;
LL ans1 = solve(); //步行结尾
LL ans2 = get(); // 车结尾
cout << min(ans1, ans2) << endl;
return 0;
}
D题Road to Post Office:题目大意
从A地出发到B地,
有一个交通工具是车,车走K米,就会坏。 坏了如果修的话,要T时间。可以不修,直接下车往目的地走。步行的速度小于车的速度,问最短需要的时间。
设车开了X个K米(要修理)外加一个车程(不修理,车坏了下车直接走向目的地),列出一个方程,发现这是一个一次方程……一次方程,就是X要不取最大的,要不取0。
方程自己求好了。。我不想打了。。。
几个会被X的要点:
1、可以车直接开到终点,不需要下车也不需要步行,更不要修车
2、一直开车,不下车步行,直到到终点
3、开车,修车,步行
4、开车,不修车,步行
其实程序没那么复杂啦……
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std;
typedef long long LL;
const LL mod = 1000000007LL;
LL powMod( LL a , LL b , LL p = mod )//a^b % p
{
LL r = 1 ;
a %= p ;
while( b )
{
if( b&1 ) r = r*a%p ;
b >>= 1 ;
a = a*a%p ;
}
return r ;
}
LL d, k, a, b, t;
LL solve()
{
if (k >=d) return a * d;
if (k * a + t - k * b >= 0)
{
return d * b - k * b + k * a;
}
LL x = d / k - 1;
return d * b - k * b + k * a + x * (k * a + t - k * b);
}
LL get() //车结尾
{
if (k >= d) return a * d;
LL x = d / k;
LL s = d % k;
return (a * k + t) * x + s * a;
}
int main()
{
cin >> d >> k >> a >> b >> t;
LL ans1 = solve(); //步行结尾
LL ans2 = get(); // 车结尾
cout << min(ans1, ans2) << endl;
return 0;
}
F题Analysis of Pathes in Functional Graph:题目大意
给你一个图,这个图有个特点,每个点出度为1.
每个边有权重为wi,问你,从一个点出发,走K步,所经过的所有点的权重和是多少,经过所有点权重最小的点是多少。 这个询问,从点1一直问到点n。
倍增算法,类似ST算法。 不懂ST算法的最好去学一下 ST算法先。
这道题AC后还有3秒比赛结束……要是错了我也没法改了……还好最终是AC的。
g[i][j]表示从i出发,走2^j步,所停留的点
f[i][j]表示从i出发,走2^j步,所经过的点的权重和
m[i][j]表示表示从i出发,走2^j步,所经过的点的权重的最小值
next[i]表示i的后续节点是什么
w[i]表示权重
用形如st算法的方法转移即可。
g[i][j] = g[g[i][j-1]][j-1]
f[i][j] = f[i][j-1] + f[g[i][j-1]][j-1]
m[i][j]形式类似
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std;
typedef long long LL;
const int maxn = 100010;
int n;
LL k;
int nextttt[maxn];
LL w[maxn];
void init()
{
scanf("%d%I64d", &n, &k);
for (int i = 0; i != n; ++ i)
scanf("%d", &nextttt[i]);
for (int i = 0; i != n; ++ i)
scanf("%I64d", &w[i]);
}
LL f[maxn][50], g[maxn][50], m[maxn][50];
vector<int>sb;
void check(int k)
{
LL xiao = 10000000000000LL;
LL sum = 0;
int now = k;
for (int i = 0; i != sb.size(); ++ i)
{
int p = sb[i];
xiao = min(xiao, m[now][p]);
sum += f[now][p];
now = g[now][p];
}
printf("%I64d %I64d\n", sum, xiao);
}
void doit()
{
memset(f, 0, sizeof(f));
memset(g, 0, sizeof(g));
sb.clear();
for (int i = 0; i != n; ++ i)
{
f[i][0] = w[i];
g[i][0] = nextttt[i];
m[i][0] = w[i];
}
for (int j = 1; j <= 45;++j)
for (int i = 0; i != n; ++ i)
{
f[i][j] = f[i][ j - 1] + f[g[i][j - 1]][j - 1];
g[i][j] = g[g[i][j-1]][j - 1];
m[i][j] = min(m[i][j - 1] , m[g[i][j - 1]][j - 1]);
//cout<<f[i][j]<<endl;
}
for (int i = 0; i <= 45; ++ i)
if ((k >> i) & 1)
{
sb.push_back(i);
//cout<<"?"<<" "<<i<<endl;
}
//for (int i = 0; i != sb.size(); ++ i) cout <<"@"<< i << endl;
//return;
for (int i = 0; i != n; ++ i)
{
check(i);
}
}
int main()
{
init();
doit();
return 0;
}