我好菜啊。。。。。。
%%%迪神AK
虽然考试成绩不太好,但至少能想到正解了,也不会菜到打不出暴力。
T1:想了半天不会,发现直接打高精可以拿到80分,就赶紧码完扔了,结果正解是利用double避免了高精运算
解法:%%迪神,高精压位,同时只记录前300位进行比较。
or利用double和除法,最后和1比较
or正解:double,对所有数取log再进行比较

1 #include2 #include 3 #include 4 #include 5 #include 6 #define LL double 7 #define N 1000050 8 using namespace std; 9 int x,y; 10 inline void work1() 11 { 12 LL a1=1,a2=0.0; 13 a1=1.0*y*log(x); 14 for(int i=1;i<=y;++i)a2+=1.0*log((double)i); 15 if(a1>a2)puts("No"); 16 else puts("Yes"); 17 } 18 int main() 19 { 20 freopen("yuuutsu.in","r",stdin); 21 freopen("yuuutsu.out","w",stdout); 22 int T;scanf("%d",&T); 23 while(T--) 24 { 25 scanf("%d%d",&x,&y); 26 work1(); 27 } 28 fclose(stdin);fclose(stdout); 29 }
T2:考场正解,细节打炸。将原数列差分掉,然后利用就可以将下标mod k进行操作了。
注意特判:差分的区间为左闭右开。所以当右端点为n+1时是可以随意加的。然而当左端点为0时不能随便加,因为是左闭右开呀

1 #include2 #include 3 #include 4 #include 5 #define LL long long 6 #define N 2000050 7 #define re register 8 using namespace std; 9 LL s1[N]; 10 inline int read() 11 { 12 int s=0,b=0;char c=getchar(); 13 while(c>'9'||c<'0'){if(c=='-')b=1;c=getchar();} 14 while(c>='0'&&c<='9')s=s*10+c-'0',c=getchar(); 15 if(b)return -s; 16 return s; 17 } 18 int n,k,m; 19 int a[N],al,pd[N]; 20 inline void add(int pos,int val) 21 { 22 pos%=k; 23 if(pd[pos])return; 24 if(s1[pos]==-val){s1[pos]=0;--al;return;} 25 if(!s1[pos]){s1[pos]=val;++al;return;} 26 s1[pos]+=val; 27 } 28 int main() 29 { 30 freopen("august.in","r",stdin); 31 freopen("august.out","w",stdout); 32 n=read(),k=read(),m=read(); 33 for(register int i=1;i<=n;++i)a[i]=read(); 34 for(register int i=n;i;--i) 35 a[i]-=a[i-1],s1[i%k]+=a[i]; 36 pd[(n+1)%k]=1; 37 for(int i=0;i i){ 38 if(pd[i])continue; 39 if(s1[i])++al; 40 } 41 if(al)puts("No"); 42 else puts("Yes"); 43 for(int i=1,x,y;i<=m;++i) 44 { 45 x=read();y=read(); 46 if(y){add(x,y);add(x+1,-y);} 47 if(al)puts("No"); 48 else puts("Yes"); 49 } 50 fclose(stdin);fclose(stdout); 51 }
T3:这题好好写一下。
考场上先打出了暴力,然后考虑加优化。
暴力:
1 for(int i=1,lca;i<=n;++i) 2 { 3 lca=a[i];ans+=c[lca]; 4 for(int j=i-1;j;--j){ 5 lca=LCA(lca,a[j]); 6 ans+=c[lca]; 7 } 8 }
暴力枚举右端点,发现左端点在一段区间内时lca是一定的。
那么这个东西可以用链表来维护。
链表记录lca的值(id)和这个lca对应左端点的数量(ct)
统计答案直接ct*id即可。
然而这种打法还是会被一条链的数据卡掉
深入挖掘它的性质。每插入一个新的右端点,会把链表内所有节点更新到新端点的祖先链上。(显然
那么新加入的节点就一定会加到链表的队尾。且设当前加入的为a[j],那么a[j]和a[j-1]的lca之前的点是共用的。
那么不断利用a[j]和a[j-1]的lca去弹掉链表的队尾。最后在队尾加入a[j]和a[j-1]的lca和a[j]即可
考虑在每个节点再维护一个答案的前缀和(an)
a[j]和a[j-1]的lca之前的所有的节点内所有东西(id,ct,an)都不变。
那么直接更新a[j]和a[j-1]的lca和a[j]的答案即可。
流程:
新开节点,插入队尾,在队中删除不合法的节点并更新a[j]和a[j-1]的lca控制区间长度。

1 #include2 #define LL long long 3 #define re register 4 #define N 200050 5 using namespace std; 6 inline int read() 7 { 8 int s=0,b=0;char c=getchar(); 9 while(c>'9'||c<'0'){if(c=='-')b=1;c=getchar();} 10 while(c>='0'&&c<='9')s=s*10+c-'0',c=getchar(); 11 if(b)return -s; 12 return s; 13 } 14 int n,m,a[N],c[N],kkk,num; 15 struct node{int pre,ne,ct,id;LL an;}li[N*10]; 16 LL ans; 17 int he[N],ne[N],to[N],fa[N],tot; 18 inline void addedge(int x,int y){to[++tot]=y;ne[tot]=he[x];he[x]=tot;} 19 int tp[N],dep[N],dfl[N],dfr[N],sz[N],hs[N],cnt; 20 int po[N]; 21 inline void dfs1(int g) 22 { 23 dep[g]=dep[fa[g]]+1;sz[g]=1; 24 for(int i=he[g];i;i=ne[i]) 25 { 26 dfs1(to[i]); 27 if(sz[to[i]]>sz[hs[g]])hs[g]=to[i]; 28 sz[g]+=sz[to[i]]; 29 } 30 } 31 inline void dfs2(int g) 32 { 33 dfl[g]=dfr[g]=++cnt; 34 po[cnt]=g; 35 if(hs[fa[g]]==g)tp[g]=tp[fa[g]]; 36 else tp[g]=g; 37 if(hs[g])dfs2(hs[g]); 38 for(int i=he[g];i;i=ne[i]) 39 if(to[i]!=hs[g])dfs2(to[i]); 40 dfr[g]=cnt; 41 } 42 inline int LCA(int x,int y) 43 { 44 if(dep[x]>dep[y])swap(x,y); 45 if(dfl[x]<=dfl[y]&&dfr[x]>=dfl[y])return x; 46 while(tp[x]!=tp[y]) 47 { 48 if(dep[tp[x]]>dep[tp[y]])swap(x,y); 49 y=fa[tp[y]]; 50 } 51 if(dep[x]>dep[y])return y; 52 else return x; 53 } 54 inline void del(int x) 55 { 56 int a1=li[x].pre,a2=li[x].ne; 57 if(a1)li[a1].ne=a2; 58 if(a2)li[a2].pre=a1; 59 if(!a2)kkk=a1; 60 } 61 int main() 62 { 63 freopen("sagittarius.in","r",stdin);freopen("sagittarius.out","w",stdout); 64 n=read(); 65 for(int i=2;i<=n;++i){fa[i]=read();addedge(fa[i],i);} 66 dfs1(1);dfs2(1); 67 for(int i=1;i<=n;++i)a[i]=read(); 68 for(int i=1;i<=n;++i)c[i]=read(); 69 ans+=c[a[1]];li[++num].ct=1; 70 li[num].id=a[1];kkk=num; 71 li[num].an=c[a[1]]; 72 for(int j=2;j<=n;++j){ 73 li[++num].id=a[j];li[num].ct=1; 74 li[kkk].ne=num;li[num].pre=kkk; 75 kkk=num;int i,t; 76 for(i=li[kkk].pre;i;i=li[i].pre){ 77 t=LCA(li[i].id,li[li[i].ne].id); 78 if(t!=li[i].id){li[i].id=t; 79 if(li[i].id==li[li[i].ne].id){ 80 li[i].ct+=li[li[i].ne].ct; 81 del(li[i].ne); 82 } 83 } 84 else { 85 if(li[i].id==li[li[i].ne].id){ 86 li[i].ct+=li[li[i].ne].ct; 87 del(li[i].ne); 88 } 89 break; 90 } 91 } 92 if(!i)i=1; 93 for(;i;i=li[i].ne)li[i].an=li[li[i].pre].an+1ll*c[li[i].id]*li[i].ct; 94 ans+=li[kkk].an; 95 } 96 cout< endl; 97 }
复杂度证明:在每个点最多插入两个节点,每个节点被删除一次。复杂度为O(n)
但由于还要求lca,复杂度变为O(nlogn)。(然而你用tarjan求lca做到O(n)我也没意见)