吉林省信息学奥赛 2017 冬令营
day2
嗯 今天题目好水
嗯 今天爆零了好伤心......
值得纪念。
三道题读错了两道,T3瞎贪心只过了样例。
这就NOIP了,长点心吧。
OIER 密码
【问题描述】
吉林省的 OIER 们保密意识很强,总是将信息加密。
有一个仅含小写字母的字符串,我们把它按如下方法加密:
步骤 1:把所有连续的相同字母都用一个字母代替。比如 aaabbbb 被替换为
ab。
步骤 2:在随机的位置插入两个相同的小写字母。重复 步骤 2 很多次。
下面是一个加密的实例
初始字符串 jjjlloooiieerr
执行步骤 1 之后变成 jloier
插入 aa 之后变成 jloiaaer
插入 bb 之后变成 jloiabbaer
插入 ll 之后变成 jllloiabbaer
现在我们给定加密后的字符串,求执行 步骤 1 之后的字符串是什么。
【输入格式】
从文件 password.in 中输入数据。
一个字符串,表示加密后的字符串。
【输出格式】
输出到文件 password.out 中。
一个字符串,表示执行 步骤 1 之后的字符串。
【样例输入】
jllloiabbaer
【样例输出】
jloier
【数据规模与约定】
对于 30%数据, 加密后的字符串的长度<=1000
对于 70%数据, 加密后的字符串的长度<=100000
对于 100%数据, 加密后的字符串的长度<=1000000
/* 话说这个题确实没问题? 如果加密后的字符串是aaaabcdefgaaaa std给出的结果是bcdefg但如果第一次加密完是abcdefg然后第二次加密恰好都是在首尾加了a呢? 是不是也可以...因为第一步消除的是连续的相同字母. abcdefg中a并不连续啊。那为何输出bcdefg? 思想还是很好的,类似括号匹配 用栈实现。 下面粘出std */ #include <cstdio> #include <cstring> #include <iostream> #include <stack> #include <vector> #include <algorithm> using namespace std; int a[1000001]; char s[1000001], in[1000001]; bool cant[1000001]; int n; vector<char> ans; stack<char> S; int main() { // freopen("password.in", "r", stdin); //freopen("password.out", "w", stdout); gets(s + 1); n = strlen(s + 1); for (int i = 1; i <= n; i++) if (S.size() && S.top() == s[i]) S.pop(); else S.push(s[i]); while(S.size()) ans.push_back(S.top()), S.pop(); reverse(ans.begin(), ans.end()); for (int i = 0; i < (int)ans.size(); i++) putchar(ans[i]); }
投资
【问题描述】
吉林省的 OIER 们投资了一支股票,大家都知道股票有赚有赔,现给出 n 天
里这支股票的涨跌情况,都为整数,涨为正,跌为负。OIER 们想知道天数在 s
到 e 之间的这只股票涨跌的最大连续和 。
【输入格式】
从文件 invest.in 中输入数据。
第一行有三个正整数 n、s 和 e ,同上描述。
接下来有 n 行,每行一个整数 ai,组成数列,数列的顺序不可以变换。
【输出格式】
输出到文件 invest.out 中。
输出长度在 s 和 e 之间连续的数列数的和的最大值。
【样例输入】
6 2 4
4
-3
9
12
-8
9
【样例输出】
22
【数据规模与约定】
对于 30%数据,1<=s<=e<=n<=100
对于 100%数据,1<=s<=e<=n<=100000
对于 100%数据,-10000<=ai<=10000
/* 单调队列...可惜我并没有读懂题目,用线段树写了0分 题意是让着求长度为 l~r 的最大子段和 首先可以从l开始枚举i,i-l就是右端点,i-r就是左端点 答案就是 Max(sum[i]-min(sum[x])) (l<=x<=y) 用单调队列维护min(sum[x]) */ #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; int n,x,y; int q[110000]; int sum[110000]; int f[110000]; int l=1,r; int ans=-10000000; int main() { freopen("invest.in","r",stdin); freopen("invest.out","w",stdout); scanf("%d%d%d",&n,&x,&y); for(int i=1;i<=n;i++) { int tmp; scanf("%d",&tmp); sum[i]=sum[i-1]+tmp; } for(int i=x;i<=n;i++) { while(l<=r&&sum[q[r]]>=sum[i-x])r--; q[++r]=i-x; while(l<=r&&q[l]<i-y)l++; //q[l]是枚举的区间起点,i-y是左端点 不在范围内 l++ f[i]=sum[i]-sum[q[l]]; ans=max(ans,f[i]); } printf("%d",ans); fclose(stdin); fclose(stdout); return 0; }
学习 计划
【问题描述】
吉林省 OIER 们都是爱学习的同学,所以他们想学习更多的课程。长春市教
育局开设了“云课程”网络学习平台,一共有 n 门课程,但这个平台有个弊端,就
是每门课程在时间 Ti 之后将不再开放,并且每门课程要想学会需要 Ci 的时间,
聪明的你帮助吉林省 OIER 们计划一下,使他们能够学习最多的课程。
【输入格式】
从文件 plan.in 中输入数据。
第一行,一个整数 n
下面 n 行,每行两个数 Ti 和 Ci
【输出格式】
输出到文件 plan.out 中。
一行 一个整数,完成的最多任务数。
【样例输入】
4
5 1
3 2
7 6
1 1
【样例输出】
3
【数据规模与约定】
对于 30%数据,n<=100
对于 100%数据,n<=100000
/* 因为有每个都有时间限制,所以容易想到按时间限制先排个序 然后模拟,并且维护一个优先队列记录加入元素的使用时间 如果当前使用时间总和大于下一个的开放时间,就弹出对首 用队首和当前的所需时间作比较,更新答案并加入更小的那个。 */ #include<iostream> #include<queue> #include<cstdio> #include<algorithm> #define N 100001 using namespace std; priority_queue<int>q; int n,s,ans; struct node { int Ti,ci; }a[N]; bool cmp(node x,node y) { return x.Ti<y.Ti; } int main() { freopen("plan.in","r",stdin); freopen("plan.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&a[i].Ti,&a[i].ci); sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++) { if(a[i].ci>a[i].Ti) continue; if(s+a[i].ci<=a[i].Ti) { ans++; s+=a[i].ci; q.push(a[i].ci); } else if(a[i].ci<q.top()) { s-=q.top();s+=a[i].ci; q.pop();q.push(a[i].ci); } } printf("%d\n",ans); return 0; }