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 ,s∈S , i ≠ j , s≠ Pre ( s)
其中,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(){;}