掉分经过##

难得这次时间比较好,下午17:35开始。

本来还很高兴,心想这回肯定不会犯困,没准排名能再上升一些呢,,可惜事与愿违……

上来a题,光看懂题就花了一些时间。

然后开始写,结果第一遍CE,第二遍WA……

出师不利啊!气急败坏,暂时放弃。

然后看b题。

惊喜地发现这类似的题我做过,大概是个bfs?嗯dp也行?

结果发现\(n \leq 10^9\)...真不妙。

这时来了个有关a题的通知,于是又回去看a题。

终于找到之前代码中的问题了,过了pretest

接着c和d题做的还算顺利,1个小时时都过了pretest

剩一个小时,3道题。

e和f看完都没什么好的想法,e想用区间dp,f想用线段树,但好像都不太行……

我又开始慌了……呜哇哇哇啊呀呀呀……

于是又回去看b题

发现居然有约1700人过了b的pretest,我猜这肯定不是道难题。

可能是个鬼畜的贪心?

嗯,想啊想啊想才终于想出来。

交了一发,TLE...又一发,WA...第三发,过了。

此时离比赛结束还有6分钟……

好了,安心下楼吃晚饭吧。

于是,就这样,比了最颓的一场cf...

终测4道题都过了,但由于太慢了,所以排名哗哗向下掉啊…QwQ


题解##

A. Points on the line###

定义一个集合diameter为该集合中的 最大数-最小数

给定一个n元素的集合与 d,求最少去掉原集合中多少个数后该集合的diameter不超过d

输入的所有数据皆\(\leq100\)

想法###

枚举集合中最后剩下的最大值

用这个最大值-d得到集合中可剩下的最小值

找出要去掉的数最少的即可。

代码###

#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; const int N = 105; int cnt[N],a[N];
int n,k; int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
cnt[0]=0;
for(int i=1;i<=n;i++) cnt[a[i]]++;
for(int i=1;i<=100;i++) cnt[i]+=cnt[i-1]; if(n==1) { printf("0\n"); return 0;} int ans=n,f;
for(int i=n;i>0;i--){
if(a[i]>k) ans=min(ans,n-cnt[a[i]]+cnt[a[i]-k-1]);
else ans=min(ans,n-cnt[a[i]]);
}
printf("%d\n",ans); return 0;
}

B. Our Tanya is Crying Out Loud###

给定n,k,A,B

设x一开始等于n

x每减1的代价为A,x每/k(前提为x是k的倍数)的代价为B

求将x变为1所需的最小代价

所有输入数据\(\leq 10^9\)

想法一###

dp[i]表示从n变到i的最小代价

dp[i]=min{dp[i+1]+A,dp[i \(\dots\) k]+B}

但n太大了,时间空间都不行。

想法二###

贪心。

先把x不断减1直到x为k的倍数

我们发现,若要x变成x/k,直接/k的代价比一点点减还大的话,直接减,一直减到1就行了,否则直接/k

循环这个过程

代码###

贪心

#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; typedef long long ll;
const int N = 1000000005; int n,k,A,B; int main()
{
scanf("%d%d%d%d",&n,&k,&A,&B); ll ans=0;
int x=n,y;
while(x>1){
if(x%k==0) {
if((ll)B>=((ll)x-x/k)*A) {
ans+=(ll)A*(x-1);
x=1;
}
else {
ans+=B;
x=x/k;
}
}
else {
y=max(((x-1)/k)*k,1);
ans+=((ll)x-y)*A;
x=y;
}
}
printf("%lld\n",ans); return 0;
}

C. Phone Numbers###

给定n,k及一个长度为n的字符串s

求一个长度为k的字符串t,t由出现在s中的字母组成,且t为满足条件的字典序比s大的第一个字符串。

想法###

贪心。

若k>n,则直接在字符串s后面补上k-n个s中的最小字符即可

否则从后面的位往前考虑,看是否能变为一个更大的字符。若可以,便变成比它大的第一个字符,后面位都变成s中的最小字符。

代码###

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring> using namespace std; const int N = 100005; char s[N];
int n,k,t;
int cnt[30],num[30];
int ans[N]; int main()
{
char ch;
scanf("%d%d",&n,&k);
scanf("%s",s);
for(int i=0;i<n;i++) cnt[s[i]-'a'+1]=1;
for(int i=1;i<=26;i++) cnt[i]+=cnt[i-1];
t=cnt[26];
for(int i=0;i<n;i++) num[cnt[s[i]-'a'+1]]=s[i]-'a'+1; if(k<=n){
for(int i=0;i<k;i++) ans[i]=cnt[s[i]-'a'+1];
for(int i=k-1;i>=0;i--){
if(ans[i]+1<=t){
ans[i]++;
break;
}
ans[i]=1;
}
for(int i=0;i<k;i++){
ch=num[ans[i]]-1+'a';
cout<<ch;
}
}
else{
for(int i=0;i<n;i++) ans[i]=cnt[s[i]-'a'+1];
for(int i=n;i<k;i++) ans[i]=1;
for(int i=0;i<k;i++){
ch=num[ans[i]]-1+'a';
cout<<ch;
}
} return 0;
}

D. Alena And The Heater###

有两个长度为n的数组a[]和b[],其中b[]由01组成

b[1]=b[2]=b[3]=b[4]=0

有l与r

对于所有 5 ≤ i ≤ n

当 a[i], a[i - 1], a[i - 2], a[i - 3], a[i - 4] > r 且 b[i - 1] = b[i - 2] = b[i - 3] = b[i - 4] = 1时 b[i]=0

当 a[i], a[i - 1], a[i - 2], a[i - 3], a[i - 4] < l 且 b[i - 1] = b[i - 2] = b[i - 3] = b[i - 4] = 0时 b[i]=1

否则b[i]=b[i-1]

给定a[]与b[],求一组合法的l,r

想法###

从左到右扫b数组

一开始令 l=-INF,r=INF

若存在“00001”的情况,则 l > max{a[i], a[i - 1], a[i - 2], a[i - 3], a[i - 4] }

若存在“11110”的情况,则 r < min{a[i], a[i - 1], a[i - 2], a[i - 3], a[i - 4] }

不断更新l,r即可

代码###

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring> using namespace std; const int N = 100005; int a[N];
char b[N];
int n; int maxn(int x){
int ret=-1000000000;
for(int i=0;i<5;i++)
ret=max(ret,a[x-i]);
return ret;
}
int minn(int x){
return min(a[x],min(a[x-1],min(a[x-2],min(a[x-3],a[x-4]))));
} int main(
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
scanf("%s",b); int l=-1000000000,r=1000000000,f=0;
for(int i=0;i<n;i++){
if(f<4) f++;
else{
if(b[i]=='1' && b[i-1]=='0'){
l=max(l,maxn(i)+1);
f=1;
}
else if(b[i]=='0' && b[i-1]=='1'){
r=min(r,minn(i)-1);
f=1;
}
}
}
printf("%d %d\n",l,r); return 0;
}

E. Cashback###

给定一个n元素的数组a[],给定一个数c

规定对于一个k元素的数组b[],其价值为b[]中所有元素的和 - 其中前\(\lfloor \frac{k}{c} \rfloor\)小的元素的和

将a数组分为若干个连续的子数组,求这些子数组的价值和的最小值

\(n \leq 10^5\)

想法###

贪心。

价值和最小,即去掉的前\(\lfloor \frac{k}{c} \rfloor\)小的元素的和最大

我们可以发现,若有一个长度为2c的子数组,那么考虑这个子数组前2小的两个元素i与j

若i与j同在这个子数组的前一半或后一半,那么将这个子数组分为两个长度为c的子子数组价值和会更小

若它们一个在前一半,一个在后一半,那么可以直接将这个子数组分为前后两部分。

故将a数组划分成的子数组长度为1或c

dp+单调队列优化即可

代码###

#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; typedef long long ll;
const int N = 100005; int a[N];
ll sum[N],f[N];
int que[N],head,tail;
int n,c; int main()
{
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
} for(int i=1;i<=n;i++){
f[i]=f[i-1]+a[i];
while(head<tail && que[head]<=i-c) head++;
while(head<tail && a[que[tail-1]]>=a[i]) tail--;
que[tail++]=i;
if(i>=c) f[i]=min(f[i],f[i-c]+sum[i]-sum[i-c]-a[que[head]]);
}
printf("%lld\n",f[n]); return 0;
}

F. Machine Learning###

给定一个数组a[],维护下面两种操作:

1.求一段区间[l,r]的mex

2.将a[p]的值改为x

假设在某区间中每个数出现的次数为cnt[i]

这个区间mex为cnt[]中不存在的最小的正整数

想法###

当时比赛的时候还不知道莫队算法

后来才发现原来这就是个带修改莫队的模板题

代码###

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<map> using namespace std; const int N = 200005; int read(){
char ch=getchar();
int x=0;
if(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x;
} int block;
inline int bl(int x) { return (x-1)/block+1; } struct que{
int l,r,tim,id;
bool operator < (const que &b) const{
return bl(l)<bl(b.l) || (bl(l)==bl(b.l) && bl(r)<bl(b.r)) || (bl(l)==bl(b.l) && bl(r)==bl(b.r) && tim<b.tim);
}
}q[N];
struct cg{
int id,fr,to;
}d[N]; int n,m,cnt1,cnt2;
int a[N];
map<int,int> num;
int nn; int size[N],cnt[N],L,R;
void add(int x){
size[cnt[x]]--;
size[++cnt[x]]++;
}
void del(int x){
size[cnt[x]]--;
size[--cnt[x]]++;
}
void cg_add(cg w){
if(L<=w.id && w.id<=R){
del(w.fr);
add(w.to);
}
a[w.id]=w.to;
}
void cg_del(cg w){
if(L<=w.id && w.id<=R){
del(w.to);
add(w.fr);
}
a[w.id]=w.fr;
} int ans[N];
inline int query(){
for(int i=1;i<=n;i++)
if(size[i]==0) return i;
} int main()
{
int opt,x,y;
n=read(); m=read();
for(int i=1;i<=n;i++) {
a[i]=read();
if(!num[a[i]]) num[a[i]]=++nn;
a[i]=num[a[i]];
}
for(int i=1;i<=m;i++){
opt=read(); x=read(); y=read();
if(opt==1) q[++cnt1]=(que){x,y,cnt2,cnt1};
else{
if(!num[y]) num[y]=++nn;
y=num[y];
d[++cnt2]=(cg){x,a[x],y};
a[x]=y;
}
} block=pow(n,0.666);
sort(q+1,q+1+cnt1); L=1; R=0;
int t=cnt2;
for(int i=1;i<=cnt1;i++){
while(R<q[i].r) add(a[++R]);
while(L>q[i].l) add(a[--L]);
while(R>q[i].r) del(a[R--]);
while(L<q[i].l) del(a[L++]);
while(t>q[i].tim) cg_del(d[t--]);
while(t<q[i].tim) cg_add(d[++t]); ans[q[i].id]=query();
}
for(int i=1;i<=cnt1;i++) printf("%d\n",ans[i]); return 0;
}

终于……

最新文章

  1. osx 编译安装配置 ruby on rails
  2. MFC 设置控件事件对应的函数
  3. JavaScript数组API
  4. thinkpad E450 fn快捷键设置
  5. MD5 加密的两种方法
  6. MSCRM 仪表盘 控件 数量 更改(Change the maximum no. of controls on MSCRM Dashboards )
  7. 如何编写Iveely搜索引擎插件
  8. JS实现动画原理一(闭包方式)
  9. iOS使用NSMutableAttributedString 实现富文本(不同颜色字体、下划线等)
  10. Python 统计IIS日志行数
  11. php-fpm 的安装与LNMP测试
  12. Injecting and Binding Objects to Spring MVC Controllers--转
  13. Android显示YUV图像
  14. 理光C5502A 打印模糊问题
  15. [翻译 EF Core in Action] 1.5 关于NoSql
  16. Error: Invoke-customs are only supported starting with Android O (--min-api 26)
  17. Jenkins 改成中文语言显示
  18. 基于Ubuntu的ESP32平台搭建
  19. 类Exception_A继承Exception,类Exception_B继承Exception_A,请问执行此段代码的输出是什么?
  20. recyclerView插入(add)和删除(remove)item后,item错乱,重复,覆盖在原recyclerView上

热门文章

  1. C# 如何写 DEBUG 输出
  2. EJB实例
  3. Linux 内核 标准 PCI 配置寄存器
  4. Linux 内核
  5. Eclipse GlassFish Server 配置
  6. 爬虫工程师的unidbg入门教程
  7. clickhouse创建视图SQL 错误 [47]: ClickHouse exception, code: 47
  8. STM32 命名方法
  9. 缓存一致性协议(MESI)
  10. 洛谷$P2055\ [ZJOI2009]$ 假期的宿舍 最大流