2021.9.23
T1:Project LeaF
Problem:
YLCH 发现这是一首由n个音符组成的乐曲,经过 YLCH 的无数次实地考察,他发现自己对于每一个音符,都有pi的概率在此音符获得Perfect,否则,由于 YLCH 太菜了,他将得到一个小姐(Miss)。游戏为了 YLCH 的每一次得分,造了一个长为n的0/1串S,若Si =1则表示他在第i个音符获得了Perfect,否则则表示 YLCH得到了一个小姐。
接下来,游戏将这样计算他的基础分(A为给定常数):BasicScore=A*∑(i=1~n)Si
这样计算他的连击分数(B为给定常数):ComboScore=B*∑(i=1~n) Si *combo(i)
其中,combo是一个定义如下的函数(t为给定常数):
combo(i)= Si i=1
combo(i-1)+1 i≠1 and Si=1
combo(i-1)*t otherwise
则最后他的总分计算为:TotalScore=BasicScore+ComboScore
众所周知,YLCH 的手机容易断触,所以总共有q次神奇的事件发生,事件的类型有两种:
- 0 x wa wb,表示将原来的概率px修改为wa / wb;
- 1 l r,表示询问在这首曲子的l到r的音符组成的片段内,YLCH 的期望得分。
对于每次1操作,输出其结果对1e8+7取模的结果。
Solution:
BasicScore = A * ∑(i=l~r) pi
设Ei为combo(i)的期望:ComboScore = B * ∑(i=l~r) pi * (Ei-1 +1)
原因是,显然Si =1 才能得到combo(i),故combo(i)显然就是i-1的期望+1。
考虑如何得到Ei显然可以递推,通过Ei-1转移得到,考虑当前是否为1,有:Ei =pi * (Ei-1 +1)+(1-pi )* Ei-1 * t
化简,得:Ei =(pi +t-pi * t) * Ei-1 +pi
发现是一个关于Ei-1 的一次函数形式,故ComboScore也是一个一次函数。
换元,得:Er =k * El-1 +b
ComboScore(l,r)=Σ k * El-1 +Σ b
考虑用线段树维护区间[l,r]的概率和sump(用于计算BasicScore,维护上式中的k,b,sumk,sumb用于计算ComboScore即可。
考虑为什么这样维护,发现显然右区间的 l-1 等于左区间的 r,信息具有可并性,可以用线段树进行快速合并。
最后询问 [l,r] 的答案即为A * sump(l,r) + B * sumb(l,r)。
Code:
1 #include<bits/stdc++.h> 2 #define re register 3 #define rint re int 4 using namespace std; 5 typedef long long ll; 6 typedef pair<int,int> P; 7 #define rll re ll 8 #define rqwq re qwq 9 template<class T> 10 void Swap(T &x,T &y){ 11 T z=x; 12 x=y; 13 y=z; 14 } 15 #define PairOP 16 #ifdef PairOP 17 template<class T1,class T2> 18 inline const pair<T1,T2> operator + (const pair<T1,T2> &p1,const pair<T1,T2> &p2){ 19 return pair<T1,T2>(p1.first+p2.first,p1.second+p2.second); 20 } 21 template<class T1,class T2> 22 inline const pair<T1,T2> operator - (const pair<T1,T2> &p1,const pair<T1,T2> &p2){ 23 return pair<T1,T2>(p1.first-p2.first,p1.second-p2.second); 24 } 25 #endif 26 #ifdef FastIO 27 char buf[1<<21],*p1,*p2; 28 #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 29 #endif 30 template<class T> 31 T Read(){ 32 T x=0,f=1; 33 char ch=getchar(); 34 while(ch<'0'||ch>'9'){ 35 if(ch=='-') 36 f=-1; 37 ch=getchar(); 38 } 39 while(ch>='0'&&ch<='9'){ 40 x=(x<<1)+(x<<3)+(ch^'0'); 41 ch=getchar(); 42 } 43 return x*f; 44 } 45 ll (*readll)()=Read<ll>; 46 #define read Read<int> 47 #define int long long 48 const int N=5e5+5,mod=1e8+7; 49 int n,m,op,l,r,A,B,T,ta,tb,x,y,a[N]; 50 inline int ksm(rint a,rint b){ 51 rint res=1; 52 while(b){ 53 if(b&1) res=res*a%mod; 54 a=a*a%mod,b>>=1; 55 } 56 return res; 57 } 58 class SegmentTree{ 59 private: 60 class Node{ 61 public: 62 int sump,k,b,sumb,sumk; 63 }t[N<<2]; 64 #define mid (l+((r-l)>>1)) 65 #define ls (p<<1) 66 #define rs (p<<1|1) 67 inline void Pushup(rint p){ 68 t[p].sump=(t[ls].sump+t[rs].sump)%mod; 69 t[p].k=(t[ls].k*t[rs].k)%mod; 70 t[p].b=(t[rs].k*t[ls].b%mod+t[rs].b)%mod; 71 t[p].sumk=(t[rs].sumk*t[ls].k%mod+t[ls].sumk)%mod; 72 t[p].sumb=(t[rs].sumk*t[ls].b%mod+t[ls].sumb+t[rs].sumb)%mod; 73 } 74 public: 75 inline void Build(rint p,rint l,rint r){ 76 if(l==r) return t[p].sump=t[p].b=t[p].sumk=t[p].sumb=a[l],t[p].k=(a[l]+T+mod-a[l]*T%mod)%mod,void(); 77 Build(ls,l,mid),Build(rs,mid+1,r),Pushup(p); 78 } 79 inline void Change(rint p,rint l,rint r,rint pos,rint k){ 80 if(l>pos||r<pos) return ; 81 if(l==r) return t[p].sump=t[p].b=t[p].sumk=t[p].sumb=k,t[p].k=(k+T+mod-k*T%mod)%mod,void(); 82 Change(ls,l,mid,pos,k),Change(rs,mid+1,r,pos,k),Pushup(p); 83 } 84 inline P Ask(rint p,rint l,rint r,rint x,rint y){ 85 if(l>y||r<x) return P(0,0); 86 if(l>=x&&r<=y) return P(t[p].sump,t[p].sumb); 87 P res=Ask(ls,l,mid,x,y)+Ask(rs,mid+1,r,x,y); 88 return Pushup(p),res; 89 } 90 }t; 91 inline int True(){ 92 #ifdef Clock 93 rint STR=clock(); 94 #endif 95 read(),n=read(),m=read(),ta=read(),tb=read(),A=read(),B=read(),T=ta*ksm(tb,mod-2)%mod; 96 for(rint i=1,x,y;i<=n;++i) x=read(),y=read(),a[i]=x*ksm(y,mod-2)%mod; 97 t.Build(1,1,n); 98 for(rint i=1;i<=m;++i){ 99 rint op=read(); 100 if(!op){ 101 rint pos=read(),x=read(),y=read(),k=x*ksm(y,mod-2)%mod; 102 t.Change(1,1,n,pos,k); 103 } 104 else{ 105 rint x=read(),y=read();P res=t.Ask(1,1,n,x,y); 106 printf("%lld\n",(A*res.first%mod+B*res.second%mod)%mod); 107 } 108 } 109 #ifdef Clock 110 rint END=clock(); 111 printf("Time:%dms\n",int((END-STR)/(qwq)CLOCKS_PER_SEC*1000)); 112 printf("Time:%ds\n",int((END-STR)/(qwq)CLOCKS_PER_SEC)); 113 #endif 114 return (0-0); 115 } 116 int Love=True(); 117 signed main(){;}
T2:JOJOI Tower
Problem:
JOIOI 塔是一种单人游戏。
这个游戏要用到一些写有J,O,I中任一文字的圆盘。这些圆盘的直径互不相同。游戏开始时,这些圆盘按照直径大的在下面的规则堆叠。你需要用这些圆盘做尽量多的迷你 JOIOI 塔。迷你 JOIOI 塔由3个圆盘构成,从直径较小的圆盘开始分别为J,O,I或分别为I,O,I。不过,每个圆盘最多只能使用一次。
现在给出长为N的字符串S,表示直径从小到大的圆盘上的文字。请编写程序求出使用这些圆盘能够做出的迷你JOIOI 塔个数的最大值。
Solution:
考虑二分答案,那么问题就变成了能不能组合出x个 JOI/IOI,考虑贪心判定,倒着做,统计没组成 OI/JOI/IOI 的 I 的个数 cnt,已经组成 OI 串,没有组成 JOI/IOI 串的个数 tot,以及 JOI/IOI 的个数 ans 。则,对于 J,显然直接找到一个 OI 组成答案,对于 O,显然直接找 I 组成 OI,对于 I,需要贪心,发现只需要造 mid 个 OI,多了会浪费,故若目前的 cnt+tot+ans>=mid则得到答案,否则,把这个 I 放到 OI 串中即可。
Code:
1 #include<bits/stdc++.h> 2 using namespace std; 3 string s; 4 int n; 5 inline bool check(int x){ 6 int cnt=0,tot=0,ans=0; 7 for(int i=n-1;i>=0;i--){ 8 if(s[i]=='I'){ 9 if(cnt+tot+ans>=x){ 10 if(tot>0){ 11 tot--; 12 ans++; 13 } 14 } 15 else cnt++; 16 } 17 if(s[i]=='O'){ 18 if(cnt>0){ 19 cnt--; 20 tot++; 21 } 22 } 23 if(s[i]=='J'){ 24 if(tot>0){ 25 tot--; 26 ans++; 27 } 28 } 29 } 30 if(ans>=x) return 1; 31 return 0; 32 } 33 int main(){ 34 cin>>n>>s; 35 int l=0,r=n/3,ans; 36 while(l<=r){ 37 int mid=(l+r)>>1; 38 if(check(mid)){ 39 ans=mid; 40 l=mid+1; 41 } 42 else r=mid-1; 43 } 44 cout<<ans; 45 return 0; 46 }
T3:炉心融解
Problem:
YLCH 的面前有n个核反应堆{ai},这n个同属一种能量类型,能量类型有三种——与,或,异或。其中,每两个反应堆都有一个能量值f(i,j)=ai opt aj ,其中,opt为三种运算符中的一种。
为了防止出现炉心融解事故,现在,YLCH 想让你分别求出,对于每个反应堆的最大能量值:
g(i)=max(res=1~i-1) f(ai ,ares),i∈[2,n] 的答案g(i),以及对于每个i本身,满足g(i)相等的res的个数。
Solution:
考虑dp,发现暴力复杂度为O(216 n)。
考虑某次初赛的最后一道题,分前八位和后八位计算的那个状压dp,把思路搬过来。
设 f[i][j] 表示前8位状态为 i,后8位状态为 j 的最大值。
则加入一个数 x 时,设它的前八位为 a,后八位为 b,则只需枚举 j 用 j op b 更新所有 f[a][j] 即可。
查询时,只需枚举 i,用所有的(i op a)<<8 | f[i][b]更新答案即可。
复杂度O(28 n)能过。
Code:
1 #include<bits/stdc++.h> 2 #define awa 2147483647 3 #define re register 4 #define rint re int 5 using namespace std; 6 typedef long long ll; 7 typedef double qwq; 8 #define rll re ll 9 #define rqwq re qwq 10 template<class T> 11 void Swap(T &x,T &y){ 12 T z=x; 13 x=y; 14 y=z; 15 } 16 #ifdef PairOP 17 template<class T1,class T2> 18 inline const pair<T1,T2> operator + (const pair<T1,T2> &p1,const pair<T1,T2> &p2){ 19 return pair<T1,T2>(p1.first+p2.first,p1.second+p2.second); 20 } 21 template<class T1,class T2> 22 inline const pair<T1,T2> operator - (const pair<T1,T2> &p1,const pair<T1,T2> &p2){ 23 return pair<T1,T2>(p1.first-p2.first,p1.second-p2.second); 24 } 25 #endif 26 #ifdef FastIO 27 char buf[1<<21],*p1,*p2; 28 #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 29 #endif 30 template<class T> 31 T Read(){ 32 T x=0,f=1; 33 char ch=getchar(); 34 while(ch<'0'||ch>'9'){ 35 if(ch=='-') 36 f=-1; 37 ch=getchar(); 38 } 39 while(ch>='0'&&ch<='9'){ 40 x=(x<<1)+(x<<3)+(ch^'0'); 41 ch=getchar(); 42 } 43 return x*f; 44 } 45 ll (*readll)()=Read<ll>; 46 #define read Read<int> 47 const int N=1e5+5; 48 int n,type,f[260][260],g[260][260],S=255,op; 49 inline int GetOp(){ 50 char ch=getchar(); 51 while(ch<'a'||ch>'z') ch=getchar(); 52 return ch=='a'?1:ch=='o'?2:3; 53 } 54 inline int F(rint x,rint y){ 55 return op==1?x&y:op==2?x|y:x^y; 56 } 57 inline int True(){ 58 #ifdef Clock 59 rint STR=clock(); 60 #endif 61 n=read(),op=GetOp(),type=read(),memset(f,0xcf,sizeof(f)); 62 for(rint k=1,now,x,y,maxx,cnt;k<=n;++k){ 63 x=read(),y=x&S,x>>=8,maxx=-awa,cnt=0; 64 for(rint i=0;i<=S;++i){ 65 now=f[x][i]+F(i,y); 66 if(now>maxx) maxx=now,cnt=0; 67 if(now==maxx) cnt+=g[x][i]; 68 } 69 for(rint i=0;i<=S;++i){ 70 now=F(i,x)<<8; 71 if(f[i][y]<now) f[i][y]=now,g[i][y]=0; 72 if(f[i][y]==now) g[i][y]++; 73 } 74 if(k>1) type?printf("%d %d\n",maxx,cnt):printf("%d\n",maxx); 75 } 76 #ifdef Clock 77 rint END=clock(); 78 printf("Time:%dms\n",int((END-STR)/(qwq)CLOCKS_PER_SEC*1000)); 79 printf("Time:%ds\n",int((END-STR)/(qwq)CLOCKS_PER_SEC)); 80 #endif 81 return (0-0); 82 } 83 int Love=True(); 84 signed main(){;}
T4:马赛克卷
Problem:
YLCH 喜欢马赛克卷,马赛克卷交错的马赛克共有n个,它们互不相同,YLCH 于是用一个二进制串集合S来表示。由于马赛克卷的作者爹扣非常喜欢火锅,所以马赛克卷为了让他下锅,规定了一个合法下锅的条件,对于一个马
赛克卷,若:任意si ,sj ∈S , i ≠ j , si ≠ Pre ( sj )
其中,Pre(x)表示x的前缀。
爹扣趁马赛克卷不在,窥探了一个马赛克卷的集合S,但是由于离得太远,对于每个si,爹扣可能看不清它的某一
位。
现在,爹扣想知道这个马赛克卷会不会让他下锅。
Solution:
翻译:给定 n 个01串,每个字符串至多有一位是未知的,可以填 0 或 1 ,求是否存在一种方案,使得任意一个字符串不是其它任意一个字符串的前缀。
发现每个串只有一个 ?,而 ? 只有两种状态(0/1),故考虑 2-SAT,发现是01串,故考虑 01trie 。
考虑建图,如果选某个串作为 trie 树上 所对应的节点,则显然 x 在树上的子树和祖先都不能选,否则组成前缀。
发现出现冲突关系,故考虑,对于trie上的边 ( fa , x ),连边fa->x,x->fa。同时,对于字符串 S 与它对应的点 x 连边 S->x,x->!S。
发现这样建图是O(n2)的。你可以使用多种暴力优化建图方式进行优化,比如线段树优化,倍增优化(不过这个题
貌似卡log的优化。
我们继续考虑这个题的性质,发现本题是在 trie 树上建边,只可能是父亲和儿子的连边,故具有单向性,可以使用前后缀优化建图,复杂度O(n)。
Code:
1 #include<bits/stdc++.h> 2 #define re register 3 #define rint re int 4 using namespace std; 5 typedef long long ll; 6 typedef double qwq; 7 template<class T> 8 void Swap(T &x,T &y){ 9 T z=x; 10 x=y; 11 y=z; 12 } 13 #ifdef PairOP 14 template<class T1,class T2> 15 inline const pair<T1,T2> operator + (const pair<T1,T2> &p1,const pair<T1,T2> &p2){ 16 return pair<T1,T2>(p1.first+p2.first,p1.second+p2.second); 17 } 18 template<class T1,class T2> 19 inline const pair<T1,T2> operator - (const pair<T1,T2> &p1,const pair<T1,T2> &p2){ 20 return pair<T1,T2>(p1.first-p2.first,p1.second-p2.second); 21 } 22 #endif 23 #ifdef FastIO 24 char buf[1<<21],*p1,*p2; 25 #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 26 #endif 27 template<class T> 28 T Read(){ 29 T x=0,f=1; 30 char ch=getchar(); 31 while(ch<'0'||ch>'9'){ 32 if(ch=='-') 33 f=-1; 34 ch=getchar(); 35 } 36 while(ch>='0'&&ch<='9'){ 37 x=(x<<1)+(x<<3)+(ch^'0'); 38 ch=getchar(); 39 } 40 return x*f; 41 } 42 ll (*readll)()=Read<ll>; 43 #define read Read<int> 44 const int N=3e6+5; 45 int n,head[N],nxt[N<<1],ver[N<<1],tot; 46 int dfn[N],low[N],stk[N],top,scc[N],num,cnt; 47 bool ins[N]; 48 inline void add (rint x,rint y){ 49 ver[++tot]=y,nxt[tot]=head[x],head[x]=tot,x^=1,y^=1; 50 ver[++tot]=x,nxt[tot]=head[y],head[y]=tot; 51 } 52 class Trie{ 53 private: 54 int tr[N][2],sz,now; 55 vector<int> p[N]; 56 inline void dfs(rint x,rint pre){ 57 for(rint y:p[x]){ 58 now+=2,add(now,y); 59 if(pre) add(now,pre),add(y^1,pre); 60 pre=now; 61 } 62 (tr[x][0])&&(dfs(tr[x][0],pre),1),(tr[x][1])&&(dfs(tr[x][1],pre),1); 63 } 64 public: 65 inline void Init(){sz=0;} 66 inline void Insert(int id,char *s){ 67 rint x=0; 68 for(rint i=0;s[i];i++){ 69 if(!tr[x][s[i]-'0']) tr[x][s[i]-'0']=++sz; 70 x=tr[x][s[i]-'0']; 71 } 72 p[x].push_back(id); 73 } 74 inline int Work(){ 75 now=(n-1)<<1,dfs(0,0); 76 return now+1; 77 } 78 }t; 79 inline void tarjan(rint x){ 80 dfn[x]=low[x]=++num,stk[++top]=x,ins[x]=1; 81 for(rint i=head[x];i;i=nxt[i]){ 82 rint y=ver[i]; 83 if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]); 84 else if(ins[y]) low[x]=min(low[x],dfn[y]); 85 } 86 if(low[x]==dfn[x]){ 87 rint y; 88 cnt++; 89 do y=stk[top--],ins[y]=0,scc[y]=cnt; while(y^x); 90 } 91 } 92 char s[N]; 93 inline int True(){ 94 #ifdef Clock 95 rint STR=clock(); 96 #endif 97 n=read(),t.Init(); 98 for(rint i=0,p;i<n;++i){ 99 scanf("%s",s),p=-1; 100 for(rint j=0;s[j];++j) if(s[j]=='?') <%p=j;break;%> 101 if(~p) s[p]='0',t.Insert(i<<1,s),s[p]='1',t.Insert(i<<1|1,s); 102 else t.Insert(i<<1,s),t.Insert(i<<1|1,s); 103 } 104 rint lim=t.Work(); 105 for(rint i=0;i<=lim;++i) if(!dfn[i]) tarjan(i); 106 for(rint i=0;i<(n<<1);i+=2) if(scc[i]==scc[i^1]) return !puts("Mosaic Roll!!"); 107 puts("DECO*27 love hotpot!!"); 108 #ifdef Clock 109 rint END=clock(); 110 printf("Time:%dms\n",int((END-STR)/(qwq)CLOCKS_PER_SEC*1000)); 111 printf("Time:%ds\n",int((END-STR)/(qwq)CLOCKS_PER_SEC)); 112 #endif 113 return (0-0); 114 } 115 int Love=True(); 116 signed main(){;}

浙公网安备 33010602011771号