18.8.15 考试总结
买卖
【问题描述】 小明找到了n个商店 小明 分别从第1个走到第n个。
在每个商店中小明可以 :买入1个或0个物品A,若买入1个消耗 ai;
卖出1个或 0物品 A,若卖出 ,若卖出1个获得bi.
求小明在最后能获得的最大价值 。
【输入格式】
从文件buy.in 中输入数据。 第一行一个整数n。
第二行n个整数,表示ai。 第三行n个整数,表示bi。
【输出格式】
输出到 文件 buy.out .out中。
第一行一个整数n。 第二行n个整数,表示ai。 第三行n个整数,表示bi。
这道题我一开始的贪心是错误的忘记考虑反悔的情况
后来发现这道题可以用网络流打暴力 可以狗四十分的
但是不知道为什么除了第一个点都re 难过
标程就是维护一个堆 每次走到一个i时的时候,我们就把i的买入价格推到堆里,
如果点 i的卖出价格比前面还没买物品里最便宜要高 那么我们买入个最便宜的,
然后在这卖出就可以获得利润 把堆顶弹出并更新答案 但是可能这样子配对并不是最优的
所以就把b也压进去 以便反悔(b[j] - a[s] = b[j] - b[i] + b[i] - a[s])
代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e7; struct node { ll x; bool operator < (const node & a) const { return x > a.x; } }; priority_queue<node>Q; ll a[N],b[N],ans; int n; int main( ) { freopen("buy.in","r",stdin); freopen("buy.out","w",stdout); scanf("%d",& n); for(int i = 1;i <= n;i ++) scanf("%I64d",& a[i]); for(int i = 1;i <= n;i ++) scanf("%I64d",& b[i]); for(int i = 1;i <= n;i ++) { node u,s; s.x = a[i]; Q.push(s); u = Q.top( ); if(u.x <= b[i]) { ans += b[i] - u.x; if(! Q.empty( )) Q.pop( ); node ss; ss.x = b[i]; Q.push(ss); } } printf("%I64d",ans); }
投资
【问题描述】
OIER们投资了一 支股票 大家都知道股票有赚赔,现给出 n天里这支股票的涨跌情况 ,
都为整数,涨为正 跌为负。
OIER 们想知道天数在s到e之间的这只股票涨跌最大连续和 。
【输入格式 】
从文件 invest.in中输入数据。 第一行有三个正整数 n、s和 e ,同上描述。 接下来有n行,每一个整数 ai ,组成数列的顺序不 可以变换。
【输出格式】
输出到文件invest.out中。输出长度在s和e之间连续的数列数的和的最大值。
做的时候用的滑动窗口 结果wa了60分 不如打暴力...。
正解是维护最大前缀和 对于一个起点来说合法的串是i +s~i + e
所以在这个区间内用线段树维护一个最大前缀和 再减去sum[i - 1]即可
代码
#include <bits/stdc++.h> #define oo 1000000000 using namespace std; typedef long long ll; const int N = 1e6 + 5; ll ans,sum[N],f[4 * N]; int n,s,e,a[N],que[2 * N],head,tail; void update(int o) { f[o] = max(f[2 * o],f[2 * o + 1]); } void build(int o,int l,int r) { if(l == r) { f[o] = sum[l]; return ; } int mid = (l + r) >> 1; build(2 * o,l,mid); build(2 * o + 1,mid + 1,r); update(o); } ll query(int o,int l,int r,int L,int R) { if(l >= L && r <= R) return f[o]; int mid = (l + r) >> 1; ll ans = -oo; if(L <= mid) ans = max(ans,query(2 * o,l,mid,L,R)); if(mid < R) ans = max(ans,query(2 * o + 1,mid + 1,r,L,R)); return ans; } int main( ) { freopen("invest.in","r",stdin); freopen("invest.out","w",stdout); scanf("%d%d%d",& n,& s,& e); for(int i = 0;i < 4 * N;i ++) f[i] = -oo; for(int i = 1;i <= n;i ++) { scanf("%d",& a[i]); sum[i] = sum[i - 1] + a[i]; } ans = -oo; build(1,1,n); for(int i = 1;i <= n;i ++) { if(i + s - 1 > n) break; ll qq = query(1,1,n,i + s - 1,min(i + e - 1,n)); ans = max(ans,qq - sum[i - 1]); } printf("%I64d",ans); return 0; }
游戏
【问题描述】
艾利斯顿商学院篮球队要参加一年度的市比赛了。拉拉队是篮球比赛的一个看点,
好队往能帮助球增加士气赢得最终比赛。所以作为队长的楚雨荨同学知道,
帮助篮球训练好有多么重要。选拔工作已经结束, 在雨荨和校长挑选下n位集优秀的身材、
舞技于一体的美女从众多报名生中脱颖而出。这些将随着篮球队小伙子们一起,和对手抗衡,
为艾利斯顿篮球队加油助威。一个阳光明媚的早晨雨荨带领队员们开始了排练。
n个女生从左到右排成一行,每人手中都举了写 有 26 个小写字母中的某一牌子,
在比赛时候挥舞为伙们呐喊、加油。雨荨发现,
如果连续的一段女生有奇数个并且他们手中牌子所写字母,从左到右和读起来一样,
那么这段女生就被称作和谐小群体。现在雨荨想找出所有和谐小群体,
并且按照女生的个数降序排之后前K个和谐小群体的女生个数乘积是多少。由于答案可能很大,
雨荨只要你告诉她谐小群体的女生个数乘积是多少。由于答案可能很大,
雨荨只要你告诉她案除以 19930726 的余数是多少就行了。
【输入格式】
从文件rehearse .in 中输入 数据。
第一行为两个正整数 n和 K,代表的东西在题目描述中已经叙。接下来一 行为 n个字符,
代表从左到右女生拿的牌子上写母。
【输出格式】
输出到文件rehearse .out .out中。 输出一个整数,
代表题目描述中所写的乘积除以 19930726 的余数,如果总 的和谐小群体个数于 K,输出一个整数 -1。
考试的时候基本是把正解给弄出来了的 然而我没写过manacher 我就自己乱yy了一个
wa了好几个点 t了3个点 还有统计答案的时候不够优秀
答题思路就是manacher + 差分树状数组 + 快速幂
代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e6 + 5; const ll mod = 19930726; int n,f[N],t[N],mi,cent = 0; char s[N]; ll c[N],k; int lowbit(int i) { return (i)&(-i); } void add(int pos,ll val) { while(pos <= n) { c[pos] += val; pos += lowbit(pos); } } ll query(int pos) { ll ans = 0; while(pos >= 1) { ans += c[pos]; pos -= lowbit(pos); } return ans; } ll fast_pow(ll a,ll b) { ll ans = 1; for(;b;b >>= 1,a = (a * a) % mod) if(b & 1) ans = (ans * a) % mod; return ans; } void manacher( ) { s[0] = '-'; s[n + 1] = '+'; for(int i = 1;i <= n;i ++) { if(i <= mi) f[i] = min(mi - i, f[cent * 2 - i]); else f[i] = 0; while(s[i - f[i] - 1] == s[i + f[i] + 1]) f[i]++; if(i + f[i] > mi) { mi = i + f[i]; cent = i; } add(1,1); add(1 + f[i] * 2 + 1,-1); } } void solve( ) { ll sum = 0,ans = 1; int st = n; if(st % 2 == 0) st --; for(int i = st;i >= 1;i -= 2) { ll num = query(i); if(sum + num >= k) { ans = ans * fast_pow(i,k - sum) % mod; sum = k; printf("%I64d",ans); break; } else { ans = ans * fast_pow(i,num) % mod; sum += num; } } if(sum < k) printf("-1"); } int main( ) { freopen("rehearse.in","r",stdin); freopen("rehearse.out","w",stdout); scanf("%d%I64d",& n,& k); scanf("%s",s + 1); manacher( ); solve( ); }