题目绝不毒瘤,各位dalao可以慢慢享用
题目背景
政府出了新政策,特邀 OI 落后的乡村的教师来南方学习。于是,副村长LX就带着S老师和Refun老师, 踏上了飞向南方的飞机。。。。。。
当然,他们是去学(颓)习(废)的。
迷失沃尔玛
题目描述
到南方的第一天晚上,副村长 LX 就坐不住了!看着繁华的街市,副村长 LX 兴冲冲地去逛街买东西。可是她不小心在一座大商场沃尔玛迷路了。然而副村长 LX 很镇定,毕竟她已经迷路过几万次了,也不差这一次了。
在逛沃尔玛的时候,副村长LX发现了一排n个美丽的商品。每个商品都有自己的价格。LX 想从左往右挑选 X 个商品,使得它们的价格从左往右看,是单调上升的。如果有多种选择,她希望这些商品的“商品价格序”最小。
但LX不想动脑子,她还想留点精力找回去的路呢!作为吃瓜群众
的你,自然是要帮她一把了对吧!
注: “最小商品价格序”是指:假设你选择了A1、A2、A3/A4….Ax 这些商品,那么你要确保 A1 的权值最小,若不唯一,再确保 A2的权值最小……(即以权值为关键字的字典序)
输入格式
输入的第一行为一个整数n——商品的个数。
下一行n个整数,表示1~n号商品的价格。
下一行一个整数Q,表示Q次询问
接下来Q行, 每行有一个整数X, 表示询问长度为X的上升序列。
输出格式
输出为 Q 行,对于每个询问,如果对应的序列存在,则输出,否则打印LXALWAYSMISS
输入样例
10
8531 21017 12567 86 19807 30631 16280 25238 23448 4947
3
3
2
6
输出样例
86 16280 23448
86 4947
LXALWAYSMISS
数据规模与约定
对于30%的数据,1≤n≤100,1≤Q≤100
对于100%的数据,1≤n≤10000, 1≤Q≤1000,1≤Ai≤10000000
解题报告
在做这道题的时候,只想到了sort+dfs;原来使用unique去重,然后就是各种乱的搞搞搞,最后弃疗,交了一个裸体的暴力,10分。坐在我旁边的xmzl大佬埋头思索写了正解,大样例跑了0.3s。
不说废话:
求规定长度的单调上升子序列,并且要输出字典序最小的那一个。
想想最长上升子序列:f[i]: 表示在序列中以i结尾的序列里面的最长上升子序列的长度(从左往右),我们来换个思维——从右往左,f[i] 表示以i作为起点的后缀当中的最长升子序列的长度,这样就可以在贪心之前用NlogN的解法处理出来,保存在结构体当中。同时处理出整个序列的最长上升子序列的长度。
补充地,结构体里面保存的还有v和id。
下面进行贪心;
如果
- 这个点的往后的最长上升子序列的长度大于后面需要选的商品数量(即x-now,now表示当前的长度)
- 下一个点的id(即在原序列中的位置)大于上一个选的点的id
- 原题中要求价格是单调上升的,所以不能有重复
满足以上三点的时候,这个点就是可以输出的;
由于我们对v为第一关键字,id为第二关键字进行过排序了,所以每次选出的就是字典序最小的一种方案。贪心正确性得以证明。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=100001;
int n,m,x,f[maxn],q,ans[maxn],tot;
struct st{
int v,id,len;//v权值,id编号,len:i开头的最长上升子序列的长度
}a[maxn];
int read()
{
int now=0,f=1; char ch=getchar();
while (ch<'1' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0' && ch<='9')
{
now=(now<<1)+(now<<3)+ch-'0';
ch=getchar();
}
return now*f;
}
bool cmp(st x,st y)
{
if (x.v==y.v) return x.id<y.id;
else return x.v<y.v;
}
int main()
{
freopen("misswalmart.in","r",stdin);
freopen("misswalmart.out","w",stdout);
n=read();
for (int i=1; i<=n; i++) a[i].v=read();
m=read();
for (int i=1; i<=n; i++) f[i]=1;
int maxx=-1;
for (int i=n; i>=1; i--)
{
for (int j=i+1; j<=n; j++)
if (a[i].v<a[j].v) f[i]=max(f[i],f[j]+1);
maxx=max(maxx,f[i]);
a[i].id=i; a[i].len=f[i];
}
sort(a+1,a+1+n,cmp);
while (m--)
{
int now=0,last=0,val=0;//放在while里面清零
x=read();
if (x>maxx) {printf("LXALWAYSMISS\n"); continue;}
for (int i=1; i<=n; i++)
{
if (now==x) break;
if (a[i].len>=x-now && a[i].id>a[last].id && a[i].v>a[last].v)
{
now++;
last=i;
printf("%d ",a[i].v);
}
}
printf("\n");
}
return 0;
}
总结:以后字典序云云可以想到排序
各种错误与漏洞百出
题目来源:[HAOI2007]上升序列
LX 还在迷路
题目描述
Refun: “副村长出去逛街好久一直不回来,肯定叕迷路了!我们怎么办?”
S老师: “我们得找她!不然回去咋跟全村人交代?”
S 老师和来到了天台,大手一挥,一部诺基亚砸到地上,地面破碎成n个奇怪的数,诡异地映射着黑夜的星空。
S老师捏着法诀,默念道: “苟……,岂……。 ”
渐渐地,地面上的数字开始变化。S老师紧张地说道: “需要时刻
得知数字的信息,才能判断副村长 LX 的位置!数字的每次变化,相当于操作:
Change:对于区间[l,r]进行操作。区间的第一个数加1,区间的第二个数加2……区间的第 x 个数加 x*(x+1)/2 ……区间的最后一个数加(r-l+1) * (r-l+2)/2
Refun: “那我需要做什么?”
S老师: “当我大声膜*的时候,你需要做操作:
Query l r: 查询区间[l,r]的和,并将答案对 1e9+7取膜!
注意了,最开始的时候,区间的所有数都是0.”
作为村里最神最厉害的Refun,快帮忙找找副村长吧!
输入格式
第一行两个整数 n 和 type,n 表示序列总长度。起初 n 个数都是0。type表示数据类型。
如果 type 是 1,则你需要对每次操作的 l,r 进行修改,newl=(l+lastans-1)%n+1,newr=(r+lastans-1)%n+1, 如果newl>newr,
则swap(newl,newr)。newl和newr才是本次操作的l和r。(刚开始lastans=0) (想用离线分块水过去?不存在的)
如果type是0,那你就不用修改l和r了。
第二行一个整数Q,表示有Q次操作
接下来Q行,每行是下面两种操作之一
Change l r : ·对于区间[l,r]进行操作。区间的第一个数加1区间的第二个数加 2*(2+1)/2.。。。。区间的第 x 个数加
x*(x+1)/2…..区间的最后一个数加 (r-l+1)*(r-l+2)/2
Query l r: 查询区间[l,r]的和,并将答案对 1e9+7取膜
输出格式
对于每个询问,输出相应答案。
输入样例 1 输入样例 2
5 0 5 1
6 6
Change 1 3 Change 1 3
Query 2 4 Query 2 4
Change 3 5 Change 3 5
Query 1 3 Query 1 3
Change 2 4 Change 2 4
Query 1 5 Query 1 5
输出样例 1 输出样例 2
9 9
11 19
30 6
解题报告
这里就把出题人的Sulotion扔一下,我太菜了搞不了
出题人原创题目,感谢生哥的验题
我们将n*(n+1)拆开,得到 n*n+n
我们把这一个操作看成两个操作:
①对[l,r] 每个点加 dis^2 (dis为该点到l的距离+1)
②对[l,r] 每个点加 dis
对于②号操作,就是线段树区间加等差数列,在此不多叙述。
我们去看第一个操作。
直接做的话,我们没法合并x^2的标记。我们考虑差分。
我们发现 n*n-(n-1)*(n-1)=2*n-1
如果是单点查询的话,我们只需要区间加一个等差数列 2*i-1,然后查询某个点的前缀和了。
但题目要求的是区间和,也就是说我们需要查询前缀和的前缀和。
(我知道看到这里你们一定是脸上笑嘻嘻心里MMP,默念着出题人毒瘤)
我们考虑每个点会被计算几次。假如我们查i∈[L,R],ans=∑Sum[i]
a[1]~a[L]算了R-L+1次
a[L+1]算了R-L次
。。。。。
a[R]算了1次
我们定义C(l,r)的意思是:
C(l,r)=
a[l]+a[l+1]+a[l+2]+……+a[r]
+a[l+1]+a[l+2]+……+a[r]
…+a[r];我们考虑线段树的查询过程,答案只会在某个区间[l,r]∈[L,R]时被计算。
那么实际上这个区间对答案的贡献应该是:
∑a[1~l-1] * (r-l+1)+C(l,r)
然后我们惊奇地发现实际上C(l,r)是可以维护的!可以进行pushdown和update 的!
那我们只需要去维护这个C(l,r)即可!
那这道题就解决了!
标记永久化的代码
std
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define o 200005
using namespace std;
const ll Mod=1e9+7;
ll inv2,inv6;
ll S[o],S2[o],W[o];
ll ksm(ll a,ll b,ll p){
ll ans=1;
for(;b;b>>=1,a=a*a%p) if(b&1) ans=ans*a%p;
return ans;
}
struct T11{
struct tree1{
ll a,b,Sum;
}T[o*4];
inline void update(int now,int l,int r){
T[now].Sum=T[now<<1].Sum+T[now<<1|1].Sum;T[now].Sum%=Mod;
if(!T[now].a&&!T[now].b) return;
ll n=W[r-l+1];
T[now].Sum+=(T[now].a*n%Mod+T[now].b*S[n]%Mod)%Mod;T[now].Sum%=Mod;
}
void change(int now,int l,int r,int left,int right,ll a,ll b){
if(left<=l&&r<=right){
T[now].a+=a;T[now].a%=Mod;
T[now].b+=b;T[now].b%=Mod;
update(now,l,r);
return;
}
int mid=(l+r)>>1;
if(left<=mid) change(now<<1,l,mid,left,right,a,b);
if(mid<right) change(now<<1|1,mid+1,r,left,right,(a+W[max(mid-max(left,l)+1,0)]*b%Mod)%Mod,b);
update(now,l,r);
}
ll Query(int now,int l,int r,int left,int right,ll a,ll b){
if(left<=l&&r<=right) return (T[now].Sum+a*W[r-l+1]%Mod+b*S[r-l+1]%Mod)%Mod;
int mid=(l+r)>>1; ll answer=0;
a=(a+T[now].a)%Mod;b=(b+T[now].b)%Mod;
if(left<=mid)
answer=(answer+Query(now<<1,l,mid,left,right,a,b))%Mod;
if(mid<right)
answer=(answer+Query(now<<1|1,mid+1,r,left,right,(a+b*W[mid-l+1]%Mod)%Mod,b))%Mod;
return answer;
}
}T1;
struct T22{
struct tree3{
ll a,b,Sum,Sum_2;
}T[o*4];
inline void update(int now,int l,int r){
int mid=(l+r)>>1;
T[now].Sum=T[now<<1].Sum+T[now<<1|1].Sum;T[now].Sum%=Mod;
T[now].Sum_2=T[now<<1].Sum_2+T[now<<1|1].Sum_2;T[now].Sum_2%=Mod;
T[now].Sum_2+=T[now<<1].Sum*(ll)(r-mid)%Mod;T[now].Sum_2%=Mod;
if(!T[now].a&&!T[now].b) return;
ll n=W[r-l+1];
T[now].Sum+=(T[now].a*n%Mod+T[now].b*S[n]%Mod)%Mod;T[now].Sum%=Mod;
T[now].Sum_2+=T[now].a*S[n]%Mod+T[now].b*S[n]%Mod*(n+1)%Mod - S2[n]* T[now].b%Mod;
T[now].Sum_2%=Mod;
}
void change(int now,int l,int r,int left,int right,ll a,ll b){
if(left<=l&&r<=right){
T[now].a+=a;T[now].a%=Mod;
T[now].b+=b;T[now].b%=Mod;
update(now,l,r);
return;
}
int mid=(l+r)>>1;
if(left<=mid) change(now<<1,l,mid,left,right,a,b);
if(mid<right) change(now<<1|1,mid+1,r,left,right,(a+W[max(mid-max(left,l)+1,0)]*b%Mod)%Mod,b);
update(now,l,r);
}
ll Query(int now,int l,int r,int left,int right,ll s,ll a,ll b){
if(left<=l&&r<=right){
ll n=W[r-l+1];
return (s*n%Mod+T[now].Sum_2+a*S[n]%Mod+b*S[n]%Mod*(n+1)%Mod - S2[n]*b%Mod)%Mod;
}
int mid=(l+r)>>1; ll answer=0;
a=(a+T[now].a)%Mod;b=(b+T[now].b)%Mod;
if(left<=mid) answer=(answer+Query(now<<1,l,mid,left,right,s,a,b))%Mod;
if(mid<right) answer=(answer+Query(now<<1|1,mid+1,r,left,right,(s+T[now<<1].Sum+a*W[(mid+1-l)]%Mod+b*S[mid+1-l])%Mod,(a+b*W[mid-l+1]%Mod)%Mod,b))%Mod;
return answer;
}
}T2;
int n,type,Q,l,r;
ll lastans;
char s[100];
int main(){
freopen("stillmiss.in","r",stdin);
freopen("stillmiss.out","w",stdout);
scanf("%d%d",&n,&type);
scanf("%d",&Q);
inv2=ksm(2ll,Mod-2,Mod);
inv6=ksm(6ll,Mod-2,Mod);
S[1]=1,S2[1]=1,W[1]=1;
for(ll i=2;i<=n;i++) {
W[i]=i;
S[i]=(S[i-1]+i)%Mod;
S2[i]=(S2[i-1]+i*i%Mod)%Mod;
}
for(int i=1;i<=Q;i++){
scanf("%s",s);
scanf("%d%d",&l,&r);
if(type){
l=(l+lastans-1)%n+1;
r=(r+lastans-1)%n+1;
if(l>r)swap(l,r);
}
if(s[0]=='C'){
T1.change(1,1,n,l,r,0,1);
T2.change(1,1,n,l,r,-1,2);
if(r!=n){
ll nn=(ll)(r-l+1);
T2.change(1,1,n,r+1,r+1,-nn*nn%Mod,0);
}
}
else{
ll ans=(T1.Query(1,1,n,l,r,0,0)+T2.Query(1,1,n,l,r,0,0,0))%Mod;
ans=ans*inv2%Mod;
ans=(ans%Mod+Mod)%Mod;
lastans=ans%n;
printf("%lld\n",ans);
}
}
return 0;
}
未来
题目描述
何为未来?魔塔即是未来。
在机器人修引擎的时候,船长正在玩一座魔塔。
这是一道提交答案题。
魔塔的信息 future.txt 已下发,文件的第一部分是 10 个 11*11
的矩阵,依次表示第1~9层以及boss层的地图,接下来12行描述怪
物信息,依次对应怪物a~怪物l,每行六个数,依次表示攻击力,防
御力, 生命值, 特殊能力编号, 杀死获得金币数, 能否被炸弹消灭(1/0)。
对于地图的解释如下:
# 一堵墙,无法通过
. 空地,可以通过
A 一扇黄门,打开需要耗费一把黄钥匙
B 一扇蓝门,打开需要耗费一把蓝钥匙
C 一扇红门,打开需要耗费一把红钥匙
D 一把黄钥匙
E 一把蓝钥匙
F 一把红钥匙
G 红宝石,加3攻击力
H 蓝宝石,加3防御力
I 绿宝石,加5魔防
J 破墙镐,可以用来消去面前的一格墙
K 炸弹,可以用来炸死面前的一个怪物
L 一把剑,装备后加10攻击力
M 一个盾,装备后加10防御力
N 一把圣剑,装备后加50攻击力
O 一个圣盾,装备后加50防御力
P 小血瓶,+100生命
Q 中血瓶,+200生命
R 大血瓶,+500生命
S 超血瓶,+1000生命
T 传送到下一层(当前层+1)的与T所在位置同一位置
U 传送到上一层(当前层-1)的与U所在位置同一位置
V 传送到boss层的同一位置
W 解毒药水,使用后解除中毒状态
X 幸运金币,获得后打怪金币加倍
Y 特殊门,杀死以其为中心的九宫格内所有怪物后自动消失
Z 特殊门,杀死怪物g后自动消失
* 减少8金币,若金币不足8则游戏失败
0 初始的位置,视为空格
a~l 对应12种怪物,杀死怪物l后游戏胜利
所有非TUV的非空格事件触发后会变为空格
TUV均视为一次移动,会触发中毒伤害
与怪物的战斗解释如下:
初始时你攻击力为10,防御力为10,生命值为500,魔防为0
每回合伤害为 max(己方攻击-对方防御,0),设你打死对方需要 k
回合,你受到的总伤害为max((k-1)*对方每回合伤害-你的魔防,0)
怪物属性介绍如下:
0 这个怪物十分咸鱼,没有任何特殊能力
1 战斗后,勇士处于中毒状态,每次移动将损失5点生命
8 怪物防御=max(怪物原本防御,勇士攻击-1)
16 战斗时,怪物优先攻击,即伤害计算公式里的k++
64 战斗时,你的防御视为0
128 战斗时,怪物每回合攻击两次,即伤害公式里的k*=2
512 战斗时,怪物附加你的防御两倍作为额外伤害
输出格式:
future.out 中应该包含一个长度不超过 100000 的字符串表示你的路线,每个字符的含义如下:
W 转向上侧
A 转向左侧
S 转向下侧
D 转向右侧
Q 触发面对方向的事件,面前必须有事件,若面前为门事件则必
须有对应的钥匙
E 向面对方向移动一格,面前必须是空格
Z 装备/卸下剑,必须有剑
X 装备/卸下圣剑,必须有圣剑
N 装备/卸下盾,必须有盾
M 装备/卸下圣盾,必须有圣盾
C 使用炸弹,必须有炸弹,面前必须是可以被炸炸死的怪物
V 使用破墙镐,必须有破墙镐,面前必须是墙
B 使用解毒药水,必须有解毒药水
开始时默认朝向上侧
一些解释:
checker.cpp已下发,它将从同一目录下的future.out读取数据
并给出一定的反馈,你可以根据做题的需要对其进行修改。
注意checker.cpp的运行需要用到同一目录下的future.txt
如对题目仍有疑问,可参考checker.cpp理解或询问出题人。
最终评测使用的 special judge 会根据 checker 给出的过关生命
及过关金币数给出得分,具体来说如下:
若你没有过关,得分为0,否则,若你的金币数不足360,你的得
分为10+[(你的金币数/360)^30*60], 否则, 设标程的过关生命为s,
你的得分为10+60+[你的生命/s*30]。
本题最终提交时,只需提交 future.out
解题报告
AEQDEEQAESEQWEDEWEQEAQSEAQEEWEQEEEEEDQEQAEQESQEEQWEEAQEQEESQDEEESEEDEQEEESQAEEEEWEEDEQAEESEEEDQEQEWQAEESEEEQEEDQSEDQWEEEEEEEEEDEQAEESEEDEEEESEQEEEQDQEQEEWQAEWQAEEWEEEEAEEEESEAQEEQSQDEEWEEEDEQAEESEEEEEEDEEEQEEWQEDEQESEQEEAQEESQDEEWEEEAEESEAEEEEEWEEEEAQEQEESQEQDESQWEDEESEEEEDEEEEEWEDEESEEEQEQWEAEESEEAQEEWEQSEDEEWEEDEEWEEEAEESEAEEEEEWEEEEEEDEQAEESEEDEEEESEEEAQEESQEEQEEQAEQDQWESQWQEEQEEQDQEEWQAEEWEAQEQESQDEESEEEEQWEEEEEDEEWEEEAEEEEWEEDEQAEESEEEEEEDEEEEEWEQEQEDEEWQAEESEEEAEEEEEWEEEEEEDEQAEESEEDEEEESEEEAEESEEEEQWEEEEEAEEWEEQEEQEDVEQSEQEQEEQEEQWEEEEEQAEESEEEEEDEESEEEEQWEEEEEDEEWEEDEQEWQEEAQSEEAEESEEAEESEEEEQWESQAEQEEEQDEEEQWEEEEDEEQEQEQAEEEEWEAEEWEEAQEQEWEQEQSEEEQEQWEEDEESEEDEESEEEEQAEEEWQEQEDEWQEQSEAEEEWQEEDQSEEDEESEEDEEQWESQWEEEEEDEEWEEEAEEEEWEEDEQAEESEEEEEEDEEEEEWEEEDEEWEQEEAQEQEESQDEEESEEEAEESEEEAEEEEESEEAQEQEESQDEEEWEEEEEEEEDEQAEESEEDEEEESEEEAEESEEEEQDEQEEQAEEQWEEEEEDEEWEEEAEEEEWEEDEQAEESEEAEEEWQEQDESEDEEWEEDEQAEESEEDEEEESEEEAEESEEEEQWEEEEDEEWEEDQEQBEQAEESEEAEEWEAEEWEEEEEDEQSEEEEAQSEEAQWEAEEEWQSQEAEQEWEQDQEEEEESEEQEEQWEQWEEQEQEQSEEEEDQEESQDEEEWQEEQSEEAEEEEEQEEEEEWQEEQSEEDEEEEEWEEEEEEZNQEQSEEEEEEEQWEEEEEEEEEQSQAEESEEEEEDEESEEEDQAQEQEQEESQEQWEDEEEESEQWEDQEQEEQEWQEDQSEQEDQWEAEEEESQWEEEEEAEEWEEEEEDEQSEEEEEEEEEQWEDEEEEESQWEEAEWQAEEWQAQSQEQEAQDQWEEDEEESEQWEAEEEEESQWEEEEEDEWQSQDEEQEEWQSQAEEWQSQAEEESEEEEQWEDEEEEESQWEEAEEEEWEAQEEWQEEDQEWQEQEAEWQEQEDQWEDQAQEEQESQEAQDQEWEDEESEEEDESEEAESEEDEEESEDEEEWEQEEEAEWQEEAQEQEWQSEQEQWEEDEEEWQEQEAQSEEAESEEDESEEEEEQWEAEEEEESQWEEEEEEEEEQAEESEEEEEDEESEEEEQWEEEEEDEEWEEEQAEEEEWEEDEQAEESEEEEEEDEEEEEWEEEAEWQDESEEEAEEWQEAQSQEWQSEAEEWEEEEEEDEQAEESEEEEDQEESEEEEEQWEEEEEEQDQEEEEWQEQEQDQEWQAESEEAEEEESEAEEWEEEEEDEQSEEEEEEEEEQWEDEEEEESQWEEAEEEEWEAEEEQEEWQENQNEDQAQWEEDQEESQAEWQEQEQEAQDQSEEEDEESEQEEQAQESQDEWEDEESQEEQEEQAQSEAQWEEEDEEWQEDEWQEDEESQEQEEEQEAQWEAQWEAQWEEEAEWQEEDQAEWQEQEEDQEQESQAEESEEEDESEEAESEAESEQEEQWEEAEEWEEAEEWEEAEEESEQDEEWQEQSEAEQSQEEQWEQDESEEAESQEQEDQSEDQEQEQEQEWQAEEEEWEEEDEEEEWEEQSEEDEEESEDEEEWEEEAQSEEEAEEEEWEAEEEEEWEEAQWEEDEEESEEEEAESEQEEAQEQDEWEEEEDEWEEEDQEEQWQSEAQDQSQEEQWEEQVEQAQDQSQ
没什么解题报告。只有yhzq学长A了这道题。然后学长萌直播在机房玩魔塔。
就是第一次见题答题吧。。。
考试总结
昨天和今天分别做了翔哥和舒老师的两场比赛,打的都不怎么样。
强的人还是很强,若的人还是很弱。
我执意要学OI是为了什么?是在今年的成绩并不是很好的里面混一个“泯然众人”?非常羡慕xMinh的乱搞想正解的能力。在考试过程中,我也不是没有认真思考,而是在心里默认自己想不出正解,往往是三道题的代码入门水平,草草暴力。
又会想起了退役时的痛苦,实在是不想退役了。