Luogu八月月赛都结束了我才来补七月月赛git
此次月赛仍是很狗的,在绍一的晚上恰逢刮台风,而后直接打到一半断网了数组
结果都没有交上去GG数据结构
感受此次难度适中,解法也比较清新天然吧,十分给个九分一分由于没的打ide
好了下面开始看题。优化
目的:送分,坑罚时spa
一道比较SB的题目,尤为注意题目中一个信息:code
保证对于一个数字,其在\(b_i\)中出现的次数很少于在\(a_i\)中出现的次数。get
而后咱们发现这个式子的本质就是一些数的乘积,咱们讨论一下最后的结果:string
固然你不能傻乎乎地直接把一堆数乘起来,你又不是Pythonit
咱们离散化一下,而后用相似于桶同样的操做便可实现消去
CODE
#include<cstdio> #include<cctype> #include<algorithm> #include<cstring> using namespace std; typedef long long LL; const LL N=100005; LL a[N],b[N],r[N<<1],t1[N<<1],t2[N<<1],tot,n,m,t,cnt,num; bool flag; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(LL &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline void clear(void) { memset(t1,0,sizeof(t1)); memset(t2,0,sizeof(t2)); cnt=tot=num=0; flag=1; } inline LL find(LL x) { LL L=1,R=cnt; while (L<=R) { LL mid=(L+R)/2; if (r[mid]==x) return mid; if (r[mid]>x) R=mid-1; else L=mid+1; } } inline bool is_prime(LL x) { if (x==1) return 0; for (register int i=2;i*i<=x;++i) if (x%i==0) return 0; return 1; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register LL i; read(t); while (t--) { clear(); read(n); read(m); for (i=1;i<=n;++i) read(a[i]),r[++cnt]=a[i]; for (i=1;i<=m;++i) read(b[i]),r[++cnt]=b[i]; sort(r+1,r+cnt+1); cnt=unique(r+1,r+cnt+1)-r-1; for (i=1;i<=n;++i) ++t1[find(a[i])]; for (i=1;i<=m;++i) ++t2[find(b[i])]; for (i=1;i<=cnt;++i) if (t1[i]-t2[i]==1) { if (!num) num=r[i]; else { flag=0; break; } } else if (t1[i]!=t2[i]) { flag=0; break; } if (!flag||!num) puts("NO"); else puts(is_prime(num)?"YES":"NO"); } return 0; }
目的:送分,连罚时都骗不到
话说这题问什么蓝了,我以为黄题都过了
看到题目和陈潇然大佬讨论了一波以为直接贪心地跳,每次选择一个最近的且大于\(S\)的跳一下便可。
具体的证实感受真的不须要:
对于一段岩石\(i\in[l,r]\),若\(w_r-w_l<S\),因为来回一次的限制,中间的石块便没法被跳完。
所以如有解,咱们只须要按上面的方法作便可。
感受没什么坑点,5min码完1A固然是赛后
CODE
#include<cstdio> #include<cctype> using namespace std; const int N=100005; int n,m,s,lst,cnt,ans[N],pre[N],dis,tot,x; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline void write(int x) { if (x>9) write(x/10); putchar(x%10+'0'); } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i; read(n); read(m); read(s); for (pre[1]=0,tot=1,i=1;i<=m;++i) { read(x); if (x-lst>=s) ans[++cnt]=i,lst=x; else if (x-dis<s) return puts("NO"),0; else pre[++tot]=i,dis=x; } if (n-lst>=s) ans[++cnt]=i; else return puts("NO"),0; for (puts("YES"),i=1;i<=cnt;++i) write(ans[i]),putchar(' '); for (i=tot;i>=1;--i) write(pre[i]),putchar(' '); return 0; }
目的:拉分题,考验脑洞和思惟
因为数据范围咱们想到二分,但不是常规的二分时间,由于这样咱们很难直接判断
考虑二分被减的时间点。接下来咱们先把题目的菜气减去被打掉的值。
这里忍不住又%一发出题人,把一个细节的数据\(w_i+r_{v_i}\le w_{i+1}\)藏的这么深
因此咱们发现菜气被打掉以后老是能够涨回来的,因而直接贪心大力加便可。
考虑当前的这个点不知足,那么尽可能向右选择便可。
CODE
#include<cstdio> #include<cctype> #include<cstring> using namespace std; const int N=5e5+5; int n,m,k,s,a[N],x,w[N],num[N],v[N],t[N],ans,d[N]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline int work(int x) { register int i; int tot=0,step=0; memcpy(t,a,sizeof(t)); memset(d,0,sizeof(d)); for (i=1;i<=x;++i) t[num[i]]-=v[i]; for (i=1;i<=n;++i) { if (t[i]+tot<1) { int dlt=1-t[i]-tot; step+=dlt; tot+=dlt; if (d[i+k-1]<=n) d[i+k-1]+=dlt; } tot-=d[i]; } return step>w[x]?step:w[x]; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i; read(n); read(m); read(k); read(s); for (i=1;i<=n;++i) read(a[i]); for (i=1;i<=s;++i) read(x); for (i=1;i<=m;++i) read(w[i]),read(num[i]),read(v[i]); int l=0,r=m,mid; w[m+1]=1e9; while (l<=r) { mid=l+r>>1; if (work(mid)<w[mid+1]) ans=mid,r=mid-1; else l=mid+1; } return printf("%d",work(ans)),0; }
目的:毒瘤数据结构,打压选手的信心
看到题目发现\(O(n^2)\)的暴力是naive的,考虑优化。
因为最近作过相似的题目,我就直接考虑当\(a_i\)为一个区间\(i\in[l,r]\)中的最大值时,对答案的贡献
首先两边是能够直接用单调栈\(O(n)\)搞出来的。
借鉴一下启发式的思想,咱们每一次以\(i\)为中心把区间分红左右两边,并挑选数字个数少的一边直接枚举
同时在另外一边的记录询问(注意这里的询问至关与求小于某一个数的数的数量)这个能够树状数组存一下
考虑咱们把全部的操做都放到最后,渐进意义下指望的时间和空间复杂度都是控制在\(O(n\ logn)\)的范围内的(好像有大佬能证实更少)
因此最后扫一次在树状数组上跑而且统计便可,注意区间计算以后要及时删除
复杂度是很迷的\(O(n\ log^2n)\),结果不吸氧也能过
CODE
#include<cstdio> #include<cctype> #include<algorithm> #include<vector> #define pb push_back using namespace std; const int N=100005; int n,a[N],b[N],stack[N],top,front[N],back[N],num[N],tot,bit[N]; vector <int> d[N]; long long ans; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline void insert(int now,int opt) { if (opt) { d[now].pb(1); d[front[now]-1].pb(-1); for (register int i=now+1;i<=back[now];++i) d[now].pb(a[now]/a[i]),d[front[now]-1].pb(-a[now]/a[i]); } else { d[back[now]].pb(1); d[now-1].pb(-1); for (register int i=front[now];i<now;++i) d[back[now]].pb(a[now]/a[i]),d[now-1].pb(-a[now]/a[i]); } } inline int abs(int x) { return x>0?x:-x; } inline int lowbit(int x) { return x&-x; } inline void add(int x) { while (x<=n) ++bit[x],x+=lowbit(x); } inline int get(int x) { int tot=0; while (x) tot+=bit[x],x-=lowbit(x); return tot; } inline int same_find(int x) { int l=1,r=tot; while (l<=r) { int mid=l+r>>1; if (b[mid]==x) return mid; if (b[mid]<x) l=mid+1; else r=mid-1; } } inline int lower_find(int x) { int l=1,r=tot,res; while (l<=r) { int mid=l+r>>1; if (b[mid]<=x) res=mid,l=mid+1; else r=mid-1; } return res; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i,j; read(n); for (i=1;i<=n;++i) read(a[i]),b[i]=a[i]; for (i=1;i<=n;++i) { while (top&&stack[top]<=a[i]) --top; front[i]=top?num[top]+1:1; stack[++top]=a[i]; num[top]=i; } for (top=0,i=n;i>=1;--i) { while (top&&stack[top]<a[i]) --top; back[i]=top?num[top]-1:n; stack[++top]=a[i]; num[top]=i; } for (i=1;i<=n;++i) if (i-front[i]<=back[i]-i) insert(i,0); else insert(i,1); sort(b+1,b+n+1); tot=unique(b+1,b+n+1)-b-1; for (i=1;i<=n;++i) { add(same_find(a[i])); for (j=0;j<d[i].size();++j) { int s=lower_find(abs(d[i][j])); ans+=d[i][j]>0?get(s):-get(s); } } return printf("%lld",ans),0; }
E题凸包弃疗,感受作不动
整体还能够吧,挺喜欢此次月赛的
但愿下次不要断网了