NOI前的考试日志

 4.14 网络流专项测试

先看T1,不会,看T2,仙人掌???wtf??弃疗。看T3,貌似最可做了,然后开始刚,刚了30min无果,打了50分暴力,然后接着去看T1,把序列差分了一下,推了会式子,发现是傻逼费用流,然后码码码,码完秒过大样例,觉得比较稳,又肉眼查了会错,就放了。然后接着推T3,发现我会做一个限制条件的,貌似和T1差不多,然后就写了,感觉能多骗点分,之后看了看T2,发现30裸树剖,30裸最大流,然后码码码。最后查了会错,发现T1没开long long,赶紧改了。100+44+63=207 rank1/5。T2挂了12分,不知道为什么,真的是静态仙人掌裸题,T3比较巧妙。

T1,差分之后每个本来就满足条件的位置有一个可以贡献的流量从S连过来,不满足条件的位置有一个需要的流量连向T。然后每种操作可以连接两个距离为l的位置,然后直接最小费用最大流即可,判断无解可以看最大流是不是等于我们需要的流量。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <deque>
 7 #define inf 0x3fffffff
 8 #define N 250
 9 using namespace std;
10 int e=2,head[N];
11 struct edge{
12     int u,v,f,w,next;
13 }ed[N*N<<1];
14 void add(int u,int v,int f,int w){
15     ed[e].u=u;ed[e].v=v;ed[e].f=f;ed[e].w=w;
16     ed[e].next=head[u];head[u]=e++;
17     ed[e].u=v;ed[e].v=u;ed[e].f=0;ed[e].w=-w; 
18     ed[e].next=head[v];head[v]=e++;
19 }
20 int dis[N],pre[N],bo[N],tim,S,T;
21 int sum,n,m,a[N],b[N];
22 bool spfa(){
23     memset(dis,0x3f,sizeof dis);
24     tim++;
25     deque<int> q;q.push_front(S);dis[S]=0;
26     while(!q.empty()){
27         int x=q.front();q.pop_front();bo[x]=0;
28         for(int i=head[x];i;i=ed[i].next){
29             int v=ed[i].v;
30             if(ed[i].f&&dis[v]>dis[x]+ed[i].w){
31                 dis[v]=dis[x]+ed[i].w;pre[v]=i;
32                 if(bo[v]!=tim){
33                     bo[v]=tim;
34                     if(!q.empty()&&dis[v]<dis[q.front()])q.push_front(v);
35                     else q.push_back(v);
36                 }
37             }
38         }
39     }
40     return dis[T]!=dis[T+1];
41 }
42 long long ans=0;
43 int dfs(int x,int f){
44     bo[x]=tim;
45     int now=0;
46     if(x==T){
47         ans+=1ll*f*dis[T];
48         return f;
49     }
50     for(int i=head[x];i;i=ed[i].next){
51         if(ed[i].f&&dis[ed[i].v]==dis[x]+ed[i].w&&bo[ed[i].v]!=tim){
52             int nxt=dfs(ed[i].v,min(f,ed[i].f));
53             now+=nxt;f-=nxt;ed[i].f-=nxt;ed[i^1].f+=nxt;
54             if(!f)break;
55         }
56     }
57     return now;
58 }
59 void work(){
60     int flow=0;
61     while(spfa()){
62         do{
63             tim++;
64             flow+=dfs(S,inf);
65         }while(bo[T]==tim);
66     }
67     if(flow!=sum)puts("-1");
68     else printf("%lld\n",ans);
69 }
70 int main(){
71     // freopen("test.in","r",stdin);
72     scanf("%d%d",&n,&m);
73     S=n+1;T=S+1;
74     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
75     for(int i=1;i<n;i++){
76         b[i]=a[i+1]-a[i];
77         if(b[i]>0)add(S,i,b[i],0);
78         else add(i,T,-b[i],0),sum-=b[i];
79     }
80     add(S,0,inf,0);add(S,n,inf,0);
81     char o[5];
82     for(int i=1,l,c;i<=m;i++){
83         scanf("%s%d%d",o,&l,&c);
84         for(int j=0;j+l<=n;j++){
85             if(o[0]=='+')add(j+l,j,inf,c);
86             else add(j,j+l,inf,c);
87         }
88     }
89     work();
90     return 0;
91 }
View Code

T2,静态仙人掌裸题,咕咕咕。

T3,比较巧妙的一个费用流。我们先假设将所有的零件都放进去,这样可能会出现不合法的情况,我们还是考虑枚举,这里我们枚举每行/列的限制,然后我们将对应行和列之间连上(k,0)的边,代表最多有这么多不被删去,剩下的如果位置(i,j)是合法的,则从i行想j列连一条(1,1)的边,代表这个零件被删去了。然后每次我们跑的都是最小费用最大流,只需要判断是否满流以及最后的零件总数是不是满足条件。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <deque>
  5 #define N 88
  6 #define inf 0x3fffffff
  7 using namespace std;
  8 int e,head[N];
  9 struct edge{
 10     int u,v,f,w,next;
 11 }ed[N*N];
 12 void add(int u,int v,int f,int w){
 13     ed[e].u=u;ed[e].v=v;ed[e].f=f;ed[e].w=w;
 14     ed[e].next=head[u];head[u]=e++;
 15     ed[e].u=v;ed[e].v=u;ed[e].f=0;ed[e].w=-w;
 16     ed[e].next=head[v];head[v]=e++;
 17 }
 18 char s[N][N];
 19 int n,A,B,S,T,ans=-1;
 20 int dis[N],pre[N],bo[N];
 21 int a[N],b[N],tot,lim,num1;
 22 bool spfa(){
 23     memset(dis,0x3f,sizeof dis);
 24     memset(bo,0,sizeof bo);
 25     deque<int> q;q.push_front(S);dis[S]=0;
 26     while(!q.empty()){
 27         int x=q.front();q.pop_front();bo[x]=0;
 28         for(int i=head[x];i;i=ed[i].next){
 29             int v=ed[i].v;
 30             if(ed[i].f&&dis[v]>dis[x]+ed[i].w){
 31                 dis[v]=dis[x]+ed[i].w;pre[v]=i;
 32                 if(!bo[v]){
 33                     bo[v]=1;
 34                     if(!q.empty()&&dis[v]<dis[q.front()])q.push_front(v);
 35                     else q.push_back(v);
 36                 }
 37             }
 38         }
 39     }
 40     return dis[T]!=dis[T+1];
 41 }
 42 int Flow,Cost;
 43 int dfs(int x,int f){
 44     bo[x]=1;
 45     if(x==T){
 46         Flow+=f;
 47         Cost+=dis[T]*f;
 48         return f;
 49     }
 50     int ans=0;
 51     for(int i=head[x];i;i=ed[i].next){
 52         int v=ed[i].v;
 53         if(ed[i].f&&dis[v]==dis[x]+ed[i].w&&!bo[v]){
 54             int nxt=dfs(v,min(f,ed[i].f));
 55             ans+=nxt;f-=nxt;ed[i].f-=nxt;ed[i^1].f+=nxt;
 56             if(!f)break;
 57         }
 58     }
 59     return ans;
 60 }
 61 void work(){
 62     Flow=0,Cost=0;
 63     while(spfa()){
 64         do{
 65             memset(bo,0,sizeof bo);
 66             dfs(S,inf);
 67         }while(bo[T]);
 68     }
 69     if(Flow==tot&&lim*B<=(tot-Cost)*A)
 70         ans=max(ans,tot-Cost);
 71 }
 72 int tim;
 73 int main(){
 74     while(scanf("%d%d%d",&n,&A,&B)==3&&((n+A+B)!=0)){
 75         num1=0;tot=0;
 76         memset(a,0,sizeof a);
 77         memset(b,0,sizeof b);
 78         for(int i=1;i<=n;i++){
 79             scanf("%s",s[i]+1);
 80             for(int j=1;j<=n;j++){
 81                 if(s[i][j]!='/'){
 82                     tot++;a[i]++;b[j]++;
 83                     if(s[i][j]=='C')num1++;
 84                 }
 85             }
 86         }
 87         S=n*2+1;T=S+1;ans=-1;
 88         for(lim=0;lim<=n;lim++){
 89             e=2;memset(head,0,sizeof head);
 90             for(int i=1;i<=n;i++){
 91                 add(S,i,a[i],0);
 92                 add(n+i,T,b[i],0);
 93                 add(i,n+i,lim,0);
 94                 for(int j=1;j<=n;j++)if(s[i][j]=='.')
 95                     add(i,n+j,1,1);
 96             }
 97             work();
 98         }
 99         printf("Case %d: ",++tim);
100         if(ans==-1)puts("impossible");
101         else printf("%d\n",ans-num1);
102     }
103     return 0;
104 }
View Code

裸的spfa在bzoj上T,在wangxh的建议下改成了多路增广,然后跑的飞快!

4.17

开场看T1,貌似不是很难,但是yy了一会,感觉O(n^2)暴力有点难写,于是去看T2,发现是二分图博弈裸题,然后码,二分图和dinic拍,本来以为二分图过不了呢,结果跑的都很快。之后看T3,这不是Cooook讲的原题嘛,操,我不会SAM,因为记得他当时说SA不能做,就没想,写了个30分kmp暴力,之后又去yyT1,然后yy出了那个O(n^2)的暴力,然后写,写完和状压拍,拍上了,然后想优化,发现我这些操作就是一个线段树,然后赶紧码上,拍上了,然后感觉今天这题岂不是会有很多人AK,然而我挂在了一道原题上。。之后又静态查了波错就完了。100+100+30=230 rank2/10,没有挂分,不错,没有人AK??有点不可思议。

T1,f[i][j]表示前i个位置,第i个位置水的高度是j的答案,cnt[i][j]=i这个位置j高度的水能满足多少条件。

转移的话:$$f[i][j]=Max_{k=0}^{h[i]} (f[i-1][k]+cnt[i][j]) (j<=h[i])$$

$$f[i][j]=f[i-1][j]+cnt[i][j] (j>h[i])$$

然后这个加法和去Max都可以通过线段树来操作,就可以O(nlogn)了,貌似正解是树形dp??

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #define N 100050
  6 using namespace std;
  7 int T,n,m,ans,h[N],num[N<<1],num_cnt;
  8 struct data{int x,y,o;}d[N];
  9 inline bool cmp(data a,data b){
 10     if(a.x==b.x)return a.y<b.y;
 11     return a.x<b.x;
 12 }
 13 int maxn[N<<3],tag[N<<3],lazy[N<<3];
 14 inline void pushdown(int rt){
 15     if(tag[rt]){
 16         maxn[rt<<1]=tag[rt<<1]=tag[rt];
 17         lazy[rt<<1]=0;
 18         maxn[rt<<1|1]=tag[rt<<1|1]=tag[rt];
 19         lazy[rt<<1|1]=0;
 20         tag[rt]=0;
 21     }
 22     if(lazy[rt]){
 23         maxn[rt<<1]+=lazy[rt];
 24         lazy[rt<<1]+=lazy[rt];
 25         maxn[rt<<1|1]+=lazy[rt];
 26         lazy[rt<<1|1]+=lazy[rt];
 27         lazy[rt]=0;
 28     }
 29 }
 30 void update(int rt,int l,int r,int x,int y,int z){
 31     if(x<=l&&r<=y){
 32         maxn[rt]+=z;lazy[rt]+=z;
 33         return ;
 34     }
 35     pushdown(rt);
 36     int mid=(l+r)>>1;
 37     if(x<=mid)update(rt<<1,l,mid,x,y,z);
 38     if(y>mid)update(rt<<1|1,mid+1,r,x,y,z);
 39     maxn[rt]=max(maxn[rt<<1],maxn[rt<<1|1]);
 40 }
 41 void change(int rt,int l,int r,int x,int y,int z){
 42     if(x<=l&&r<=y){
 43         maxn[rt]=tag[rt]=z;lazy[rt]=0;
 44         return ;
 45     }
 46     pushdown(rt);
 47     int mid=(l+r)>>1;
 48     if(x<=mid)change(rt<<1,l,mid,x,y,z);
 49     if(y>mid)change(rt<<1|1,mid+1,r,x,y,z);
 50     maxn[rt]=max(maxn[rt<<1],maxn[rt<<1|1]);
 51 }
 52 int query(int rt,int l,int r,int x,int y){
 53     if(x<=l&&r<=y)return maxn[rt];
 54     pushdown(rt);
 55     int mid=(l+r)>>1;
 56     if(y<=mid)return query(rt<<1,l,mid,x,y);
 57     if(x>mid)return query(rt<<1|1,mid+1,r,x,y);
 58     return max(query(rt<<1,l,mid,x,y),query(rt<<1|1,mid+1,r,x,y));
 59 }
 60 inline int read(){
 61     int a=0;char ch=getchar();
 62     while(ch<'0'||ch>'9')ch=getchar();
 63     while(ch>='0'&&ch<='9'){a=a*10+(ch^48);ch=getchar();}
 64     return a;
 65 }
 66 int main(){
 67     register int i,l,r,mx;
 68     T=read();
 69     while(T--){
 70         n=read();m=read();
 71         num_cnt=0;
 72         for(i=1;i<n;++i){
 73             h[i]=read();
 74             num[++num_cnt]=h[i];
 75         }
 76         for(i=1;i<=m;++i){
 77             d[i].x=read();d[i].y=read();d[i].o=read();
 78             num[++num_cnt]=++d[i].y;
 79         }
 80         sort(d+1,d+m+1,cmp);
 81         sort(num+1,num+num_cnt+1);
 82         num_cnt=unique(num+1,num+num_cnt+1)-num-1;
 83         for(i=1;i<n;++i)
 84             h[i]=lower_bound(num+1,num+num_cnt+1,h[i])-num;
 85         for(i=1;i<=m;++i)
 86             d[i].y=lower_bound(num+1,num+num_cnt+1,d[i].y)-num;
 87         memset(maxn,0,sizeof maxn);
 88         memset(tag,0,sizeof tag);
 89         memset(lazy,0,sizeof lazy);
 90         for(i=1,l=1,r=0;i<=n;++i){
 91             while(r<m&&d[r+1].x==i)++r;
 92             for(;l<=r;++l){
 93                 if(d[l].o)update(1,0,num_cnt,d[l].y,num_cnt,1);
 94                 else update(1,0,num_cnt,0,d[l].y-1,1);
 95             }
 96             mx=query(1,0,num_cnt,0,h[i]);
 97             change(1,0,num_cnt,0,h[i],mx);
 98         }
 99         printf("%d\n",maxn[1]);
100     }
101 }
View Code

T2,裸的二分图博弈,不解释。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <queue>
 7 #define N 10050
 8 #define inf 0x3fffffff
 9 using namespace std;
10 int e=2,head[N];
11 struct edge{
12     int u,v,next;
13 }ed[N<<5];
14 void add(int u,int v){
15     ed[e].u=u;ed[e].v=v;
16     ed[e].next=head[u];head[u]=e++;
17 }
18 char s[105];
19 int n,m,can[105][105],id[105][105],tot1,tot2,cnt;
20 int ans[N],bo[N],pp[N];
21 bool find(int x){
22     for(int i=head[x];i;i=ed[i].next){
23         int v=ed[i].v;
24         if(!bo[v]){
25             bo[v]=1;
26             if(!pp[v]||find(pp[v])){
27                 pp[v]=x;
28                 pp[x]=v;
29                 return 1;
30             }
31         }
32     }
33     return 0;
34 }
35 void dfs(int x,int o){
36     bo[x]=1;
37     // printf("x====%d  %d\n",x,o);
38     if(!o){
39         ans[x]=1;
40         for(int i=head[x];i;i=ed[i].next){
41             int v=ed[i].v;
42             if(!bo[v])dfs(v,o^1);
43         }
44     }
45     else  dfs(pp[x],o^1);
46 }
47 int main(){
48     // freopen("test.in","r",stdin);
49     // freopen("2.out","w",stdout);
50     scanf("%d%d",&n,&m);
51     for(int i=1;i<=n;i++){
52         scanf("%s",s+1);
53         for(int j=1;j<=m;j++)if(s[j]=='.'){
54             can[i][j]=1;
55             if((i+j)&1)id[i][j]=++tot1;
56             else id[i][j]=++tot2;
57         }
58     }
59     for(int i=1;i<=n;i++)
60         for(int j=1;j<=m;j++)if(can[i][j]){
61             if(!((i+j)&1))id[i][j]+=tot1;
62             // printf("%d  %d  %d\n",i,j,id[i][j]);
63         }
64  
65     for(int i=1;i<=n;i++)
66         for(int j=1;j<m;j++)if(can[i][j]&&can[i][j+1]){
67             add(id[i][j],id[i][j+1]);
68             add(id[i][j+1],id[i][j]);
69         }
70     for(int i=1;i<n;i++)
71         for(int j=1;j<=m;j++)if(can[i][j]&&can[i+1][j]){
72             add(id[i][j],id[i+1][j]);
73             add(id[i+1][j],id[i][j]);
74         }
75  
76     for(int i=1;i<=tot1;i++){
77         memset(bo,0,sizeof bo);
78         find(i);
79     }
80     for(int i=1;i<=tot1+tot2;i++)if(!pp[i]){
81         memset(bo,0,sizeof bo);
82         dfs(i,0);
83     }
84     for(int i=1;i<=n;i++)
85         for(int j=1;j<=m;j++)if(can[i][j]&&ans[id[i][j]])cnt++;
86     printf("%d\n",cnt);
87     for(int i=1;i<=n;i++)
88         for(int j=1;j<=m;j++)if(can[i][j]&&ans[id[i][j]])printf("%d %d\n",i,j);
89     return 0;
90 }
View Code

T3,后缀自动机,分类讨论。当$k>\sqrt{n}$时,我们暴力跑,时间复杂度O(mqlogn)。否则我们对于每个串暴力O(k^2)在后缀自动机上跑,对于每个区间的贡献,离线用莫队来维护,时间复杂度$O(m\sqrt{m}+qk^{2})$。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <vector>
  7 #define LL long long
  8 #define N 100500
  9 using namespace std;
 10 int n,m,q,K,last,tot,l[N],r[N];
 11 char s[N];
 12 int ch[N<<2][26],mx[N<<2],par[N<<2],size[N<<2];
 13 int e=1,head[N<<2];
 14 struct edge{
 15     int u,v,next;
 16 }ed[N<<2];
 17 void add(int u,int v){
 18     ed[e].u=u;ed[e].v=v;
 19     ed[e].next=head[u];head[u]=e++;
 20 }
 21 void extend(int c,int o){
 22     int p=last;
 23     if(ch[p][c]){
 24         int q=ch[p][c];
 25         if(mx[q]==mx[p]+1){last=q;return ;}
 26         int nq=++tot;par[nq]=par[q];mx[nq]=mx[p]+1;
 27         memcpy(ch[nq],ch[q],sizeof ch[nq]);
 28         for(;p&&ch[p][c]==q;p=par[p])ch[p][c]=nq;
 29         par[q]=nq;
 30         last=nq;return;
 31     }
 32     int np=++tot;mx[np]=mx[p]+1;size[np]=o;
 33     for(;p&&!ch[p][c];p=par[p])ch[p][c]=np;
 34     if(!p)par[np]=1;
 35     else{
 36         int q=ch[p][c];
 37         if(mx[q]==mx[p]+1)par[np]=q;
 38         else{
 39             int nq=++tot;par[nq]=par[q];mx[nq]=mx[p]+1;
 40             memcpy(ch[nq],ch[q],sizeof ch[nq]);
 41             for(;p&&ch[p][c]==q;p=par[p])ch[p][c]=nq;
 42             par[q]=par[np]=nq;
 43         }
 44     }
 45     last=np;
 46 }
 47 int a[N],b[N];
 48 namespace work1{
 49     char t[N];
 50     int fa[N<<2][22];
 51     LL ans;
 52     vector <int> pp[405];
 53     void dfs(int x,int d){
 54         for(int i=1;(1<<i)<=d;i++)
 55             fa[x][i]=fa[fa[x][i-1]][i-1];
 56         for(int i=head[x];i;i=ed[i].next){
 57             int v=ed[i].v;
 58             fa[v][0]=x;dfs(v,d+1);
 59             size[x]+=size[v];
 60         }
 61     }
 62     int find(int x,int l){
 63         for(int i=20;~i;i--)
 64             if(mx[fa[x][i]]>=l)x=fa[x][i];
 65         return x;
 66     }
 67     void Main(){
 68         for(int i=1;i<=q;i++){
 69             scanf("%s%d%d",t+1,&a[i],&b[i]);
 70             a[i]++;b[i]++;
 71             last=1;
 72             pp[i].push_back(last);
 73             for(int j=1;j<=K;j++){
 74                 extend(t[j]-'a',0);
 75                 pp[i].push_back(last);
 76             }
 77         }
 78         for(int i=1;i<=tot;i++)add(par[i],i);
 79         dfs(1,1);
 80         for(int i=1;i<=q;i++){
 81             ans=0;
 82             for(int j=a[i];j<=b[i];j++)
 83                 ans+=size[find(pp[i][r[j]],r[j]-l[j]+1)];
 84             printf("%lld\n",ans);
 85         }
 86         return ;
 87     }
 88 }
 89 namespace work2{
 90     int be[N];
 91     int cnt[444][444];
 92     LL ans[N];
 93     struct data{
 94         char t[444];
 95         int a,b,id;
 96     }d[N];
 97     bool cmp(data a,data b){
 98         if(be[a.a]==be[b.a])return a.b<b.b;
 99         return be[a.a]<be[b.a];
100     }
101     LL query(data x){
102         LL ans=0;
103         for(int i=1;i<=K;i++){
104             for(int j=i,now=1;j<=K;j++){
105                 if(!ch[now][x.t[j]-'a'])break;
106                 now=ch[now][x.t[j]-'a'];
107                 ans+=1ll*size[now]*cnt[i][j];
108             }
109         }
110         return ans;
111     }
112     void dfs(int x){
113         for(int i=head[x];i;i=ed[i].next){
114             int v=ed[i].v;
115             dfs(v);
116             size[x]+=size[v];
117         }
118     }
119     void Main(){
120         for(int i=1;i<=tot;i++)add(par[i],i);
121         dfs(1);
122         for(int i=1;i<=q;i++){
123             d[i].id=i;
124             scanf("%s%d%d",d[i].t+1,&d[i].a,&d[i].b);
125             d[i].a++;d[i].b++;
126         }
127         int mm=sqrt(m);
128         for(int i=1;i<=m;i++)be[i]=(i-1)/mm+1;
129         sort(d+1,d+q+1,cmp);
130         int posl=1,posr=0;
131         for(int i=1;i<=q;i++){
132             while(posl<d[i].a)cnt[l[posl]][r[posl]]--,posl++;
133             while(posl>d[i].a)posl--,cnt[l[posl]][r[posl]]++;
134             while(posr<d[i].b)posr++,cnt[l[posr]][r[posr]]++;
135             while(posr>d[i].b)cnt[l[posr]][r[posr]]--,posr--;
136             ans[d[i].id]=query(d[i]);
137         }
138         for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);
139     }
140 }
141 int main(){
142     scanf("%d%d%d%d",&n,&m,&q,&K);
143     scanf("%s",s+1);
144     last=++tot;
145     for(int i=1;i<=n;i++)extend(s[i]-'a',1);
146     for(int i=1;i<=m;i++)scanf("%d%d",&l[i],&r[i]),l[i]++,r[i]++;
147     if(K>sqrt(n))work1::Main();
148     else work2::Main();
149     return 0;
150 }
View Code

4.19

开场看T1,发现和原来做的商店购物有点像,估计是一堆组合数乱搞,先放放。看T2,裸fwt啊!裸的fwt有五十分,然后发现现在要求$x+x^{2}+x^{4}+x^{8}....$,然后我玄学的乱猜了个结论,这个会有循环节,然后就打出来了,发现好像是对的。就去看T3,只会30分暴力,之后一直在想从谁走到谁会做出多少贡献,发现概率不同,贡献也不同,之后赶紧去把T1的50分暴力打上了,然后想到了容斥,没时间打了。GG。40+100+30=170 rank1/10。T1up没有减一挂了10分。

T1,容斥前几个有几个不合法,然后直接组合数,组合数要用exLucas,然后我发现我原来学了一个假的exLucas,非常优秀。

  1 #pragma GCC optimize ("O3")
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <cmath>
  7 using namespace std;
  8 int read(){
  9     int a=0;char ch=getchar();
 10     while(ch<'0'||ch>'9')ch=getchar();
 11     while(ch>='0'&&ch<='9'){a=a*10+(ch^48);ch=getchar();}
 12     return a;
 13 }
 14 int T,mod,n,n1,n2,m,ans,up[12];
 15 int cnt[266],p[10],pk[10],K[10],r[10],num,fac[10][11111];
 16 void UPD(int &a,int b){a=(a+b>=mod)?(a+b-mod):(a+b);}
 17 int qp(int a,int b,int c){
 18     int ans=1;
 19     while(b){
 20         if(b&1)ans=1ll*ans*a%c;
 21         a=1ll*a*a%c; b>>=1;
 22     }
 23     return ans;
 24 }
 25 #define pr pair<int,int>
 26 #define fir first
 27 #define sec second
 28 pr calc(int n,int x){
 29     if(!n)return pr(1,0);
 30     int a=qp(fac[x][pk[x]-1],n/pk[x],pk[x]);
 31     int b=n/p[x];
 32     pr ans=calc(n/p[x],x);
 33     a=1ll*a*fac[x][n%pk[x]]%mod;
 34     ans.fir=1ll*ans.fir*a%pk[x];
 35     ans.sec+=b;
 36     return ans;
 37 }
 38 int C(int n,int m,int x){
 39     if(m>n||m<0)return 0;
 40     if(m==n||m==0)return 1;
 41     pr ans1=calc(n,x),ans2=calc(m,x),ans3=calc(n-m,x);
 42     int a=1ll*ans1.fir
 43              *qp(ans2.fir,pk[x]/p[x]*(p[x]-1)-1,pk[x])%pk[x]
 44              *qp(ans3.fir,pk[x]/p[x]*(p[x]-1)-1,pk[x])%pk[x];
 45     int b=ans1.sec-ans2.sec-ans3.sec;
 46     if(b>=K[x])return 0;
 47     return 1ll*a*qp(p[x],b,pk[x])%pk[x];
 48 }
 49 int crt(){
 50     int ans=0;
 51     for(int i=1,tmp;i<=num;i++){
 52         tmp=qp(mod/pk[i],pk[i]/p[i]*(p[i]-1)-1,pk[i]);
 53         UPD(ans,1ll*(mod/pk[i])*tmp%mod*r[i]%mod);
 54     }
 55     return ans;
 56 }
 57 int getc(int n,int m){
 58     if(m>n||m<0)return 0;
 59     if(m==n||m==0)return 1;
 60     for(int i=1;i<=num;i++){
 61         r[i]=C(n,m,i);
 62     }
 63     return crt();
 64 }
 65 int main(){
 66     register int i,j,sum,now;
 67     T=read();mod=read();
 68     if(mod==10007)num=1,p[1]=pk[1]=10007,K[1]=1;
 69     if(mod==262203414){
 70         p[1]=pk[1]=2,p[2]=pk[2]=3,p[3]=pk[3]=11,p[4]=pk[4]=397,p[5]=pk[5]=10007;
 71         K[1]=K[2]=K[3]=K[4]=K[5]=1;num=5;
 72     }
 73     if(mod==437367875){
 74         num=K[1]=K[2]=3;K[3]=2;
 75         p[1]=5;pk[1]=125;p[2]=7;pk[2]=343;p[3]=101;pk[3]=10201;
 76     }
 77     for(i=1;i<=num;i++){
 78         fac[i][0]=1;
 79         for(int j=1;j<pk[i];j++)
 80             if(j%p[i])fac[i][j]=1ll*fac[i][j-1]*j%pk[i];
 81             else fac[i][j]=fac[i][j-1];
 82     }
 83     while(T--){
 84         ans=0;
 85         n=read();n1=read();n2=read();m=read()-n;
 86         for(i=1;i<=n1;++i)up[i]=read();
 87         for(i=n1+1;i<=n1+n2;++i)m-=read()-1;
 88         for(i=1;i<=n1;++i)up[i]--;
 89         for(i=0;i<(1<<n1);i++){
 90             cnt[i]=cnt[i>>1]+(i&1);
 91             for(j=1,sum=0;j<=n1;j++)if(i&(1<<j-1))
 92                 sum+=up[j]+1;
 93             now=getc(m-sum+n-1,n-1);
 94             if(cnt[i]&1)ans=(ans-now+mod)%mod;
 95             else UPD(ans,now);
 96         }
 97         printf("%d\n",ans);
 98     }
 99     return 0;
100 }
View Code

T2,考场打的循环节其实是有理论依据的,我们现在其实是要求最小的x满足$2^{x}=2 (mod \; \phi{p})$,然后我们会发现这个x等于5003,其实这里用到了ex欧拉定理,其实也是因为2比较特殊。更优秀一点的做法是倍增求解,我们需要倍增处理出$x^{2^{2^{a}}}$和$\sum_{i=0}^{a}{x^{2^{2^{i}}}}$,然后直接上fwt就可以了。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <ctime>
 7 #define N 277777
 8 #define mod 10007
 9 using namespace std;
10 int a[N],n,m,p,ans,all;
11 int inv2=5004;
12 void UPD(int &a,int b){a=(a+b>=mod)?(a+b-mod):(a+b);}
13 void fwt(int *a){
14     register int i,j,k,x,y;
15     for(k=2;k<=all;k<<=1)
16         for(i=0;i<all;i+=k)
17             for(j=0;j<(k>>1);j++){
18                 x=a[i+j],y=a[i+j+(k>>1)];
19                 a[i+j]=(x+y)%mod;
20                 a[i+j+(k>>1)]=(x-y+mod)%mod;
21             }
22 }
23 void ifwt(int *a){
24     register int i,j,k,x,y;
25     for(k=2;k<=all;k<<=1)
26         for(i=0;i<all;i+=k)
27             for(j=0;j<(k>>1);j++){
28                 x=a[i+j],y=a[i+j+(k>>1)];
29                 a[i+j]=(x+y)*inv2%mod;
30                 a[i+j+(k>>1)]=(x-y+mod)*inv2%mod;
31             }
32 }
33 int sum[mod+10],vis[mod+10],tim[mod+10];
34 int s1[mod+10],pos[mod+10],val[mod+10],len[mod+10],s2[mod+10];
35 int pp[mod+10];
36 void work(){
37     int now,cnt;
38     for(int i=1;i<mod;i++){
39         now=i;cnt=1;
40         sum[cnt]=now;
41         vis[now]=i;
42         tim[now]=cnt;
43         while(vis[now*now%mod]!=i){
44             now=now*now%mod;cnt++;
45             sum[cnt]=(sum[cnt-1]+now)%mod;
46             vis[now]=i;tim[now]=cnt;
47         }
48         now=now*now%mod;
49         s1[i]=sum[tim[now]-1];
50         pos[i]=tim[now];
51         val[i]=now;
52         len[i]=cnt-tim[now]+1;
53         s2[i]=(sum[cnt]-sum[tim[now]-1]+mod)%mod;
54     }
55     m++;
56     for(int i=1;i<mod;i++){
57         if(m<pos[i]){
58             now=i;
59             for(int j=1;j<=m;j++){
60                 UPD(pp[i],now);
61                 now=now*now%mod;
62             }
63         }
64         else{
65             pp[i]=s1[i];
66             int l=(m-pos[i]+1);
67             UPD(pp[i],(l/len[i])%mod*s2[i]%mod);
68             l%=len[i];now=val[i];
69             for(int j=1;j<=l;j++){
70                 UPD(pp[i],now);
71                 now=now*now%mod;
72             }
73         }
74     }
75     for(int i=0;i<all;i++)a[i]=pp[a[i]];
76 }
77 int main(){
78     scanf("%d%d%d",&n,&m,&p);
79     all=(1<<n);
80     for(int i=0;i<all;i++)scanf("%d",&a[i]);
81     fwt(a);work();ifwt(a);
82     printf("%d\n",a[p]);
83 }
View Code

T3,我们考虑把环拆成一个序列,然后我们dp时就是钦定该段只剩最后一个元素是点,然后求出从初始状态到该状态的期望和概率,转移时再枚举剩下的点中谁是最后一个变成X的,然后就变成了我们已知的f值,这样区间dp下去就可以了。

具体的转移方程:f表概率,g表期望,p表示l~r这段除r外最后变成X的.的位置是k的概率

$$p(l,r,k)={\frac{len(l,k)}{len(l,r)}}^{num(l,k)} {\frac{len(k+1,r)}{len(l,r)}}^{num(k+1,r)-1}*C_{num(l,r)-2}^{num(l,k)-1}g(l,k)g(k+1,r)$$

$$g(l,r)=\sum_{k=l}^{r-1}{p(l,r,k)}$$

$$f(l,r)=\frac{1}{g(l,r)} \sum_{k=l}^{r-1}{p(l,r,k)(f(l,k)+f(k+1,r)+\frac{k-i}{2})}$$

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define N 205
 7 #define nxt(x) (((x)==n)?(1):((x)+1))
 8 #define pre(x) (((x)==1)?(n):((x)-1))
 9 using namespace std;
10 char s[N];
11 int visf[N][N],visg[N][N],len[N][N],cnt[N][N],n,T;
12 double f[N][N],g[N][N],C[N][N],pw[N][N],ans;
13 double P(int l,int r,int k);
14 double G(int l,int r);
15 double F(int l,int r);
16 double P(int l,int r,int k){
17     if(s[r]=='X'||s[k]=='X')return 0;
18     int c1=cnt[l][k]-1,c2=cnt[nxt(k)][r]-1;
19     return C[c1+c2][c1]*pw[len[l][k]][c1+1]*pw[len[nxt(k)][r]][c2]/pw[len[l][r]][c1+c2+1]*G(l,k)*G(nxt(k),r);
20 }
21 double G(int l,int r){
22     if(visg[l][r])return g[l][r];
23     if(s[r]=='X')return 0;
24     if(cnt[l][r]==1)return 1;
25     double ans=0;
26     for(int i=l;i!=r;i=nxt(i))
27         ans+=P(l,r,i);
28     visg[l][r]=1;
29     return g[l][r]=ans;
30 }
31 double F(int l,int r){
32     if(visf[l][r])return f[l][r];
33     if(s[r]=='X')return 0;
34     if(cnt[l][r]==1)return 0;
35     if(G(l,r)<1e-12)return 0;
36     double ans=0;
37     for(int i=l;i!=r;i=nxt(i))
38         ans+=P(l,r,i)*(F(l,i)+F(nxt(i),r)+(len[l][i]-1)/2.0);
39     visf[l][r]=1;
40     return f[l][r]=ans/G(l,r);
41 }
42 int main(){
43     scanf("%d",&T);
44     for(int i=0;i<=200;i++){
45         C[i][0]=1;
46         for(int j=1;j<=i;j++)
47             C[i][j]=C[i-1][j-1]+C[i-1][j];
48     }
49     for(int i=1;i<=200;i++){
50         pw[i][0]=1;
51         for(int j=1;j<=200;j++)
52             pw[i][j]=pw[i][j-1]*i;
53     }
54     while(T--){
55         scanf("%s",s+1);
56         n=strlen(s+1);
57         memset(cnt,0,sizeof cnt);
58         for(int i=1;i<=n;i++){
59             cnt[i][i]=(s[i]=='.');
60             len[i][i]=1;
61             for(int j=nxt(i);j!=i;j=nxt(j))
62                 cnt[i][j]=cnt[i][pre(j)]+(s[j]=='.'),
63                 len[i][j]=len[i][pre(j)]+1;
64         }
65         if(!cnt[1][n]){puts("0");continue;}
66         memset(visf,0,sizeof visf);
67         memset(visg,0,sizeof visg);
68         ans=0;
69         for(int i=1;i<=n;i++)
70             ans+=G(nxt(i),i)*F(nxt(i),i);
71         printf("%0.8f\n",ans+(n-1)/2.0);
72     }
73     return 0;
74 }
View Code

 4.22

怎么又考试啊。先看T1,35分sb杜教筛phi,20分暴力,看起来很好,感觉又是组合数乱搞?看T2,只会20分裸暴力,yy了一会循环节,但是觉得至少是O(p)的,就没深入想,然后看T3,多项式?卷积?不错,这不是裸的多点求值嘛!yy了一会,不会,但是感觉这肯定不是正解,然后又乱yy了一会,啥也不会,然后哪道题都不会了,就GG了。40+0+30=70 rank10/10,T1傻逼暴力挂了,T2矩阵中我的-1没有+mod爆负了,然后就挂了。

T1,容斥最后gcd的质因子,$$\sum_{i=1}^{n}{\mu{(i)} \cdot C_{n/i+k-1}^{k}}$$需要杜教筛mu,然后除法分块。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <map>
 7 #define mod 1000000007
 8 #define N 10000050
 9 using namespace std;
10 int tot,mu[N],sm[N],prime[666666],T,n,m,ans;
11 int inv[1000500],fac[1000500],Inv;
12 bool vis[N];
13 void init(){
14     mu[1]=sm[1]=1;
15     for(int i=2;i<=10000000;i++){
16         if(!vis[i]){
17             prime[++tot]=i;
18             mu[i]=mod-1;
19         }
20         for(int j=1;j<=tot&&i*prime[j]<=10000000;j++){
21             vis[i*prime[j]]=1;
22             if(i%prime[j]==0){
23                 mu[i*prime[j]]=0;
24                 break;
25             }
26             mu[i*prime[j]]=mod-mu[i];
27         }
28         sm[i]=(sm[i-1]+mu[i])%mod;
29     }
30 }
31 map<int,int> mm;
32 int gets(int n){
33     if(n<=10000000)return sm[n];
34     if(mm.count(n))return mm[n];
35     int ans=1;
36     for(int i=2,j;i<=n;i=j+1){
37         j=n/(n/i);
38         ans=(ans-1ll*(j-i+1)*gets(n/i)%mod+mod)%mod;
39     }
40     return mm[n]=ans;
41 }
42 void UPD(int &a,int b){a=(a+b>=mod)?(a+b-mod):(a+b);}
43 int qp(int a,int b){
44     int c=1;
45     for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)c=1ll*c*a%mod;
46     return c;
47 }
48 int C(int n){
49     int ans=Inv;
50     if(n<=1000000)ans=1ll*ans*fac[n]%mod;
51     else for(int i=1;i<=m;i++)ans=1ll*ans*(n-i+1)%mod;
52     return ans;
53 }
54 int main(){
55 //freopen("test.in","r",stdin);
56     init();
57     inv[1]=1;
58     for(int i=2;i<=1000000;i++)
59         inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod;
60     scanf("%d",&T);
61     while(T--){
62         scanf("%d%d",&n,&m);
63         fac[m]=1;
64         for(int i=1;i<=m;i++)fac[m]=1ll*fac[m]*i%mod;
65         for(int i=m+1;i<=1000000;i++)
66             fac[i]=1ll*fac[i-1]*i%mod*inv[i-m]%mod;
67         Inv=qp(fac[m],mod-2);
68         ans=0;
69         for(int i=1,j;i<=n;i=j+1){
70             j=n/(n/i);
71             UPD(ans,1ll*(gets(j)-gets(i-1)+mod)%mod*C(n/i+m-1)%mod);
72         }
73         printf("%d\n",ans);
74     }
75     return 0;
76 }
View Code

 T2,暴力找循环节,然后用bsgs的思想$O(\sqrt{p})$做就可以了。但是复杂度不够优秀,我们考虑打表找规律,f[i]表示%i意义下的循环节长度,可以发现,若$(x,y)=1$,$f[x*y]=lcm(f[x],f[y])$,若$x=p^{k}$ ,$f[x]=f[p] \cdot  p^{k-1}$,然后若$p%10=1|p%10=9$,$f[i]=p-1$,然后这样需要做bsgs的数就很少了,就可以愉快的AC了。

 1 #pragma GCC optimize ("O3")
 2 #include <bits/stdc++.h>
 3 #define int unsigned long long
 4 using namespace std;
 5 int a,b,n,k,p,T,len[105];
 6 struct mart{
 7     int a[2][2];
 8     mart operator * (mart B){
 9         mart C;
10         C.a[0][0]=(a[0][0]*B.a[0][0]%p+a[0][1]*B.a[1][0]%p)%p;
11         C.a[0][1]=(a[0][0]*B.a[0][1]%p+a[0][1]*B.a[1][1]%p)%p;
12         C.a[1][0]=(a[1][0]*B.a[0][0]%p+a[1][1]*B.a[1][0]%p)%p;
13         C.a[1][1]=(a[1][0]*B.a[0][1]%p+a[1][1]*B.a[1][1]%p)%p;
14         return C;
15     }
16 }A,B,d,e,f;
17 mart qp(mart a,int b){
18     mart c;
19     c.a[0][0]=c.a[1][1]=1;
20     c.a[0][1]=c.a[1][0]=0;
21     for(;b;b>>=1,a=a*a)
22         if(b&1)c=c*a;
23     return c;
24 }
25 int getg(int n){
26     if(!n)return a%p;
27     A.a[0][0]=3;A.a[0][1]=1;
28     A.a[1][0]=p-1;A.a[1][1]=0;
29     B.a[0][0]=b%p;B.a[0][1]=a%p;
30     B.a[1][0]=B.a[1][1]=0;
31     B=B*qp(A,n-1);
32     return B.a[0][0];
33 }
34 unordered_map<int,int> hh;
35 unordered_map<int,int> mm;
36 int getp(int n){
37     if(n%10==1||n%10==9)return n-1;
38     if(mm.count(n))return mm[n];
39     hh.clear();p=n;
40     int x=ceil(sqrt(2*n)),last=0,now=1,tmp;
41     d.a[0][0]=1;d.a[0][1]=0;d.a[1][0]=d.a[1][1]=0;
42     e.a[0][0]=3;e.a[0][1]=1;e.a[1][0]=p-1;e.a[1][1]=0;
43     f.a[0][0]=f.a[1][1]=1;f.a[0][1]=f.a[1][0]=0;
44     for(int i=0;i<x;i++){
45         if(hh.count(now*1000000007+last))return i;
46         hh[now*1000000007+last]=i;
47         tmp=now;now=(now*3%p-last+p)%p;last=tmp;
48         f=f*e;
49     }
50     d=d*f*f;
51     for(int i=1;i<=x;i++,d=d*f){
52         if(hh.count(d.a[0][0]*1000000007+d.a[0][1]))
53             return mm[n]=(i+1)*x-hh[d.a[0][0]*1000000007+d.a[0][1]];
54     }
55 }
56 int gcd(int x,int y){return !y?x:gcd(y,x%y);}
57 int lcm(int x,int y){return x/gcd(x,y)*y;}
58 int getl(int x){
59     if(mm.count(x))return mm[x];
60     int y=x,ans=1;
61     for(int i=2;i*i<=y;i++)if(y%i==0){
62         int w=getp(i);y/=i;
63         while(y%i==0)w=w*i,y/=i;
64         ans=lcm(ans,w);
65     }
66     if(y!=1)ans=lcm(ans,getp(y));
67     return mm[x]=ans;
68 }
69 signed main(){
70     scanf("%lld",&T);
71     while(T--){
72         scanf("%lld%lld%lld%lld%lld",&a,&b,&n,&k,&p);
73         len[1]=p;
74         for(int i=2;i<=k;i++)len[i]=getl(len[i-1]);
75         for(int i=k;i;i--)p=len[i],n=getg(n);
76         printf("%lld\n",n);
77     }
78     return 0;
79 }
View Code

T3,真$\cdot$神题。首先如果c=0,可以直接暴力。

我们考虑$b=0$的情况,我们现在要求

$$y_{p}=\sum_{i=0}^{n-1}{A[i]*x_{p}^{i}}$$

$$\sum_{i=0}^{n-1}{A[i]  \sum_{j=0}^{i} C_{i}^{j} \cdot d^{j} \cdot e^{i-j}  \cdot c^{2pj}}$$

$$\sum_{j=0}^{n-1}{  c^{(p+j)^{2}-p^{2}-j^{2}}  \cdot d^{j}  \cdot  \frac{1}{j!}  \sum _{i=j+k}{A[i]  \cdot  {i!} \cdot  e^{k}  \cdot \frac{1}{k!} } }$$

$$\frac{1}{c^{p^{2}}}   \sum_{x=p+j}{ c^{x^{2}} \cdot  d^{j} \cdot \frac{1}{c^{j^{2}}}  \cdot \frac{1}{j!}   \sum_{i=j+k}{A[i]  \cdot  {i!}  \cdot  e^{k}  \cdot \frac{1}{k!}  } }$$

然后我们就可以通过两次卷积来统计这个答案啦。

于是我们就愉快的解决了$b=0$的情况。

下面考虑通解,我们发现$bc^{4k}+dc^{2k}+e$这个式子很不美丽,于是我们考虑将其化成$b(c^{2k}+d’)^{2}+e’$,解方程解得$d'=\frac{d}{2b}$,$e'=e-\frac{d^{2}}{4b}$。

ps.下面的d即为d',e即为e'。

所以我们现在要求的就是

$$\sum_{i=0}^{n-1}{A[i]  (b(c^{2p}+d)^{2}+e)^{i}  }$$

$$\sum_{i=0}^{n-1}{A[i]  \sum_{j=0}^{i} C_{i}^{j} \cdot b^{j} \cdot (c^{2p}+d)^{2j} \cdot  e^{i-j}  }$$

$$\sum_{j=0}^{n-1} {   (c^{2p}+d)^{2j} \cdot  b^{j} \cdot  \frac{1}{j!}   \sum_{i=j+k} {A[i]  \cdot i!  \cdot  e^{k} \cdot  \frac{1}{k!}  }    }$$

我们按照上面$b=0$的做法将后面的东西卷积,现在我们就是要求

$$\sum_{j=0}^{n-1}  {   (c^{2p}+d)^{2j} \cdot A[j]  }$$

$$\sum_{j=0}^{n-1}  {    A[j]   \sum_{k+l=2j}{ C_{2j}^{k}  \cdot  c^{(p+k)^{2}-p^{2}-k^{2}}   \cdot d^{l}  }   }$$

$$\frac{1}{c^{p^{2}}}      \sum_{x=p+k}  {   c^{x^{2}}  \cdot  \frac{1}{c^{k^{2}}}  \cdot  \frac{1}{k!}  \sum_{k+l=2j} {   d^{l} \cdot  \frac{1}{l!} \cdot  A[j]  \cdot {(2j)!} }  }    $$

我们发现到这里就可以卷积啦!只是细节比较麻烦。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #define N 555555
  7 #define mod 1000003
  8 #define LL long long
  9 using namespace std;
 10  
 11 int a[N],b[N],c[N],d[N],e[N],f[N],g[N];
 12 int n,B,C,D,E;
 13 int pw_b[N],pw_d[N],pw_e[N],pw_c[N],inv_c[N],fac[N],inv[N];
 14  
 15 LL mul(LL a,LL b,LL p){
 16     return (a*b-(LL)(((long double)a*b+0.5)/(long double)p)*p+p)%p;
 17 }
 18 int qp(int a,int b,int p=mod){
 19     int c=1;
 20     for(;b;b>>=1,a=1ll*a*a%p)
 21         if(b&1)c=1ll*c*a%p;
 22     return c;
 23 }
 24 void UPD(int &a,int b){
 25     a=(a+b>=mod)?(a+b-mod):(a+b);
 26 }
 27  
 28 struct poly{
 29     int p,g,w[N],rev[N];
 30     void prepare(int l){
 31         w[0]=1;int dan=qp(g,(p-1)/l,p);
 32         for(int i=1;i<=l;i++)w[i]=1ll*w[i-1]*dan%p;
 33         for(int i=0;i<=l;i++){
 34             if(i&1)rev[i]=(rev[i>>1]>>1)|(l>>1);
 35             else rev[i]=rev[i>>1]>>1;
 36         }
 37     }
 38     void dft(int *a,int o,int l){
 39         for(int i=0;i<l;i++)
 40             if(i<rev[i])swap(a[i],a[rev[i]]);
 41         for(int k=2,t;k<=l;k<<=1){
 42             for(int i=0;i<l;i+=k){
 43                 for(int j=0;j<(k>>1);j++){
 44                     t=1ll*(o==1?w[l/k*j]:w[l-l/k*j])*a[i+j+(k>>1)]%p;
 45                     a[i+j+(k>>1)]=(a[i+j]-t+p)%p;a[i+j]=(a[i+j]+t)%p;
 46                 }
 47             }
 48         }
 49         int inv=qp(l,p-2,p);
 50         if(o==-1)for(int i=0;i<l;i++)a[i]=1ll*a[i]*inv%p;
 51     }
 52     void mul(int *a,int *b,int *c,int l){
 53         static int tmpa[N],tmpb[N];
 54         prepare(l);
 55         for(int i=0;i<l;i++)tmpa[i]=a[i],tmpb[i]=b[i];
 56         dft(tmpa,1,l);dft(tmpb,1,l);
 57         for(int i=0;i<l;i++)c[i]=1ll*tmpa[i]*tmpb[i]%p;
 58         dft(c,-1,l);
 59     }
 60     void revmul(int *a,int *b,int *c,int l){
 61         static int tmpb[N];
 62         for(int i=0;i<l;i++)tmpb[i]=b[i];
 63         reverse(tmpb,tmpb+l);
 64         mul(a,tmpb,c,l);
 65         reverse(c,c+l);
 66     }
 67 }P[2];
 68 void revmul(int *a,int *b,int *c,int l,int l1){
 69     static int tmp[2][N];
 70     int L;for(L=1;L<=l;L<<=1);
 71     P[0].revmul(a,b,tmp[0],L);
 72     P[1].revmul(a,b,tmp[1],L);
 73     LL Mod=1ll*P[0].p*P[1].p,v;
 74     for(int i=0;i<l1;i++){
 75         v=0;
 76         v=(v+mul(1ll*tmp[0][i]*P[1].p%Mod,1ll*qp(P[1].p,P[0].p-2,P[0].p)%Mod,Mod))%Mod;
 77         v=(v+mul(1ll*tmp[1][i]*P[0].p%Mod,1ll*qp(P[0].p,P[1].p-2,P[1].p)%Mod,Mod))%Mod;
 78         c[i]=v%mod;
 79     }
 80 }
 81 namespace work1{
 82     void Main(){
 83         int x=(B+D+E)%mod,y=0,now=1;
 84         for(int i=0;i<n;i++,now=1ll*now*x%mod)
 85             UPD(y,1ll*a[i]*now%mod);
 86         printf("%d\n",y);
 87         x=E;y=0;now=1;
 88         for(int i=0;i<n;i++,now=1ll*now*x%mod)
 89             UPD(y,1ll*a[i]*now%mod);
 90         for(int i=1;i<n;i++)printf("%d\n",y);
 91     }
 92 }
 93 namespace work2{
 94     void Main(){
 95         fac[0]=1;for(int i=1;i<=2*n;i++)fac[i]=1ll*fac[i-1]*i%mod;
 96         inv[2*n]=qp(fac[2*n],mod-2);for(int i=2*n;i;i--)inv[i-1]=1ll*inv[i]*i%mod;
 97         pw_d[0]=1;for(int i=1;i<=2*n;i++)pw_d[i]=1ll*pw_d[i-1]*D%mod;
 98         pw_e[0]=1;for(int i=1;i<=2*n;i++)pw_e[i]=1ll*pw_e[i-1]*E%mod;
 99         for(int i=0;i<=2*n;i++)pw_c[i]=qp(C,1ll*i*i%(mod-1)),inv_c[i]=qp(pw_c[i],mod-2);
100         for(int i=0;i<n;i++)a[i]=1ll*a[i]*fac[i]%mod;
101         for(int i=0;i<n;i++)b[i]=1ll*pw_e[i]*inv[i]%mod;
102         revmul(b,a,c,2*n,n);
103         for(int i=0;i<n;i++)c[i]=1ll*c[i]*inv_c[i]%mod*inv[i]%mod*pw_d[i]%mod;
104         for(int i=0;i<2*n;i++)d[i]=pw_c[i];
105         revmul(c,d,e,3*n,n);
106         for(int i=0;i<n;i++){
107             e[i]=1ll*e[i]*inv_c[i]%mod;
108             printf("%d\n",e[i]);
109         }
110     }
111 }
112 namespace work3{
113     void Main(){
114         D=1ll*D*qp(2*B,mod-2)%mod;
115         E=(E-1ll*B*D%mod*D%mod+mod)%mod;
116         fac[0]=1;for(int i=1;i<=3*n;i++)fac[i]=1ll*fac[i-1]*i%mod;
117         inv[3*n]=qp(fac[3*n],mod-2);for(int i=3*n;i;i--)inv[i-1]=1ll*inv[i]*i%mod;
118         pw_b[0]=1;for(int i=1;i<=3*n;i++)pw_b[i]=1ll*pw_b[i-1]*B%mod;
119         pw_d[0]=1;for(int i=1;i<=3*n;i++)pw_d[i]=1ll*pw_d[i-1]*D%mod;
120         pw_e[0]=1;for(int i=1;i<=3*n;i++)pw_e[i]=1ll*pw_e[i-1]*E%mod;
121         for(int i=0;i<=3*n;i++)pw_c[i]=qp(C,1ll*i*i%(mod-1)),inv_c[i]=qp(pw_c[i],mod-2);
122         for(int i=0;i<n;i++)a[i]=1ll*a[i]*fac[i]%mod;
123         for(int i=0;i<n;i++)b[i]=1ll*pw_e[i]*inv[i]%mod;
124         revmul(b,a,c,2*n,n);
125         for(int i=2*n-1;~i;i--){
126             if(i&1)c[i]=0;
127             else c[i]=1ll*c[i>>1]*fac[i]%mod*inv[i>>1]%mod*pw_b[i>>1]%mod;
128         }
129         for(int i=0;i<2*n;i++)d[i]=1ll*pw_d[i]*inv[i]%mod;
130         revmul(d,c,e,4*n,2*n);
131         for(int i=0;i<2*n;i++)e[i]=1ll*e[i]*inv[i]%mod*inv_c[i]%mod;
132         for(int i=0;i<3*n;i++)f[i]=pw_c[i];
133         revmul(e,f,g,5*n,n);
134         for(int i=0;i<n;i++){
135             g[i]=1ll*g[i]*inv_c[i]%mod;
136             printf("%d\n",g[i]);
137         }
138     }
139 }
140 int main(){
141     P[0].p=998244353;P[0].g=3;
142     P[1].p=1004535809;P[1].g=3;
143     scanf("%d%d%d%d%d",&n,&B,&C,&D,&E);
144     for(int i=0;i<n;i++)scanf("%d",&a[i]);
145     if(!C){work1::Main();return 0;}
146     if(!B){work2::Main();return 0;}
147     work3::Main();return 0;
148 }
View Code

 4.23

开场看T1,第二个样例不太明白,然后果断弃疗去看T2,怎么又是这个题啊,三遍了。数据越来越强,只会10分暴力。看T3,这这这,矩阵树+多项式??两个变量?把另一个强行设为$x^{n}$,算了一下复杂度,$O(n^{5}+n^{6})$,貌似很不可过啊,但是感觉这个是最可写的了,然后码码码,过了大样例,造了组极限数据,90s。。之后卡了卡,卡到了50s,感觉很绝望,之后去看T1,玩出来了样例2,然后我就陷入了一个思维误区,觉得每次的决策是确定的,然后就在想怎么比较两个决策的优劣,然后乱搞了好久也没搞出来,最后打了个假的暴搜,打完就剩20min了,赶紧去把T2的10分暴力写了。20+10+50=80 rank4/10。

T1,我们发现问题其实就是要求出每一轮妹子的胜率,我们设p为胜率,q为负率,发现就是要最大化$\frac{p}{q}$,然后我们二分他,然后倒着dp,或者说贪心?每次按照当前最优策略转移,就可以了。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define eps 1e-6
 7 using namespace std;
 8 int n,m1,m2;
 9 double f[5050][2050],p[1050][5];
10 bool check(double x){
11     for(int i=1;i<=2*n+1;i++){
12         if(i<=n)f[n+1][i]=-x;
13         if(i==n+1)f[n+1][i]=0;
14         if(i>n+1)f[n+1][i]=1;
15     }
16     double r,s,t,w,d,l;
17     for(int i=n;i;i--){
18         r=p[i][1],s=p[i][2],t=p[i][3];
19         for(int j=1;j<=2*n+1;j++){
20             w=f[i+1][j+1],d=f[i+1][j],l=f[i+1][j-1];
21             f[i][j]=max(max(r*w+s*d+t*l,s*w+t*d+r*l),t*w+r*d+s*l);
22         }
23     }
24     return f[1][n+1]>0;
25 }
26 int main(){
27 //freopen("rps0.in","r",stdin);
28     while(scanf("%d%d%d",&n,&m1,&m2)==3&&((n+m1+m2)!=0)){
29         for(int i=1;i<=n;i++){
30             scanf("%lf%lf%lf",&p[i][1],&p[i][2],&p[i][3]);
31             p[i][1]/=100.0;p[i][2]/=100.0;p[i][3]/=100.0;
32         }
33         double l=0,r=1000000,mid;
34         while(l+eps<=r){
35             mid=(l+r)/2.0;
36             if(check(mid))l=mid;
37             else r=mid;
38         }
39         mid=1.0-1.0/(1.0+mid);
40         memset(f,0,sizeof f);
41         f[0][m2+1]=1;
42         for(int i=0;i<=5000;i++){
43             for(int j=2;j<m1+m2+1;j++){
44                 f[i+1][j-1]+=f[i][j]*(1-mid);
45                 f[i+1][j+1]+=f[i][j]*mid;
46             }
47             f[i+1][1]+=f[i][1];
48             f[i+1][m1+m2+1]+=f[i][m1+m2+1];
49         }
50         printf("%0.5f\n",f[5001][m1+m2+1]);
51     }
52     return 0;
53 }
View Code

T2,咕咕咕

T3,咕咕咕,正解是二维拉格朗日插值,复杂度貌似是$O(n^{5}+n^{4})$,还没有看懂。

但是可以用高斯消元水过,因为常数比较优秀。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #define N 1666
  7 #define mod 1000000007
  8 using namespace std;
  9 int a[44][44],n,m,n1,n2,b[888][888],c[888],f[888],cnt;
 10 int du[100500],dv[100500],dw[100500],ans;
 11 int qp(int a,int b){
 12     int c=1;
 13     for(;b;b>>=1,a=1ll*a*a%mod)
 14         if(b&1)c=1ll*c*a%mod;
 15     return c;
 16 }
 17 void UPD(int &a,int b){
 18     a=(a+b>=mod)?(a+b-mod):(a+b);
 19 }
 20 int work(){
 21     int ans=1;
 22     for(int k=1;k<n;k++){
 23         if(!a[k][k]){
 24             for(int i=k+1;i<n;i++)if(a[i][k]){
 25                 for(int j=k;j<n;j++)swap(a[k][j],a[i][j]);
 26                 ans=mod-ans;
 27                 break;
 28             }
 29         }
 30         if(!a[k][k])return 0;
 31         ans=1ll*ans*a[k][k]%mod;
 32         int inv=qp(a[k][k],mod-2);
 33         for(int i=k+1;i<n;i++){
 34             int t=1ll*a[i][k]*inv%mod;
 35             for(int j=k;j<n;j++)
 36                 UPD(a[i][j],mod-1ll*t*a[k][j]%mod);
 37         }
 38     }
 39     return ans;
 40 }
 41 void add(int u,int v,int w){
 42     UPD(a[u][u],w);
 43     UPD(a[v][v],w);
 44     UPD(a[u][v],mod-w);
 45     UPD(a[v][u],mod-w);
 46 }
 47 void gauss(){
 48     for(int k=1;k<=cnt;k++){
 49         if(!b[k][k]){
 50             for(int i=k+1;i<=cnt;i++)if(b[i][k]){
 51                 for(int j=k;j<=cnt;j++)swap(b[k][j],b[i][j]);
 52                 swap(c[k],c[i]);
 53                 break;
 54             }
 55         }
 56         int ny=qp(b[k][k],mod-2);
 57         for(int i=k+1;i<=cnt;i++){
 58             int t=1ll*b[i][k]*ny%mod;
 59             for(int j=k;j<=cnt;j++)
 60                 UPD(b[i][j],mod-1ll*b[k][j]*t%mod);
 61             UPD(c[i],mod-1ll*c[k]*t%mod);
 62         }
 63     }
 64     for(int i=cnt;i;i--){
 65         for(int j=i+1;j<=cnt;j++)
 66             UPD(c[i],mod-1ll*b[i][j]*f[j]%mod);
 67         f[i]=1ll*c[i]*qp(b[i][i],mod-2)%mod;
 68     }
 69 }
 70 int g[44][44][5];
 71 int main(){
 72     scanf("%d%d%d%d",&n,&m,&n1,&n2);
 73     for(int i=1;i<=m;i++){
 74         scanf("%d%d%d",&du[i],&dv[i],&dw[i]);
 75         g[du[i]][dv[i]][dw[i]]++;
 76     }
 77     for(int x=0;x<n;x++){
 78         for(int y=0;y<n-x;y++){
 79             memset(a,0,sizeof a);
 80             for(int i=1;i<=n;i++)
 81                 for(int j=1;j<=n;j++)
 82                     for(int k=1;k<=3;k++)if(g[i][j][k]){
 83                         if(k==1)add(i,j,g[i][j][k]);
 84                         if(k==2)add(i,j,x*g[i][j][k]);
 85                         if(k==3)add(i,j,y*g[i][j][k]);
 86                     }
 87             c[++cnt]=work();
 88             for(int i=0,now=0,nx=1;i<n;i++){
 89                 for(int j=0,ny=1;j<n-i;j++){
 90                     b[cnt][++now]=1ll*nx*ny%mod;
 91                     ny=1ll*ny*y%mod;
 92                 }
 93                 nx=1ll*nx*x%mod;
 94             }
 95         }
 96     }
 97     gauss();
 98     for(int i=0,now=1;i<n;i++){
 99         for(int j=0;j<n-i;j++,now++)
100             if(i<=n1&&j<=n2)UPD(ans,f[now]);
101     }
102     printf("%d\n",ans);
103     return 0;
104 }
View Code

 4.24

先看T1,发现40分sb主席树乱搞,后面的离线可以莫队?然后看T2,看起来可以线筛+杜教筛,看T3,感觉就10分暴力可写。然后回去码T1,写完40分,和暴力拍上了,然后想w=1的,yy了半个多小时,没有想出来。然后去写T2,写了个O(40n)的筛(我是傻逼),又推了推式子,没推出来,然后拿着k=40的数据去猜k=1的结论,啥也没发现。然后还有1h左右,在T1的离线和T3的暴力中选择了T1,写了30min左右写完了,感觉很开心,发现还有时间去写T3,然后手贱测了组极限数据,7s。。。然后致力卡常办小时,还是没卡进去。40+30+0=70 rank6/10。这两天暴力分不是挂了就是没有拿满,以后要注意这个问题。

T1,我们考虑对于每一个查询,可以改变每个点作出的贡献,然后二分答案,计算小于ans且个数小于w的数的个数,于是我们对于一个权值,将他最后w个的权值附成1,倒数第w+1个的权值设成-w。然后我们可以知道对于一个数,他对哪些区间的贡献是1,-w。这可以对应到平面上的一个矩形,然后我们就相当于是矩形加,单点求和。这个可以主席数套线段树来做,外层是关于左端点的可持久化权值线段树,内层是关于右端点的线段树。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <vector>
 7 #define N 100500
 8 using namespace std;
 9 vector <int> v[N];
10 int n,w,q,type,a[N],np[N],nnp[N];
11 int lazy[800*N],ls[800*N],rs[800*N],tot;
12 int root[N],rt[50*N],lon[50*N],ron[50*N],sz;
13 void _update(int &rt,int l,int r,int x,int y,int z){
14     if(!rt)rt=++tot;
15     if(x<=l&&r<=y){lazy[rt]+=z;return ;}
16     int mid=(l+r)>>1;
17     if(x<=mid)_update(ls[rt],l,mid,x,y,z);
18     if(y>mid)_update(rs[rt],mid+1,r,x,y,z);
19 }
20 void _merge(int o,int &rt,int l,int r){
21     if(!o)return ;
22     if(!rt){rt=o;return ;}
23     lazy[rt]+=lazy[o];
24     if(l==r)return ;
25     int mid=(l+r)>>1;
26     _merge(ls[o],ls[rt],l,mid);
27     _merge(rs[o],rs[rt],mid+1,r);
28 }
29 int _query(int o,int rt,int l,int r,int x){
30     if(l==r)return lazy[rt]-lazy[o];
31     int mid=(l+r)>>1;
32     if(x<=mid)return _query(ls[o],ls[rt],l,mid,x)+lazy[rt]-lazy[o];
33     else return _query(rs[o],rs[rt],mid+1,r,x)+lazy[rt]-lazy[o];
34 }
35 void update(int &rt,int l,int r,int x,int nl,int nr,int nx){
36     if(!rt)rt=++sz;
37     _update(::rt[rt],1,n,nl,nr,nx);
38     if(l==r)return ;
39     int mid=(l+r)>>1;
40     if(x<=mid)update(lon[rt],l,mid,x,nl,nr,nx);
41     else update(ron[rt],mid+1,r,x,nl,nr,nx);
42 }
43 void merge(int o,int &rt,int l,int r){
44     if(!o)return ;
45     if(!rt){rt=o;return;}
46     _merge(::rt[o],::rt[rt],1,n);
47     if(l==r)return ;
48     int mid=(l+r)>>1;
49     merge(lon[o],lon[rt],l,mid);
50     merge(ron[o],ron[rt],mid+1,r);
51 }
52 int query(int o,int rt,int l,int r,int x,int k){
53     if(l==r)return l;
54     int mid=(l+r)>>1;
55     int now=_query(::rt[lon[o]],::rt[lon[rt]],1,n,x);
56     if(now>=k)return query(lon[o],lon[rt],l,mid,x,k);
57     else return query(ron[o],ron[rt],mid+1,r,x,k-now);
58 }
59 int main(){
60     scanf("%d%d%d%d",&n,&w,&q,&type);
61     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
62     for(int i=1;i<=n;i++){
63         v[a[i]].push_back(i);
64         if(v[a[i]].size()>w){
65             np[v[a[i]][v[a[i]].size()-w-1]]=i;
66             if(v[a[i]].size()>w+1)
67                 nnp[v[a[i]][v[a[i]].size()-w-2]]=i;
68         }
69     }
70     for(int i=1;i<=n;i++){
71         if(!np[i])np[i]=n+1;
72         if(!nnp[i])nnp[i]=n+1;
73         update(root[i],0,n-1,a[i],i,np[i]-1,1);
74         if(np[i]<=n)update(root[i],0,n-1,a[i],np[i],nnp[i]-1,-w);
75         merge(root[i-1],root[i],0,n-1);
76     }
77     int ans=0;
78     for(int t=1,l,r,k,now;t<=q;t++){
79         scanf("%d%d%d",&l,&r,&k);
80         if(type)l^=ans,r^=ans,k^=ans;
81         now=_query(rt[root[l-1]],rt[root[r]],1,n,r);
82         if(now<k)ans=n;
83         else ans=query(root[l-1],root[r],0,n-1,r,k);
84         printf("%d\n",ans);
85     }
86     return 0;
87 }
View Code

T2,容斥来求$\sum_{i=1}^{n}{f_{d}{[n]}}$,我们设$\lambda{[i]}=f_{\infty}{[i]}$,我们现在要求的就是

$$F_{d}{[n]}=\sum_{i=1}^{n}{\mu{[i]} \sum_{j=1}^{ \lfloor \frac{n}{i^{d+1}} \rfloor} {\lambda{[i^{d+1} \cdot j ]}} }$$

然后因为$\lambda$是完全积性函数,所以我们把关于i的都提到外面,我们现在还需要求一个$\sum{\lambda}$,然后我们发现$\lambda \otimes 1 = [x  \; is \;  Perfect   \;Square]$,然后就可以杜教筛了。

 1 #include <bits/stdc++.h>
 2 #define N 5005000
 3 #define int long long
 4 using namespace std;
 5 int prime[N/10],tot,n,m,ans;
 6 bool vis[N];
 7 int mu[N],lmd[N],slmd[N],phi[N],sphi[N],pw[100500][44];
 8 int f[N],sf[N],tim[N],mx[N];
 9 unordered_map<int,int> hphi,hlmd;
10 void init(){
11     mu[1]=1;mx[1]=1;
12     lmd[1]=slmd[1]=1;
13     phi[1]=sphi[1]=1;
14     for(int i=2;i<=5000000;i++){
15         if(!vis[i]){
16             prime[++tot]=i;
17             phi[i]=i-1;mu[i]=lmd[i]=-1;
18             tim[i]=mx[i]=1;
19         }
20         for(int j=1;j<=tot&&i*prime[j]<=5000000;j++){
21             vis[i*prime[j]]=1;
22             lmd[i*prime[j]]=-lmd[i];
23             if(i%prime[j]==0){
24                 tim[i*prime[j]]=tim[i]+1;
25                 mx[i*prime[j]]=max(mx[i],tim[i]+1);
26                 phi[i*prime[j]]=phi[i]*prime[j];
27                 mu[i*prime[j]]=0;
28                 break;
29             }
30             phi[i*prime[j]]=phi[i]*phi[prime[j]];
31             mu[i*prime[j]]=-mu[i];
32             tim[i*prime[j]]=1;
33             mx[i*prime[j]]=mx[i];
34         }
35         sphi[i]=sphi[i-1]+phi[i];
36         slmd[i]=slmd[i-1]+lmd[i];
37     }
38     for(int i=1;i<=5000000;i++){
39         f[i]=lmd[i]*max(0ll,m-mx[i]+1);
40         sf[i]=sf[i-1]+f[i];   
41     }
42     for(int i=1;i<=100000;i++){
43         pw[i][0]=1;
44         for(int j=1;j<=41;j++){
45             pw[i][j]=pw[i][j-1]*i;
46             if(pw[i][j]>10000000000ll)break;
47         }
48     }
49 }
50 int getsphi(int n){
51     if(n<=5000000)return sphi[n];
52     if(hphi.count(n))return hphi[n];
53     int ans=1ll*n*(n+1)/2;
54     for(int i=2,j;i<=n;i=j+1){
55         j=n/(n/i);
56         ans-=(j-i+1)*getsphi(n/i);
57     }
58     return hphi[n]=ans;
59 }
60 int getslmd(int n){
61     if(n<=5000000)return slmd[n];
62     if(hlmd.count(n))return hlmd[n];
63     int ans=sqrt(n);
64     for(int i=2,j;i<=n;i=j+1){
65         j=n/(n/i);
66         ans-=(j-i+1)*getslmd(n/i);
67     }
68     return hlmd[n]=ans;
69 }
70 int getf(int d,int x){
71     int ans=0;
72     for(int i=1;pw[i][d+1]&&pw[i][d+1]<=x;i++)
73         ans+=((d&1)?(1):(lmd[i]))*mu[i]*getslmd(x/pw[i][d+1]);
74     return ans;
75 }
76 int getsf(int x){
77     if(x<=5000000)return sf[x];
78     int ans=0;
79     for(int d=1;d<=m;d++)ans+=getf(d,x);
80     return ans;
81 }
82 int gcd(int a,int b){return !b?a:gcd(b,a%b);}
83 signed main(){
84     scanf("%lld%lld",&n,&m);
85     init();
86     for(int i=1,j,last=0,now;i<=n;i=j+1){
87         j=n/(n/i);
88         now=getsf(j);
89         ans+=(now-last)*(2*getsphi(n/i)-1);
90         last=now;
91     }
92     printf("%lld\n",ans&1073741823);
93 }
View Code

T3,我们利用期望的线性性,考虑求出每个点的贡献,即每个点的期望经过次数*其对应的距离,我们考虑如何求出一个状态下某个点的期望经过次数,因为选点是随机的,所以我们只需统记若干1的状态下0,1的点的期望经过次数,我们考虑在这一层算下一步造成的贡献,于是转移方程就有了。

$$f_{i,0}=\frac{i}{n} f_{i-1,0} + \frac{n-i-1}{n} f_{i+1,0}  +\frac{1}{n}(f_{i+1,1}+[notend_{i+1}])$$

$$f_{i,1}=\frac{i-1}{n}f_{i-1,1} +\frac{n-i}{n} f_{i+1,1} +\frac{1}{n}(f_{i-1,0}+[notend_{i-1}])$$

然后我们知道$f_{0/n,0/1}=0$,我们在设$f_{1,0}=x,f_{1,1}=y$,然后推到$f_{n-1}$,然后我们就可以解二元一次方程组了。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #define mod 1000000007
  7 #define N 100500
  8 using namespace std;
  9 int n,num1,inv[N],ans;
 10 char s[N];
 11 struct data{
 12     int x,y,z;
 13     data(){x=y=z=0;}
 14     data(int a,int b,int c){x=a;y=b;z=c;}
 15     data operator + (data a){return data((x+a.x)%mod,(y+a.y)%mod,(z+a.z)%mod);}
 16     data operator - (data a){return data((x-a.x+mod)%mod,(y-a.y+mod)%mod,(z-a.z+mod)%mod);}
 17     data operator * (int a){return data(1ll*x*a%mod,1ll*y*a%mod,1ll*z*a%mod);}
 18 }f[N][2],one;
 19 int qp(int a,int b){
 20     int c=1;
 21     for(;b;b>>=1,a=1ll*a*a%mod)
 22         if(b&1)c=1ll*c*a%mod;
 23     return c;
 24 }
 25 void UPD(int &a,int b){
 26     a=(a+b>=mod)?(a+b-mod):(a+b);
 27 }
 28 namespace graph{
 29     int e=1,head[N],d1[N],d2[N],d[N],size[N];
 30     struct edge{
 31         int v,next;
 32     }ed[N<<1];
 33     void add(int u,int v){
 34         ed[e].v=v;ed[e].next=head[u];
 35         head[u]=e++;
 36     }
 37     void dfs1(int x,int f){
 38         size[x]=1;
 39         for(int i=head[x];i;i=ed[i].next){
 40             int v=ed[i].v;
 41             if(v==f)continue;
 42             dfs1(v,x);
 43             d1[x]+=d1[v]+size[v];
 44             size[x]+=size[v];
 45         }
 46     }
 47     void dfs2(int x,int f){
 48         for(int i=head[x];i;i=ed[i].next){
 49             int v=ed[i].v;
 50             if(v==f)continue;
 51             d2[v]=d2[x]+(d1[x]-d1[v]-size[v])+(n-size[v]);
 52             dfs2(v,x);
 53         }
 54         d[x]=1ll*(d1[x]+d2[x])*inv[n]%mod;
 55     }
 56 }
 57 using namespace graph;
 58 int main(){
 59 //freopen("test.in","r",stdin);
 60     scanf("%d",&n);
 61     scanf("%s",s+1);
 62     for(int i=1;i<=n;i++)
 63         if(s[i]=='1')num1++;
 64     inv[0]=inv[1]=1;
 65     for(int i=2,x;i<=n;i++){
 66         scanf("%d",&x);
 67         add(x,i);add(i,x);
 68         inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod;
 69     }
 70     dfs1(1,0);dfs2(1,0);
 71      
 72     f[0][0]=data(0,0,0);
 73     f[0][1]=data(0,0,0);
 74     f[1][0]=data(1,0,0);
 75     f[1][1]=data(0,1,0);
 76     one=data(0,0,1);
 77      
 78     f[2][1]=(f[1][1]*n)*inv[n-1];
 79     f[2][0]=(f[1][0]*n-f[2][1]-one)*inv[n-2];
 80     for(int i=3;i<n;i++){
 81         f[i][1]=(f[i-1][1]*n-f[i-2][1]*(i-2)-f[i-2][0]-one)*inv[n-i+1];
 82         f[i][0]=(f[i-1][0]*n-f[i-2][0]*(i-1)-f[i][1]-one)*inv[n-i];
 83     }
 84     f[n-1][1]=f[n-1][1]*n-f[n-2][1]*(n-2)-f[n-2][0]-(n==2?data(0,0,0):one);
 85     f[n-1][0]=f[n-1][0]*n-f[n-2][0]*(n-1);
 86      
 87     //printf("%d %d %d\n",f[n-1][1].x,f[n-1][1].y,f[n-1][1].z);
 88     //printf("%d %d %d\n",f[n-1][0].x,f[n-1][0].y,f[n-1][0].z);
 89      
 90     int a1=f[n-1][1].x,b1=f[n-1][1].y,c1=mod-f[n-1][1].z;
 91     int a2=f[n-1][0].x,b2=f[n-1][0].y,c2=mod-f[n-1][0].z;
 92     int d1=(1ll*c1*a2%mod-1ll*c2*a1%mod+mod)%mod;
 93     int d2=(1ll*b1*a2%mod-1ll*b2*a1%mod+mod)%mod;
 94     int y=1ll*d1*qp(d2,mod-2)%mod;
 95     int x=1ll*(c1-1ll*b1*y%mod+mod)%mod*qp(a1,mod-2)%mod;
 96      
 97     //printf("x==%d  y==%d\n",x,y);
 98      
 99     int f0=((1ll*f[num1][0].x*x%mod+1ll*f[num1][0].y*y%mod)%mod+f[num1][0].z)%mod;
100     int f1=((1ll*f[num1][1].x*x%mod+1ll*f[num1][1].y*y%mod)%mod+f[num1][1].z)%mod;
101      
102     //printf("f0==%d  f1==%d\n",f0,f1);
103      
104     for(int i=1;i<=n;i++){
105         if(s[i]=='0')UPD(ans,1ll*(f0+inv[n])*d[i]%mod);
106         else UPD(ans,1ll*(f1+inv[n])*d[i]%mod);
107     }
108     printf("%d\n",ans);
109     return 0;
110 }
View Code

 4.26

今天这套题,充分暴露了我的问题,不能怪题,还是自己弱。

开场先读题,发现T1计算几何好像很清真,T2貌似是回文自动机?T3是DP?然后思考了20minT1,开始写,写了1h左右写完了,然后造了几组小样例调了调,然后过不了大样例,然后开始死磕,然后还有90min时发现后两题还没看,然后把暴力都写上了,接着调,最后一个小时手玩发现样例好像是错的,然后就崩溃了。最后看了一眼T3,发现好像是傻逼网络流,没时间打了。80+30+20=130 rank7,wq,zzhAK了??T1可以忽略多边形???这么傻逼,T3果然是sb网络流,T2貌似也是sb题,然后就GG了。后来发现是我重心求错了,他要求整个面积的重心,而我求的是多边形的重心。

T1,数据太水了,我的代码好像也不对。就是大模拟。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 using namespace std;
 7 #define eps 1e-8
 8 const double pi=acos(-1.0);
 9 struct point{
10     double x,y;
11     point (){x=y=0;}
12     point (double a,double b){x=a;y=b;}
13     point operator + (point a){return point(x+a.x,y+a.y);}
14     point operator - (point a){return point(x-a.x,y-a.y);}
15     double operator * (point a){return x*a.y-y*a.x;}
16     point operator * (double a){return point(x*a,y*a);}
17     point operator / (double a){return point(x/a,y/a);}
18 }sun,ear,g,p[33],np;
19 int n;
20 double t1,t2,t,R,alp,dis,alpl,alpr,pl,pr,ans;
21 double getdis(point a){
22     return sqrt(a.x*a.x+a.y*a.y);
23 }
24 bool cross1(point a){
25     for(int i=1;i<=n;i++)
26         if(getdis(p[i]-sun)<=getdis(a-sun)&&(sun-p[i])*(a-p[i])>=0)return 1;
27     return 0;
28 }
29 bool cross2(point a){
30     for(int i=1;i<=n;i++)
31         if(getdis(p[i]-sun)<=getdis(a-sun)&&(a-p[i])*(sun-p[i])>=0)return 1;
32     return 0;
33 }
34 int main(){
35     scanf("%lf%lf%lf%lf%lf",&sun.x,&sun.y,&ear.x,&ear.y,&R);
36     scanf("%d%lf%lf%lf",&n,&t1,&t2,&t);
37     for(int i=1;i<=n;i++)
38         scanf("%lf%lf",&p[i].x,&p[i].y);
39     for(int i=1;i<=n;i++){
40         alp=atan2(p[i].y-ear.y,p[i].x-ear.x);
41         dis=getdis(p[i]-ear);
42         alp=alp+2*pi/t1*t;
43         p[i]=point(ear.x+dis*cos(alp),ear.y+dis*sin(alp));
44     }
45     double S=0;
46     for(int i=1;i<=n;i++)
47     {
48         double tmp=p[i]*p[i==n?1:i+1];
49         g=g+((p[i]+p[i==n?1:i+1])*tmp);
50         S+=tmp;
51     }
52     g=g/(3*S);
53     for(int i=1;i<=n;i++){
54         alp=atan2(p[i].y-g.y,p[i].x-g.x);
55         dis=getdis(p[i]-g);
56         alp=alp+2*pi/t2*t-2*pi/t1*t;
57         p[i]=point(g.x+dis*cos(alp),g.y+dis*sin(alp));
58     }
59     dis=getdis(ear-sun);
60     dis=sqrt(dis*dis-R*R);
61     alp=atan2(sun.y-ear.y,sun.x-ear.x);
62     double l=0,r=pi,mid;
63     while(l+eps<=r){
64         mid=(l+r)/2.0;
65         if(getdis(sun-point(ear.x+cos(alp+mid)*R,ear.y+sin(alp+mid)*R))<=dis)l=mid;
66         else r=mid;
67     }
68     alpl=alp-mid;alpr=alp+mid;
69     if(alpr<alpl)alpr+=2*pi;
70     l=alpl,r=alpr;
71     while(l+eps<=r){
72         mid=(l+r)/2.0;
73         np=point(ear.x+cos(mid)*R,ear.y+sin(mid)*R);
74         if(cross1(np))r=mid;
75         else l=mid;
76     }
77     pl=mid;
78     l=pl,r=alpr;
79     while(l+eps<=r){
80         mid=(l+r)/2.0;
81         np=point(ear.x+cos(mid)*R,ear.y+sin(mid)*R);
82         if(cross2(np))l=mid;
83         else r=mid;
84     }
85     pr=mid;
86     ans=((alpr-pr)+(pl-alpl))*R;
87     printf("%0.2lf\n",ans);
88     return 0;
89 }
View Code

T2,manacher水题。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define mod 1000000007
 7 #define N 2000500
 8 using namespace std;
 9 int T,n,l[N],f[N],g[N],a1[N],b1[N],a2[N],b2[N],tot,ans,now,de;
10 char s[N],s1[N];
11 void UPD(int &a,int b){
12     a=(a+b>=mod)?(a+b-mod):(a+b);
13 }
14 void manacher(){
15     int mx=0,pos=0;
16     for(int i=1;i<=tot;i++){
17         if(i<mx)l[i]=min(l[2*pos-i],mx-i);
18         else l[i]=0;
19         while(i-l[i]>0&&i+l[i]<=tot&&s1[i-l[i]]==s1[i+l[i]])l[i]++;
20         if(i+l[i]>mx)mx=i+l[i],pos=i;
21         if(i&1){
22             int posl=(i-l[i]+2)>>1,posr=(i+l[i]-2)>>1,posn=(i+1)>>1;
23             if(posl>posr)continue;
24             UPD(a1[posl],posr);UPD(b1[posl],mod-1);
25             UPD(a1[posn],mod-posn+1);UPD(b1[posn],1);
26              
27             UPD(a2[posr],posl);UPD(b2[posr],1);
28             UPD(a2[posn-1],mod-posn);UPD(b2[posn-1],mod-1);
29         }
30         else{
31             int posl=(i-l[i]+2)>>1,posr=(i+l[i]-2)>>1,posn=i>>1;
32             if(posl>posr)continue;
33             UPD(a1[posl],posr);UPD(b1[posl],mod-1);
34             UPD(a1[posn+1],mod-posn+1);UPD(b1[posn+1],1);
35              
36             UPD(a2[posr],posl);UPD(b2[posr],1);
37             UPD(a2[posn-1],mod-posn-1);UPD(b2[posn-1],mod-1);
38         }
39     }
40 }
41 int main(){
42 //freopen("test.in","r",stdin);
43     scanf("%d",&T);
44     while(T--){
45         scanf("%s",s+1);
46         n=strlen(s+1);
47         ans=tot=0;
48         memset(a1,0,sizeof a1);
49         memset(b1,0,sizeof b1);
50         memset(a2,0,sizeof a2);
51         memset(b2,0,sizeof b2);
52         s1[++tot]='#';
53         for(int i=1;i<=n;i++){
54             s1[++tot]=s[i];
55             s1[++tot]='#';
56         }
57         manacher();
58         now=de=0;
59         for(int i=1;i<=n;i++){
60             UPD(now,de);
61             UPD(now,a1[i]);
62             UPD(de,b1[i]);
63             f[i]=now;
64         }
65         now=de=0;
66         for(int i=n;i;i--){
67             UPD(now,de);
68             UPD(now,a2[i]);
69             UPD(de,b2[i]);
70             g[i]=now;
71         }
72         ans=0;
73         for(int i=1;i<n;i++)
74             UPD(ans,1ll*g[i]*f[i+1]%mod);
75         printf("%d\n",ans);
76     }
77     return 0;
78 }
View Code

T3,网络流水题,最大权闭合子图加上文理分科的思想。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <queue>
 7 #define inf 0x3fffffff
 8 #define N 150
 9 using namespace std;
10 int Tim,n,ans,buc[11],a[11],b[11],c[N],w[N][N];
11 char s[N];
12 int e=2,head[N];
13 struct edge{
14     int u,v,f,next;
15 }ed[N*N<<2];
16 void add(int u,int v,int f1,int f2){
17     ed[e].u=u;ed[e].v=v;ed[e].f=f1;
18     ed[e].next=head[u];head[u]=e++;
19     ed[e].u=v;ed[e].v=u;ed[e].f=f2;
20     ed[e].next=head[v];head[v]=e++;
21 }
22 int dep[N],S,T;
23 bool bfs(){
24     memset(dep,0,sizeof dep);
25     dep[S]=1;
26     queue<int> q;q.push(S);
27     while(!q.empty()){
28         int x=q.front();q.pop();
29         for(int i=head[x];i;i=ed[i].next){
30             int v=ed[i].v;
31             if(ed[i].f&&!dep[v]){
32                 dep[v]=dep[x]+1;
33                 if(v==T)return 1;
34                 q.push(v);
35             }
36         }
37     }
38     return 0;
39 }
40 int dfs(int x,int f){
41     if(x==T||!f)return f;
42     int ans=0;
43     for(int i=head[x];i;i=ed[i].next){
44         int v=ed[i].v;
45         if(ed[i].v&&dep[v]==dep[x]+1){
46             int nxt=dfs(v,min(f,ed[i].f));
47             ans+=nxt;f-=nxt;ed[i].f-=nxt;ed[i^1].f+=nxt;
48             if(!f)break;
49         }
50     }
51     if(!ans)dep[x]=-1;
52     return ans;
53 }
54 int dinic(){
55     int ans=0;
56     while(bfs())ans+=dfs(S,inf);
57     return ans;
58 }
59 int sum[N];
60 int main(){
61     scanf("%d",&Tim);
62     while(Tim--){
63         scanf("%d",&n);ans=0;
64         scanf("%s",s+1);
65         for(int i=1;i<=n;i++)c[i]=s[i]-'0';
66         for(int i=0;i<=9;i++)
67             scanf("%d%d",&a[i],&b[i]);
68         memset(sum,0,sizeof sum);
69         for(int i=1;i<=n;i++)
70             for(int j=1;j<=n;j++){
71                 scanf("%d",&w[i][j]);
72                 if(i==j)continue;
73                 sum[i]+=w[i][j];
74                 sum[j]+=w[i][j];
75                 ans+=2*w[i][j];
76             }
77         e=2;memset(head,0,sizeof head);
78         S=n+11;T=S+1;
79         for(int i=0;i<=9;i++)add(n+i+1,T,2*(b[i]-a[i]),0);
80         for(int i=1;i<=n;i++){
81             add(S,i,sum[i],0);
82             add(i,T,2*a[c[i]],0);
83             add(i,n+c[i]+1,inf,0);
84             for(int j=i+1;j<=n;j++)
85                 add(i,j,w[i][j]+w[j][i],w[i][j]+w[j][i]);
86         }
87         printf("%d\n",(ans-dinic())/2);
88     }
89     return 0;
90 }
View Code

RP上红,233。

加油吧。

4.27

吸取昨天的教训,先读了一遍题,发现T2原题,T1,T3都不会。然后T2换题了,看了看好像是裸插头。觉得T1是多项式,然后推,推了一个多小时,没推出来,puts了样例,然后去把T3的暴力打了,之后去看T2,写插头DP,写完发现看错数据范围了。然后过了样例,没怎么检查,然后去推T1的70分,感觉是个dp,还是没推出来。然后GG,5+11+30=46 rank6,T2,插头dp情况没讨论全挂了24分,T1貌似O(n^4)暴力dp很清真。然而正解是二分图生成树。T3分块。。。

T1,$O(n^{4})$,dp是枚举一个点所在树的大小,然后套路组合数转移。然后我们发现把奇数层和偶数层看成两种点,其实是求完全二分图的生成树个数,这个我们可以打表发现答案是$S(n,m)=n^{m-1}+m^{n-1}$,最后$ans=C_{n-1}^{m-1} \cdot S(n-m,m)$

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 using namespace std;
 7 int n,m,mod,inv[500500];
 8 int qp(int a,int b){
 9     int c=1;
10     for(;b;b>>=1,a=1ll*a*a%mod)
11         if(b&1)c=1ll*c*a%mod;
12     return c;
13 }
14 int C(int n,int m){
15     m=min(m,n-m);
16     int ans=1;
17     for(int i=1;i<=m;i++)
18         ans=1ll*ans*(n-i+1)%mod;
19     inv[1]=1;
20     for(int i=2;i<=m;i++){
21         inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod;
22         ans=1ll*ans*inv[i]%mod;
23     }
24     return ans;
25 }
26 int main(){
27     scanf("%d%d%d",&n,&m,&mod);
28     printf("%lld\n",1ll*C(n-1,m-1)*qp(m,n-m-1)%mod*qp(n-m,m-1)%mod);
29     return 0;
30 }
View Code

T2,35分插头dp

  1 #pragma GCC optimize ("O3")
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <cmath>
  7 #define N 35
  8 #define inf 0x3fffffff
  9 using namespace std;
 10 int n,m,num,vis[N][N],c[N][N],d[N][N];
 11 int now,last,mx,my,ans,Tim;
 12 struct hash_table{
 13     static const int P=333331;
 14     int head[P+10],nxt[P+10],val[P+10],tot,key[P+10];
 15     void clear(){
 16         memset(head,0,sizeof head);
 17         tot=0;
 18     }
 19     void add(int x,int v){
 20         int y=x%P;
 21         nxt[++tot]=head[y];head[y]=tot;
 22         key[tot]=x;val[tot]=v;
 23     }
 24     int & operator [] (int x){
 25         int y=x%P;
 26         for(int i=head[y];i;i=nxt[i])
 27             if(key[i]==x)return val[i];
 28         add(x,-inf);
 29         return val[tot];
 30     }
 31 }f[2];
 32 int gets(int x,int y){
 33     return ((x>>((y-1)*2))&3);
 34 }
 35 int find(int x,int y){
 36     for(int i=y,cnt=0,now,pos=(gets(x,y)==1?1:-1);;i+=pos){
 37         now=gets(x,i);
 38         if(now==1)cnt++;
 39         if(now==2)cnt--;
 40         if(!cnt)return i;
 41     }
 42 }
 43 void change(int &x,int y,int z){
 44     x^=(gets(x,y)<<(2*(y-1)))^(z<<(2*(y-1)));
 45 }
 46 void dp(int i,int j){
 47     swap(now,last);
 48     f[now].clear();
 49     for(int k=1;k<=f[last].tot;k++){
 50         int nf=f[last].val[k],s=f[last].key[k];
 51         int x=gets(s,j),y=gets(s,j+1);
 52         if(x==1&&y==2){
 53             change(s,j,0);change(s,j+1,0);
 54             if((!s)&&(i>mx||(i==mx&&j>=my)))
 55                 ans=max(ans,nf);
 56             f[now][s]=max(f[now][s],nf);
 57         }
 58         else if(x==2&&y==1){
 59             change(s,j,0);change(s,j+1,0);
 60             f[now][s]=max(f[now][s],nf);
 61         }
 62         else if(x==1&&y==1){
 63             change(s,find(s,j+1),1);
 64             change(s,j,0);change(s,j+1,0);
 65             f[now][s]=max(f[now][s],nf);
 66         }
 67         else if(x==2&&y==2){
 68             change(s,find(s,j),2);
 69             change(s,j,0);change(s,j+1,0);
 70             f[now][s]=max(f[now][s],nf);
 71         }
 72         else if(!x&&!y){
 73             if(!vis[i][j])f[now][s]=max(f[now][s],nf);
 74             if(i==n||j==m)continue;
 75             change(s,j,1);change(s,j+1,2);
 76             f[now][s]=max(f[now][s],nf+c[i][j]+d[i][j]);
 77         }
 78         else if(x&&!y){
 79             if(i==n)continue;
 80             f[now][s]=max(f[now][s],nf+d[i][j]);
 81         }
 82         else if(!x&&y){
 83             if(j==m)continue;
 84             f[now][s]=max(f[now][s],nf+c[i][j]);
 85         }
 86     }
 87 }
 88 int main(){
 89 //freopen("bounce5d.in","r",stdin);
 90 //freopen("1.out","w",stdout);
 91     scanf("%d",&Tim);
 92     while(Tim--){
 93         scanf("%d%d",&n,&m);
 94         //if(n>10&&m>10){puts("0");continue;}
 95         if(n>=m){
 96             for(int i=1;i<=n;i++)
 97                 for(int j=1;j<m;j++)
 98                     scanf("%d",&c[i][j]);
 99             for(int i=1;i<n;i++)
100                 for(int j=1;j<=m;j++)
101                     scanf("%d",&d[i][j]);
102             memset(vis,0,sizeof vis);
103             scanf("%d",&num);
104             mx=my=0;
105             for(int i=1,x,y;i<=num;i++){
106                 scanf("%d%d",&x,&y);
107                 vis[x][y]=1;
108                 if(x>mx)mx=x,my=y;
109                 else if(x==mx&&y>my)my=y;
110             }
111         }
112         else{
113             swap(n,m);
114             for(int j=1;j<=m;j++)
115                 for(int i=1;i<n;i++)
116                     scanf("%d",&d[i][j]);
117             for(int j=1;j<m;j++)
118                 for(int i=1;i<=n;i++)
119                     scanf("%d",&c[i][j]);
120             memset(vis,0,sizeof vis);
121             scanf("%d",&num);
122             mx=my=0;
123             for(int i=1,x,y;i<=num;i++){
124                 scanf("%d%d",&y,&x);
125                 vis[x][y]=1;
126                 if(x>mx)mx=x,my=y;
127                 else if(x==mx&&y>my)my=y;
128             }
129         }
130         now=1,last=0,ans=-inf;
131         if(!num)ans=0;
132         f[now].clear();
133         f[now][0]=0;
134         for(int i=1;i<=n;i++){
135             for(int j=1;j<=m;j++)
136                 dp(i,j);
137             swap(now,last);
138             f[now].clear();
139             for(int k=1;k<=f[last].tot;k++)
140                 f[now][f[last].key[k]<<2]=max(f[now][f[last].key[k]<<2],f[last].val[k]);
141         }
142         if(ans==-inf)puts("Impossible");
143         else printf("%d\n",ans);
144     }
145 }
View Code

正解网络流,其实还是套路,我们把每个点拆点,然后自己流一条S->x1->x2->T,然后黑白染色,分别是横进竖出,竖进横出,如果x可以到y,那么x1->y2连一条边,这样x2也需要一个流量,y1也需要出一个流量,就可以跑最小费用最大流了。

  1 #pragma GCC optimize ("O3")
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N 33
  6 #define inf 0x3fffffff
  7 using namespace std;
  8 int n,m,num,vis[N][N],c[N][N],d[N][N],Tim;
  9 int e,head[N*N<<1];
 10 struct edge{
 11     int u,v,w,f,next;
 12 }ed[(N*N)<<4];
 13 void add(int u,int v,int f,int w){
 14     ed[e].u=u;ed[e].v=v;ed[e].f=f;ed[e].w=w;
 15     ed[e].next=head[u];head[u]=e++;
 16     ed[e].u=v;ed[e].v=u;ed[e].f=0;ed[e].w=-w;
 17     ed[e].next=head[v];head[v]=e++;
 18 }
 19 #define id(i,j) (((i)-1)*2+(j))
 20 int dis[N*N<<1],Flow,Cost,S,T,id[N][N],tot1,tot2;
 21 int bo[N*N<<1],tim;
 22 int q[N*N*N],he,ta;
 23 bool spfa(){
 24     memset(dis,-0x3f,sizeof dis);
 25     tim++;dis[S]=0;
 26     he=ta=1;q[1]=S;
 27     while(he<=ta){
 28         int x=q[he++];bo[x]=0;
 29         for(int i=head[x];i;i=ed[i].next){
 30             int v=ed[i].v;
 31             if(ed[i].f&&dis[v]<dis[x]+ed[i].w){
 32                 dis[v]=dis[x]+ed[i].w;
 33                 if(bo[v]!=tim){bo[v]=tim;q[++ta]=v;}
 34             }
 35         }
 36     }
 37     return dis[T]!=dis[0];
 38 }
 39 int dfs(int x,int f){
 40     bo[x]=tim;
 41     if(x==T){
 42         Cost+=dis[T]*f;
 43         Flow+=f;
 44         return f;
 45     }
 46     if(!f)return 0;
 47     int ans=0;
 48     for(int i=head[x];i;i=ed[i].next){
 49         int v=ed[i].v;
 50         if(ed[i].f&&dis[v]==dis[x]+ed[i].w&&bo[v]!=tim){
 51             int nxt=dfs(v,min(f,ed[i].f));
 52             ans+=nxt;f-=nxt;ed[i].f-=nxt;ed[i^1].f+=nxt;
 53             if(!f)break;
 54         }
 55     }
 56     return ans;
 57 }
 58 void work(){
 59     Cost=Flow=0;
 60     while(spfa()){
 61         do{
 62             tim++;
 63             dfs(S,inf);
 64         }while(bo[T]==tim);
 65     }
 66     if(Flow!=n*m)puts("Impossible");
 67     else printf("%d\n",Cost);
 68     return ;
 69 }
 70 int main(){
 71 //freopen("bounce6e.in","r",stdin);
 72 //freopen("4.out","w",stdout);
 73     scanf("%d",&Tim);
 74     while(Tim--){
 75         scanf("%d%d",&n,&m);
 76         for(int i=1;i<=n;i++)
 77             for(int j=1;j<m;j++)
 78                 scanf("%d",&c[i][j]);
 79         for(int i=1;i<n;i++)
 80             for(int j=1;j<=m;j++)
 81                 scanf("%d",&d[i][j]);
 82         scanf("%d",&num);
 83         memset(vis,0,sizeof vis);
 84         for(int i=1,x,y;i<=num;i++){
 85             scanf("%d%d",&x,&y);
 86             vis[x][y]=1;
 87         }
 88         tot1=tot2=0;
 89         for(int i=1;i<=n;i++){
 90             for(int j=1;j<=m;j++){
 91                 if((i+j)&1)id[i][j]=++tot1;
 92                 else id[i][j]=++tot2;
 93             }
 94         }
 95         for(int i=1;i<=n;i++)
 96             for(int j=1;j<=m;j++)
 97                 if(!((i+j)&1))id[i][j]+=tot1;
 98         S=n*m*2+1;T=S+1;
 99         e=2,memset(head,0,sizeof head);
100         for(int i=1;i<=n;i++){
101             for(int j=1;j<m;j++){
102                 if((i+j)&1)add(id(id[i][j],1),id(id[i][j+1],2),1,c[i][j]);
103                 else add(id(id[i][j+1],1),id(id[i][j],2),1,c[i][j]);
104             }
105         }
106         for(int i=1;i<n;i++){
107             for(int j=1;j<=m;j++){
108                 if((i+j)&1)add(id(id[i+1][j],1),id(id[i][j],2),1,d[i][j]);
109                 else add(id(id[i][j],1),id(id[i+1][j],2),1,d[i][j]);
110             }
111         }
112         for(int i=1;i<=n;i++){
113             for(int j=1;j<=m;j++){
114                 add(S,id(id[i][j],1),1,0);
115                 add(id(id[i][j],2),T,1,0);
116                 if(!vis[i][j])add(id(id[i][j],1),id(id[i][j],2),1,0);
117             }
118         }
119         work();
120     }
121 }
View Code

T3,分块,我们发现权值范围很小,然后分块时要保证每个块的权值范围不超过$len*sqrt{n}$,然后每$\sqrt{m}$次操作暴力重构。

感觉根号的思路都很巧妙,放到数列上就是分块莫队之类的,脑洞很大,思路清奇。

  1 #pragma GCC optimize ("O3")
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <cmath>
  7 #define N 100500
  8 using namespace std;
  9 int e=1,head[N];
 10 struct edge{
 11     int u,v,w,next;
 12 }ed[N];
 13 void add(int u,int v,int w){
 14     ed[e].u=u;ed[e].v=v;ed[e].w=w;
 15     ed[e].next=head[u];head[u]=e++;
 16 }
 17 int a[N],tot,L[N],R[N],cnt,be[N],fro[N],en[N];
 18 int minn[705],maxn[705],buc[705][5050],Low,High,mx,mn;
 19 int n,m,len,nn,mm,lazy[705];
 20 void dfs(int x,int dep){
 21     a[++tot]=dep;
 22     L[x]=tot;
 23     for(int i=head[x];i;i=ed[i].next)
 24         dfs(ed[i].v,dep+ed[i].w);
 25     R[x]=tot;
 26 }
 27 void build(){
 28     if(cnt){
 29         for(int i=1;i<=cnt;i++){
 30             for(int j=0;j<=maxn[i]-minn[i];j++)
 31                 buc[i][j]=0;
 32             for(int j=fro[i];j<=en[i];j++)
 33                 a[j]+=lazy[i];
 34             lazy[i]=0;
 35         }
 36         cnt=0;
 37     }
 38     mx=mn=a[1];be[1]=++cnt;fro[cnt]=1;
 39     for(int i=2;i<=n;i++){
 40         if(i-fro[cnt]>nn||max(mx,a[i])-min(mn,a[i])>nn*len){
 41             maxn[cnt]=mx;minn[cnt]=mn;
 42             en[cnt]=i-1;fro[++cnt]=i;
 43             be[i]=cnt;mx=mn=a[i];
 44         }
 45         else{
 46             be[i]=cnt;
 47             mx=max(mx,a[i]);
 48             mn=min(mn,a[i]);
 49         }
 50     }
 51     en[cnt]=n;maxn[cnt]=mx;minn[cnt]=mn;
 52     Low=100000000;High=0;
 53     //cerr<<cnt<<endl;
 54     for(int i=1;i<=cnt;i++){
 55         for(int j=fro[i];j<=en[i];j++)
 56             buc[i][a[j]-minn[i]]++;
 57         for(int j=1;j<=maxn[i]-minn[i];j++)
 58             buc[i][j]+=buc[i][j-1];
 59         Low=min(Low,minn[i]);
 60         High=max(High,maxn[i]);
 61     }
 62 }
 63 void change(int x){
 64     for(int i=0;i<=maxn[x]-minn[x];i++)buc[x][i]=0;
 65     minn[x]=100000000;maxn[x]=0;
 66     for(int i=fro[x];i<=en[x];i++){
 67         a[i]+=lazy[x];
 68         maxn[x]=max(maxn[x],a[i]);
 69         minn[x]=min(minn[x],a[i]);
 70     }
 71     lazy[x]=0;
 72     for(int i=fro[x];i<=en[x];i++)
 73         buc[x][a[i]-minn[x]]++;
 74     for(int i=1;i<=maxn[x]-minn[x];i++)
 75         buc[x][i]+=buc[x][i-1];
 76 }
 77 bool check(int l,int r,int x,int y){
 78     int ans=0;
 79     if(be[l]==be[r]){
 80         for(int i=l;i<=r;i++)if(a[i]+lazy[be[l]]<=x)ans++;
 81     }
 82     else{
 83         for(int i=l;i<=en[be[l]];i++)if(a[i]+lazy[be[l]]<=x)ans++;
 84         for(int i=fro[be[r]];i<=r;i++)if(a[i]+lazy[be[r]]<=x)ans++;
 85         for(int i=be[l]+1;i<be[r];i++){
 86             if(minn[i]+lazy[i]<=x&&maxn[i]+lazy[i]>=x)
 87                 ans+=buc[i][x-lazy[i]-minn[i]];
 88             else if(maxn[i]+lazy[i]<x)ans+=buc[i][maxn[i]-minn[i]];
 89         }
 90     }
 91     return ans>=y;
 92 }
 93 int query(int l,int r,int y){
 94     int low=Low,high=High,mid,fin=low-1;
 95     while(low<=high){
 96         mid=(low+high)>>1;
 97         if(check(l,r,mid,y))fin=mid,high=mid-1;
 98         else low=mid+1;
 99     }
100     return fin;
101 }
102 int main(){
103     scanf("%d%d%d",&n,&m,&len);
104     nn=250;mm=500;
105     for(int i=2,x,y;i<=n;i++){
106         scanf("%d%d",&x,&y);
107         add(x,i,y);
108     }
109     dfs(1,0);
110     build();
111     int o,x,y,l,r,tim=0;
112     while(m--){
113         scanf("%d%d%d",&o,&x,&y);
114         if(o==1){
115             l=L[x];r=R[x];
116             if(r-l+1<y){puts("-1");continue;}
117             printf("%d\n",query(l,r,y));
118         }
119         else{
120             l=L[x];r=R[x];
121             if(be[l]==be[r]){
122                 for(int i=l;i<=r;i++)a[i]+=y;
123                 change(be[l]);
124             }
125             else{
126                 for(int i=be[l]+1;i<be[r];i++)lazy[i]+=y;
127                 for(int i=l;i<=en[be[l]];i++)a[i]+=y;
128                 for(int i=fro[be[r]];i<=r;i++)a[i]+=y;
129                 change(be[l]);change(be[r]);
130             }
131             High+=y;
132             tim++;
133         }
134         if(tim==mm){
135             tim=0;
136             build();
137         }
138     }
139     return 0;
140 }
View Code

翻翻翻!

4.28

先看T1,感觉就很水,先写了个O(n^2)dp,然后观察推理了一波,发现了个规律,然后打上了。看T2,好像做过类似的,推了一会式子,没推出来,先写了30分暴力,然后发现50分好像也可以做,然后改了改,之后去看T3,一眼只会20分暴力,推了一下,发现a,b串字符集不相交时就是裸的矩阵乘,然后码码码,把两个部分分都写上了,懒得拍了,最后发现T2貌似可以乱dp一波,但是没时间了,肉眼查了波错就交了。100+30+60=190 rank3。T2挂分了。炸内存了,md,还没开long long,这还有分,老天有眼啊。裸暴力210,但是最高分205,落实暴力不挂分看来的确是很重要的。

T1,水题。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <map>
 7 #define inf 0x3fffffff
 8 #define int long long
 9 using namespace std;
10 int pw[105];
11 map<int,int> mm;
12 int getf(int x){
13     if(mm.count(x+1))return 0;
14     int ans=0;
15     int pos=upper_bound(pw,pw+61,x)-pw-1;
16     for(int i=pos;~i;i--){
17         if(pw[i]<=x){
18             ans++;
19             x-=pw[i];
20         }
21         if(mm.count(x+1))return ans;
22     }
23     return ans;
24 }
25 int n,m,ans,p[15],vis1,visn;
26 signed main(){
27 //freopen("2.out","w",stdout);
28     for(int i=0,now=1;i<=60;i++,now=2ll*now){
29         pw[i]=now;
30         mm[now]=1;
31     }
32     scanf("%lld%lld",&n,&m);
33     for(int i=1;i<=m;i++){
34         scanf("%lld",&p[i]);
35         if(p[i]==1)vis1=1;
36         if(p[i]==n)visn=1;
37     }
38     if(!vis1)p[++m]=1,ans++;
39     if(!visn&&n!=1)p[++m]=n,ans++;
40     sort(p+1,p+m+1);
41     for(int i=2;i<=m;i++)
42         ans+=getf(p[i]-p[i-1]-1);
43     printf("%lld\n",ans);
44     return 0;
45 }
View Code

T2,我们考虑优化暴力dp,我们发现函数值是一个下凸的函数,而且总拐点是O(n)级别的,我们考虑在拐点处维护斜率的增量,这个可以用一个可并堆来实现。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define N 200050
 5 #define LL long long
 6 using namespace std;
 7 int n,T;
 8 int e,head[N];
 9 struct edge{
10     int u,v,w,next;
11 }ed[N<<1];
12 void add(int u,int v,int w){
13     ed[e].u=u;ed[e].v=v;ed[e].w=w;
14     ed[e].next=head[u];head[u]=e++;
15 }
16 LL f[N];
17 struct diui{
18     diui *ch[2];
19     int x,val;
20     diui(int a,int b){
21         x=a;val=b;
22         ch[0]=ch[1]=NULL;
23     }
24 }*root[N];
25 diui *merge(diui *a,diui *b){
26     if(!a)return b;
27     if(!b)return a;
28     if((a->x>b->x)||(a->x==b->x&&a->val>b->val))swap(a,b);
29     a->ch[1]=merge(a->ch[1],b);
30     swap(a->ch[0],a->ch[1]);
31     return a;
32 }
33 void dfs(int x,int fa,int w){
34     for(int i=head[x];i;i=ed[i].next){
35         int v=ed[i].v;
36         if(v==fa)continue;
37         dfs(v,x,ed[i].w);
38     }
39     root[x]=merge(new diui(1,-1),new diui(w,2));
40     f[x]=w-1;
41     for(int i=head[x];i;i=ed[i].next){
42         int v=ed[i].v;
43         if(v==fa)continue;
44         root[x]=merge(root[x],root[v]);
45         f[x]+=f[v];
46     }
47     int p=1,v=0,np,nv;
48     while(1){
49         np=root[x]->x;nv=root[x]->val;
50         f[x]+=1ll*(np-p)*v;p=np;v+=nv;
51         root[x]=merge(root[x]->ch[0],root[x]->ch[1]);
52         if(v>=0){root[x]=merge(root[x],new diui(np,v));break;}
53     }
54 }
55 int main(){
56     scanf("%d",&T);
57     while(T--){
58         scanf("%d",&n);
59         e=1;memset(head,0,sizeof head);
60         for(int i=1,u,v,w;i<n;i++){
61             scanf("%d%d%d",&u,&v,&w);
62             add(u,v,w);add(v,u,w);
63         }
64         dfs(1,0,1);
65         printf("%lld\n",f[1]);
66     }
67     return 0;
68 }
View Code

T3,很好的sam矩乘的题,我们发现字符集有交时可能一个串会被统计多次,于是我们考虑用一种定义方法使得其唯一对应一种状态,于是我们设$f_{i,sa,sb}$表示长度为i的串,被分成aba...aba这种的最后一个a的子串最短的分割方法其对应在a串的sam中的结点,sb同理,然后转移也很巧妙,不过这里地方太小,写不下。而且这样的状态数最多是8n左右,然后矩乘就可以。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <queue>
  7 #define N 25
  8 #define mod 1000000007
  9 #define pr pair<int,int>
 10 #define mk make_pair
 11 #define fi first
 12 #define se second
 13 using namespace std;
 14 int n,m,len,mm[N<<1][N<<1],tot,T,ml;
 15 pr p[405];queue<pr> q;
 16 char sa[N],sb[N];
 17 void UPD(int &a,int b){a=(a+b>=mod)?(a+b-mod):(a+b);}
 18 struct sam{
 19     int last,tot,mx[N<<1],ch[N<<1][4],par[N<<1];
 20     void add(int c){
 21         int p=last,np=++tot;
 22         mx[np]=mx[p]+1;
 23         for(;!ch[p][c];p=par[p])ch[p][c]=np;
 24         if(!p)par[np]=1;
 25         else{
 26             int q=ch[p][c];
 27             if(mx[q]==mx[p]+1)par[np]=q;
 28             else{
 29                 int nq=++tot;
 30                 mx[nq]=mx[p]+1;par[nq]=par[q];
 31                 memcpy(ch[nq],ch[q],sizeof ch[nq]);
 32                 par[q]=par[np]=nq;
 33                 for(;p&&ch[p][c]==q;p=par[p])ch[p][c]=nq;
 34             }
 35         }
 36         last=np;
 37     }
 38 }sama,samb;
 39 struct mart{
 40     int a[155][155];
 41     mart(){memset(a,0,sizeof a);}
 42     mart operator *(const mart & B)const{
 43         mart C;
 44         for(int i=1;i<=ml;i++)
 45             for(int j=1;j<=ml;j++)if(a[i][j])
 46                 for(int k=1;k<=ml;k++)if(B.a[j][k])
 47                     UPD(C.a[i][k],1ll*a[i][j]*B.a[j][k]%mod);
 48         return C;
 49     }
 50 }A,B;
 51 mart qp(mart a,int b){
 52     mart c;
 53     for(int i=1;i<=ml;i++)
 54         c.a[i][i]=1;
 55     for(;b;b>>=1,a=a*a)
 56         if(b&1)c=c*a;
 57     return c;
 58 }
 59 void work(){
 60     memset(mm,0,sizeof mm);
 61     memset(A.a,0,sizeof A.a);
 62     memset(B.a,0,sizeof B.a);
 63     for(int i=0;i<4;i++)if(sama.ch[1][i]){
 64         mm[sama.ch[1][i]][0]=++tot;
 65         p[tot]=mk(sama.ch[1][i],0),q.push(p[tot]);
 66         B.a[1][tot]=1;
 67     }
 68     while(!q.empty()){
 69         pr now=q.front();q.pop();
 70         int x=now.fi,y=now.se,nx,ny;
 71         for(int i=0;i<4;i++){
 72             if(!sama.ch[1][i]&&!samb.ch[1][i])nx=0,ny=0;
 73             else if(sama.ch[1][i]&&!samb.ch[1][i]){
 74                 if(y==0)nx=sama.ch[x][i],ny=0;
 75                 else nx=sama.ch[1][i],ny=0;
 76             }
 77             else if(!sama.ch[1][i]&&samb.ch[1][i]){
 78                 if(x==0)nx=0,ny=samb.ch[y][i];
 79                 else nx=0,ny=samb.ch[1][i];
 80             }
 81             else{
 82                 if(x&&y)nx=sama.ch[1][i],ny=samb.ch[1][i];
 83                 else if(!x&&y)nx=sama.ch[1][i],ny=samb.ch[y][i];
 84                 else if(x&&!y)nx=sama.ch[x][i],ny=samb.ch[1][i];
 85                 else nx=sama.ch[1][i],ny=samb.ch[1][i];
 86             }
 87             if(!nx&&!ny)continue;
 88             if(!mm[nx][ny])mm[nx][ny]=++tot,p[tot]=mk(nx,ny),q.push(p[tot]);
 89             A.a[mm[x][y]][mm[nx][ny]]++;
 90         }
 91     }
 92     ml=tot+1;
 93     A.a[ml][ml]=1;
 94     for(int i=1;i<=tot;i++)
 95         if(p[i].se!=0)A.a[i][ml]++;
 96     B=B*qp(A,len);
 97     printf("%d\n",B.a[1][ml]);
 98 }
 99 int main(){
100     scanf("%d",&T);
101     while(T--){
102         scanf("%d%d%d",&n,&m,&len);
103         scanf("%s",sa+1);
104         sama.last=sama.tot=1;
105         memset(sama.ch,0,sizeof sama.ch);
106         for(int i=1;i<=n;i++){
107             if(sa[i]=='A')sa[i]='0';
108             if(sa[i]=='T')sa[i]='1';
109             if(sa[i]=='C')sa[i]='2';
110             if(sa[i]=='G')sa[i]='3';
111             sama.add(sa[i]-'0');
112         }
113         scanf("%s",sb+1);
114         samb.last=samb.tot=1;
115         memset(samb.ch,0,sizeof samb.ch);
116         for(int i=1;i<=m;i++){
117             if(sb[i]=='A')sb[i]='0';
118             if(sb[i]=='T')sb[i]='1';
119             if(sb[i]=='C')sb[i]='2';
120             if(sb[i]=='G')sb[i]='3';
121             samb.add(sb[i]-'0');
122         }
123         work();
124     }
125     return 0;
126 }
View Code

fighting!fighting!

4.29

先读了一遍题,发现T1如果不是分数的话就是sb题,然后感觉分数也不是很难搞,T2一脸不可做,T3貌似50分是送的?然后开始想T1,感觉正解应该是什么单调队列优化dp之类的,但是推了一会也没推出来,然后想了个骗分,就是二分答案,对最后分出来的答案在序列上跑一遍卡个边界就可以了,然后写完了,造了几组数据调了调eps,然而T2的10分暴力还是不想写,就去看T3,先写了50分暴力,然后想正解,感觉是网络流?yy了一堆建图都失败了。之后又去想T1,乱搞出来了个$O(n^{2})$dp,然而怎么也不能优化。最后把T2的10分暴力打了就完了。100+10+50=160rank2

T1,骗分是正解?就是二分答案,然后对于最后的答案我们可以暴力找分数和他匹配,也可以像我再在序列上跑一遍。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define eps 1e-7
 7 #define N 100500
 8 #define ld long double
 9 using namespace std;
10 int T,n;ld mx,mn;
11 bool vis1[N],vis2[N];
12 struct data{
13     ld l,r;
14     bool operator < (const data &a)const{return l<a.l;}
15 }d[N];
16 bool check(ld x){
17     ld now=mn;
18     for(int i=1;i<=n;i++){
19         now=max(now,d[i].l);now+=x;
20         if(now>d[i].r)return 0;
21     }
22     return 1;
23 }
24 int gcd(int a,int b){return !b?a:gcd(b,a%b);}
25 struct fra{
26     int son,mom;
27     fra(int a,int b){int g=gcd(a,b);son=a/g;mom=b/g;}
28     fra(){son=0,mom=1;}
29     bool operator < (const fra & a)const{return 1ll*son*a.mom<1ll*mom*a.son;}
30     void print(){printf("%d/%d\n",son,mom);}
31 };
32 int main(){
33     scanf("%d",&T);
34     while(T--){
35         scanf("%d",&n);
36         mn=1e9,mx=0;
37         for(int i=1;i<=n;i++){cin>>d[i].l>>d[i].r;mn=min(mn,d[i].l);mx=max(mx,d[i].r);}
38         sort(d+1,d+n+1);
39         ld l=0,r=(mx-mn)/1.0/n,mid,e=1e-12;
40         while(l+e<=r){
41             mid=(l+r)/2.0;
42             if(check(mid))l=mid;
43             else r=mid;
44         }
45         ld now=mn;
46         memset(vis1,0,sizeof vis1);
47         memset(vis2,0,sizeof vis2);
48         for(int i=1;i<=n;i++,now+=l){
49             if(now<=d[i].l+eps)vis1[i]=1,now=d[i].l;
50             if(now+l>=d[i].r-eps)vis2[i]=1;
51         }
52         fra ans=fra(1000000000,1);
53         for(int i=1,pos;i<=n;i++){
54             if(vis1[i])pos=i;
55             if(vis2[i])ans=min(ans,fra(round(d[i].r-d[pos].l),i-pos+1));
56         }
57         ans.print();
58     }
59     return 0;
60 }
View Code

T2,挺好的一道数学题。

60分dp就是定义f[i][j]表示i个点中有j棵树的方案数,然后

$$f[i][j]= \frac{1}{j} \sum_{k=1}^{i}{f[i-k][j-1] \cdot k^{k-2} \cdot C_{i}^{k}}$$

套路转移即可。

 1 #pragma GCC optimize ("O3")
 2 #include <bits/stdc++.h>
 3 #define N 1050
 4 #define mod 998244353
 5 using namespace std;
 6 int qp(int a,int b){
 7     int c=1;
 8     for(;b;b>>=1,a=1ll*a*a%mod)
 9         if(b&1)c=1ll*c*a%mod;
10     return c;
11 }
12 void UPD(int &a,int b){a=(a+b>=mod)?(a+b-mod):(a+b);}
13 int n,m,C[N][N],g[N],f[N][N],inv[N],ans,gc[N];
14 int main(){
15 //freopen("test.in","r",stdin);
16     register int i,j,k;
17     scanf("%d%d",&n,&m);
18     for(i=0;i<=n;++i){
19         C[i][0]=1;
20         for(j=1;j<=i;++j)
21             C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
22     }
23     g[1]=1;
24     for(i=2;i<=n;++i)g[i]=qp(i,i-2);
25     inv[0]=inv[1]=1;
26     for(i=2;i<=n;++i)inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod;
27     f[0][0]=1;
28     for(i=1;i<=n;++i){
29         for(k=1;k<=i;++k)gc[k]=1ll*g[k]*C[i][k]%mod;
30         for(j=1;j<=i;++j){
31             for(k=1;k<=i-j+1;++k)
32                 UPD(f[i][j],1ll*f[i-k][j-1]*gc[k]%mod);
33             f[i][j]=1ll*f[i][j]*inv[j]%mod;
34             UPD(f[i][0],mod-f[i][j]);
35         }
36         UPD(f[i][0],qp(2,1ll*i*(i-1)/2%(mod-1)));
37     }
38     for(i=1;i<=n;++i)
39         UPD(ans,1ll*f[n][i]*qp(i,m)%mod);
40     printf("%d\n",ans);
41     return 0;
42 }
View Code

正解更nb,由第二类斯特林数可得$x^{k}= \sum_{i=1}^{min(x,k)}{S(k,i) \cdot C_{x}^{i}  \cdot i!}$,然后我们考虑每i个树联通块,他的贡献就是他在所有方案中出现的次数乘上$S(k,i) \cdot i!$,然后我们就只需dp出i个点构成j棵树的方案数就可以了,这里的j<=k。注意上面60分的f中i个点中除了j棵树,还可能有不是树的联通块,而这里必须只有j棵树,转移类似

$$f[i][j]= \sum_{k=1}^{i}{f[i-k][j-1] \cdot k^{k-2} \cdot C_{i-1}^{k-1}}$$

之后把组合数拆开,然后用fft优化即可。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define N 33333
 7 #define mod 998244353
 8 using namespace std;
 9 int n,m,up,g[N],h[N],ans,len,rev[N<<1];
10 int fac[N],inv[N],S[25][25],f[25][N<<1],a[N<<1],b[N<<1];
11 int qp(int a,int b){
12     int c=1;
13     for(;b;b>>=1,a=1ll*a*a%mod)
14         if(b&1)c=1ll*c*a%mod;
15     return c;
16 }
17 int C(int n,int m){
18     if(m==0||m==n)return 1;
19     return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
20 }
21 void UPD(int &a,int b){a=(a+b>=mod)?(a+b-mod):(a+b);}
22 void ntt(int *a,int o){
23     register int i,j,k,dan,now,t;
24     for(i=0;i<len;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
25     for(k=2;k<=len;k<<=1){
26         dan=qp(3,(o==1)?((mod-1)/k):(mod-1-(mod-1)/k));
27         for(i=0;i<len;i+=k){
28             now=1;
29             for(j=0;j<(k>>1);j++,now=1ll*now*dan%mod){
30                 t=1ll*a[i+j+(k>>1)]*now%mod;
31                 a[i+j+(k>>1)]=(a[i+j]-t+mod)%mod;
32                 a[i+j]=(a[i+j]+t)%mod;
33             }
34         }
35     }
36     if(o==-1){
37         int ny=qp(len,mod-2);
38         for(i=0;i<len;i++)a[i]=1ll*a[i]*ny%mod;
39     }
40 }
41 int main(){
42     scanf("%d%d",&n,&m);
43     up=min(n,m);
44     for(int i=0;i<=m;i++){
45         S[i][0]=0;S[i][i]=1;
46         for(int j=1;j<i;j++)
47             S[i][j]=(S[i-1][j-1]+1ll*S[i-1][j]*j%mod)%mod;
48     }
49     fac[0]=1;for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
50     inv[n]=qp(fac[n],mod-2);for(int i=n;i;i--)inv[i-1]=1ll*inv[i]*i%mod;
51     g[1]=1;for(int i=2;i<=n;i++)g[i]=qp(i,i-2);
52     h[0]=1;for(int i=1;i<=n;i++)h[i]=qp(2,1ll*i*(i-1)/2%(mod-1));
53     for(len=1;len<=2*n;len<<=1);
54     for(int i=0;i<len;i++){
55         if(i&1)rev[i]=(rev[i>>1]>>1)|(len>>1);
56         else rev[i]=rev[i>>1]>>1;
57     }
58     f[0][0]=1;
59     for(int i=1;i<=up;i++){
60         for(int j=1;j<=n;j++)b[j]=1ll*g[j]*inv[j-1]%mod;
61         for(int j=0;j<=n;j++)a[j]=1ll*f[i-1][j]*inv[j]%mod;
62         for(int j=n+1;j<len;j++)b[j]=a[j]=0;b[0]=0;
63         ntt(a,1);ntt(b,1);
64         for(int j=0;j<len;j++)f[i][j]=1ll*a[j]*b[j]%mod;
65         ntt(f[i],-1);
66         for(int j=1;j<=n;j++)f[i][j]=1ll*f[i][j]*fac[j-1]%mod;
67     }
68     for(int i=1,cnt;i<=up;i++){
69         cnt=0;
70         for(int j=1;j<=n;j++)
71             UPD(cnt,1ll*f[i][j]*C(n,j)%mod*h[n-j]%mod);
72         UPD(ans,1ll*cnt*S[m][i]%mod*fac[i]%mod);
73     }
74     printf("%d\n",ans);
75     return 0;
76 }
View Code

T3,sbDP题,f[i][j][k]表示前后各放了i个数,前面i个有j个p,后面有k个p的最优解,然后我们可以发现,这样就可以避免重复,因为长度为i和n-i的条件我们可以一并考虑。然后就没了。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define P 9705276
 7 #define Q 12805858
 8 #define N 205
 9 #define pr pair<int,int>
10 #define mk make_pair
11 #define LL long long
12 using namespace std;
13 LL read(){
14     LL a=0;char ch=getchar();
15     while(ch<'0'||ch>'9')ch=getchar();
16     while((ch>='0'&&ch<='9')||(ch=='.'))
17         {if(ch!='.')a=a*10+(ch^48);ch=getchar();}
18     return a;
19 }
20 int mm[N<<1][N<<1];LL mx;
21 int Tim,ans,len,nump,numq,n,f[N][N][N],ansj,ansk;
22 pr pre[N][N][N];
23 char s[N<<1];
24 void dfs(int x,int p1,int p2){
25     if(!x)return ;
26     int prej=pre[x][p1][p2].first,prek=pre[x][p1][p2].second;
27     s[x]=(prej==p1)?'Q':'P';
28     s[len-x+1]=(prek==p2)?'Q':'P';
29     dfs(x-1,prej,prek);
30 }
31 int main(){
32     scanf("%d",&n);
33     for(int i=1,y,z;i<=n;i++){
34         LL x=read();y=z=0;
35         for(int j=0;j<=400&&x-1ll*j*P>=0;j++)
36             if((x-1ll*j*P)%Q==0){y=j;z=(x-1ll*j*P)/Q;break;}
37         if(x>mx)mx=x,nump=y,numq=z;
38         if(y||z)mm[y+z][y]++;
39     }
40     len=nump+numq;
41     memset(f,-0x3f,sizeof f);
42     f[0][0][0]=1;
43     for(int i=1,up,np;i<=(len>>1);i++){
44         up=min(i,nump);
45         for(int j=0;j<=up;j++){
46             for(int k=0;k<=up&&j+k<=nump;k++){
47                 np=mm[i][j]+mm[len-i][nump-j];
48                 if(j!=k)np+=mm[i][k]+mm[len-i][nump-k];
49                 f[i][j][k]=f[i-1][j][k];pre[i][j][k]=mk(j,k);
50                 if(j&&f[i-1][j-1][k]>f[i][j][k])f[i][j][k]=f[i-1][j-1][k],pre[i][j][k]=mk(j-1,k);
51                 if(k&&f[i-1][j][k-1]>f[i][j][k])f[i][j][k]=f[i-1][j][k-1],pre[i][j][k]=mk(j,k-1);
52                 if(j&&k&&f[i-1][j-1][k-1]>f[i][j][k])f[i][j][k]=f[i-1][j-1][k-1],pre[i][j][k]=mk(j-1,k-1);
53                 f[i][j][k]+=np;
54             }
55         }
56     }
57     if(len&1){
58         for(int j=0,k,np;j<=nump;j++){
59             k=nump-j;
60             np=mm[len+1>>1][j];if(j!=k)np+=mm[len+1>>1][k];
61             if(f[len>>1][j][k]+np>ans){ans=f[len>>1][j][k]+np;ansj=j;ansk=k;s[len+1>>1]='Q';}
62             if(j==nump)break;
63             k=nump-j-1;
64             np=mm[len+1>>1][j+1];if(j!=k)np+=mm[len+1>>1][k+1];
65             if(f[len>>1][j][k]+np>ans){ans=f[len>>1][j][k]+np;ansj=j;ansk=k;s[len+1>>1]='P';}
66         }
67     }
68     else{
69         for(int j=0;j<=nump;j++)if(f[len>>1][j][nump-j]>ans)
70             ans=f[len>>1][j][nump-j],ansj=j,ansk=nump-j;
71     }
72     dfs(len>>1,ansj,ansk);
73     printf("%s\n",s+1);
74     return 0;
75 }
View Code

晚上回家打了场cf,abc傻逼题,d题打了个贪心,感觉很稳,然后c题没判同一层,d题贪心少跑了一遍,然后就是喜闻乐见的fst了。mdzz。

5.1

劳动节快乐!

先看T1,点分?看数据范围,暴力70,这么良心,然后写了4个那么namespace,写了一个多小时,感觉点分好像很恶心,就弃了,然后看T2,根本不可做啊,然后看T3,暴力60,然后写写写,写完想了想,发现这个才是傻逼点分,直接建出点分树然后维护个动态开点线段树就可以了,然后码码码,编译过一遍过样例,然后和暴力拍,发现inf设大了,炸int了,然后改了,之后写了T2的20分暴力,没有仔细想。70+25+100=195 rank4。

T1,可以二分+点分,也可以点分+超级钢琴。就tm我bzoj上过不去!!!为什么!!!pbds都过不去,开O3都过不去!!!

  1 #pragma GCC optimize ("O3")
  2 #include <bits/stdc++.h>
  3 #include <ext/pb_ds/priority_queue.hpp>
  4 #define N 50505
  5 using namespace std;
  6 int n,m,size[N],mx[N],allsize,root,tot,vis[N],L,R;
  7 int e=1,head[N];
  8 struct edge{
  9     int v,w,next;
 10 }ed[N<<1];
 11 void add(int u,int v,int w){
 12     ed[e].v=v;ed[e].w=w;
 13     ed[e].next=head[u];head[u]=e++;
 14 }
 15 void getroot(int x,int fa){
 16     size[x]=1;mx[x]=0;
 17     for(int i=head[x];i;i=ed[i].next){
 18         int v=ed[i].v;
 19         if(v==fa||vis[v])continue;
 20         getroot(v,x);
 21         size[x]+=size[v];
 22         mx[x]=max(mx[x],size[v]);
 23     }
 24     mx[x]=max(mx[x],allsize-size[x]);
 25     if(mx[x]<mx[root])root=x;
 26 }
 27 int a[16*N],l[16*N],r[16*N],maxn[16*N][20],pp[16*N][20],lg[16*N];
 28 void dfs(int x,int fa,int w){
 29     a[++tot]=w;
 30     l[tot]=L,r[tot]=R;
 31     for(int i=head[x];i;i=ed[i].next){
 32         int v=ed[i].v;
 33         if(v==fa||vis[v])continue;
 34         dfs(v,x,w+ed[i].w);
 35     }
 36 }
 37 void work(int x){
 38     vis[x]=1;
 39     a[++tot]=0;
 40     L=tot;R=tot;
 41     for(int i=head[x];i;i=ed[i].next){
 42         int v=ed[i].v;
 43         if(vis[v])continue;
 44         dfs(v,x,ed[i].w);
 45         R=tot;
 46     }
 47     int now=allsize;
 48     for(int i=head[x];i;i=ed[i].next){
 49         int v=ed[i].v;
 50         if(vis[v])continue;
 51         if(size[v]>size[x])allsize=now-size[x];
 52         else allsize=size[v];
 53         root=0;getroot(v,0);
 54         work(root);
 55     }
 56 }
 57 void st_init(){
 58     for(int i=1,j=1,cnt=0;i<=tot;i++){
 59         if((j<<1)<i)j<<=1,cnt++;
 60         lg[i]=cnt;
 61     }
 62     for(int i=1;i<=tot;i++)maxn[i][0]=a[i],pp[i][0]=i;
 63     for(int i=1;i<=lg[tot];i++){
 64         for(int j=1;j+(1<<i)-1<=tot;j++){
 65             if(maxn[j][i-1]>maxn[j+(1<<i-1)][i-1])maxn[j][i]=maxn[j][i-1],pp[j][i]=pp[j][i-1];
 66             else maxn[j][i]=maxn[j+(1<<i-1)][i-1],pp[j][i]=pp[j+(1<<i-1)][i-1];
 67         }
 68     }
 69 }
 70 struct data{
 71     int l,r,x,pos,val;
 72     data(){}
 73     data(int a,int b,int c){
 74         l=a;r=b;x=c;
 75         int k=lg[b-a+1];
 76         if(maxn[a][k]>maxn[b-(1<<k)+1][k])pos=pp[a][k],val=::a[c]+maxn[a][k];
 77         else pos=pp[b-(1<<k)+1][k],val=::a[c]+maxn[b-(1<<k)+1][k];
 78     }
 79     bool operator < (const data &a)const{
 80         return val<a.val;
 81     }
 82 };
 83 __gnu_pbds::priority_queue<data> q;
 84 int main(){
 85     scanf("%d%d",&n,&m);
 86     for(int i=1,u,v,w;i<n;i++){
 87         scanf("%d%d%d",&u,&v,&w);
 88         add(u,v,w);add(v,u,w);
 89     }
 90     mx[0]=n+1;root=0;allsize=n;
 91     getroot(1,0);work(root);
 92     st_init();
 93     for(int i=1;i<=tot;i++)if(l[i])
 94         q.push(data(l[i],r[i],i));
 95     for(int i=1;i<=m;i++){
 96         data now=q.top();q.pop();
 97         printf("%d\n",now.val);
 98         if(now.pos>now.l)q.push(data(now.l,now.pos-1,now.x));
 99         if(now.pos<now.r)q.push(data(now.pos+1,now.r,now.x));
100     }
101     return 0;
102 }
View Code

T2,魔法森林加强版,我们先把点权附到边上,然后问题转化成了最小的bs满足将b小于他的边都加进去有一个>=k的联通块,然后我们相当于要维护一个动态最小生成树,然后加完一条边更新答案时,我们从当前的边集里找b最大的,尝试删去他,如果删去他还有大于等于k的联通块,我们就删去他,否则,他就是这个a对应的最小的b,更新答案即可。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <queue>
  7 #define inf 0x7fffffff
  8 using namespace std;
  9 struct Node{
 10     Node *ch[2],*fa;
 11     int size,sm,sxu,maxn,maxid,val,id,rev;
 12     Node();
 13     void Rev();
 14     void pushup();
 15     void pushdown();
 16 }*null=new Node(),tree[800500];
 17 Node :: Node(){
 18     ch[0]=ch[1]=fa=null;
 19     size=sxu=maxid=id=rev=0;
 20     val=maxn=-inf;
 21 }
 22 void Node :: Rev(){
 23     rev^=1;
 24     swap(ch[0],ch[1]);
 25 }
 26 void Node :: pushup(){
 27     if(ch[0]->maxn>ch[1]->maxn)maxn=ch[0]->maxn,maxid=ch[0]->maxid;
 28     else maxn=ch[1]->maxn,maxid=ch[1]->maxid;
 29     if(val>maxn)maxn=val,maxid=id;
 30     size=ch[0]->size+ch[1]->size+sm+sxu;
 31 }
 32 void Node :: pushdown(){
 33     if(rev){
 34         ch[0]->Rev();
 35         ch[1]->Rev();
 36         rev=0;
 37     }
 38 }
 39 void rotate(Node *x){
 40     Node *y=x->fa,*z=y->fa;
 41     int w=y->ch[1]==x;
 42     x->ch[w^1]->fa=y;y->ch[w]=x->ch[w^1];
 43     y->fa=x;x->ch[w^1]=y;
 44     if(z->ch[0]==y)z->ch[0]=x;
 45     if(z->ch[1]==y)z->ch[1]=x;
 46     x->fa=z;
 47     y->pushup();x->pushup();
 48 }
 49 bool isroot(Node *x){return x->fa->ch[0]!=x&&x->fa->ch[1]!=x;}
 50 bool get(Node *x){return x->fa->ch[1]==x;}
 51 void pushdown(Node *x){
 52     if(!isroot(x))pushdown(x->fa);
 53     x->pushdown();
 54 }
 55 void splay(Node *x){
 56     pushdown(x);
 57     Node *y;
 58     for(;!isroot(x);rotate(x)){
 59         y=x->fa;
 60         if(!isroot(y)){
 61             if(get(y)==get(x))rotate(y);
 62             else rotate(x);
 63         }
 64     }
 65 }
 66 void access(Node *x){
 67     Node *y=null;
 68     while(x!=null){
 69         splay(x);
 70         x->sxu+=x->ch[1]->size-y->size;
 71         x->ch[1]=y;
 72         x->pushup();
 73         y=x;x=x->fa;
 74     }
 75 }
 76 void make_root(Node *x){
 77     access(x);
 78     splay(x);
 79     x->Rev();
 80 }
 81 void link(Node *x,Node *y){
 82     make_root(x);
 83     make_root(y);
 84     x->fa=y;
 85     y->sxu+=x->size;
 86     y->pushup();
 87 }
 88 void cut(Node *x,Node *y){
 89     make_root(x);
 90     access(y);
 91     splay(y);
 92     y->ch[0]=x->fa=null;
 93     y->pushup();
 94 }
 95 bool check(Node *x,Node *y){
 96     make_root(x);
 97     access(y);
 98     splay(y);
 99     splay(x);
100     return (y->fa!=null);
101 }
102 struct data{
103     int u,v,id,a,b;
104     bool operator < (const data & x)const{
105         if(b==x.b)return id<x.id;
106         return b<x.b;
107     }
108     bool operator == (const data & x)const{
109         return id==x.id;
110     }
111 }d[500500];
112 bool cmpa(data x,data y){return x.a<y.a;}
113 struct que{
114     priority_queue<data> a,b;
115     void ins(data x){a.push(x);}
116     void del(data x){b.push(x);}
117     void mt(){while(!b.empty()&&a.top()==b.top())a.pop(),b.pop();}
118     data top(){mt();return a.top();}
119     int size(){mt();return a.size();}
120     void pop(){mt();a.pop();}
121 }q;
122 int a[300500],b[300500],n,m,K,ans,cnt;
123 int main(){
124     scanf("%d%d%d",&n,&m,&K);
125     for(int i=1;i<=n;i++)
126         scanf("%d%d",&a[i],&b[i]);
127     if(K==1){
128         ans=inf;
129         for(int i=1;i<=n;i++)ans=min(ans,a[i]+b[i]);
130         printf("%d\n",ans);
131         return 0;
132     }
133     for(int i=1;i<=m;i++){
134         scanf("%d%d",&d[i].u,&d[i].v);
135         d[i].a=max(a[d[i].u],a[d[i].v]);
136         d[i].b=max(b[d[i].u],b[d[i].v]);
137     }
138     sort(d+1,d+m+1,cmpa);
139     for(int i=1;i<=m;i++)d[i].id=i;
140     for(int i=1;i<=n;i++){
141         tree[i].ch[0]=tree[i].ch[1]=tree[i].fa=null;
142         tree[i].id=tree[i].maxid=i;
143         tree[i].size=tree[i].sm=1;
144         tree[i].rev=tree[i].sxu=0;
145         tree[i].val=tree[i].maxn=-inf;
146     }
147     for(int i=n+1;i<=n+m;i++){
148         tree[i].ch[0]=tree[i].ch[1]=tree[i].fa=null;
149         tree[i].id=tree[i].maxid=i;
150         tree[i].size=tree[i].sm=0;
151         tree[i].rev=tree[i].sxu=0;
152         tree[i].val=tree[i].maxn=d[i-n].b;
153     }
154     cnt=0;
155     ans=inf;
156     for(int i=1;i<=m;i++){
157         int u=d[i].u,v=d[i].v;
158         if(!check(&tree[u],&tree[v])){
159             make_root(&tree[u]);if(tree[u].size>=K)cnt--;
160             make_root(&tree[v]);if(tree[v].size>=K)cnt--;
161             link(&tree[u],&tree[n+i]);
162             link(&tree[v],&tree[n+i]);
163             make_root(&tree[n+i]);if(tree[n+i].size>=K)cnt++;
164             q.ins(d[i]);
165         }
166         else{
167             make_root(&tree[u]);access(&tree[v]);splay(&tree[v]);
168             if(tree[v].maxn>d[i].b){
169                 int y=tree[v].maxid;
170                 cut(&tree[y],&tree[d[y-n].u]);
171                 cut(&tree[y],&tree[d[y-n].v]);
172                 link(&tree[u],&tree[n+i]);
173                 link(&tree[v],&tree[n+i]);
174                 q.ins(d[i]);
175                 q.del(d[y-n]);
176             }
177         }
178         if(!cnt)continue;
179         while(q.size()){
180             data now=q.top();
181             make_root(&tree[n+now.id]);if(tree[n+now.id].size>=K)cnt--;
182             cut(&tree[n+now.id],&tree[now.u]);
183             cut(&tree[n+now.id],&tree[now.v]);
184             make_root(&tree[now.u]);if(tree[now.u].size>=K)cnt++;
185             make_root(&tree[now.v]);if(tree[now.v].size>=K)cnt++;
186             if(!cnt){
187                 cnt++;
188                 link(&tree[n+now.id],&tree[now.u]);
189                 link(&tree[n+now.id],&tree[now.v]);
190                 ans=min(ans,d[i].a+now.b);
191                 break;
192             }
193             q.pop();
194         }
195     }
196     if(ans<inf)printf("%d\n",ans);
197     else puts("no solution");
198     return 0;
199 }
View Code

T3,裸点分,貌似还有一系列根号做法。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #define N 100500
  7 #define inf 0x3fffffff
  8 using namespace std;
  9 int root,size[N],mx[N],allsize,n,m;
 10 int e=1,head[N];
 11 struct edge{
 12     int v,w,next;
 13 }ed[N<<1];
 14 void add(int u,int v,int w){
 15     ed[e].v=v;ed[e].w=w;
 16     ed[e].next=head[u];head[u]=e++;
 17 }
 18 int dep[N],val[N],fa[N][18];
 19 void dfs(int x,int d,int vv){
 20     dep[x]=d;
 21     val[x]=vv;
 22     for(int i=1;(1<<i)<=d;i++)
 23         fa[x][i]=fa[fa[x][i-1]][i-1];
 24     for(int i=head[x];i;i=ed[i].next){
 25         int v=ed[i].v;
 26         if(v==fa[x][0])continue;
 27         fa[v][0]=x;
 28         dfs(v,d+1,vv+ed[i].w);
 29     }
 30 }
 31 int getlca(int x,int y){
 32     if(dep[x]<dep[y])swap(x,y);
 33     for(int i=16;~i;i--)
 34         if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
 35     if(x==y)return x;
 36     for(int i=16;~i;i--)
 37         if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
 38     return fa[x][0];
 39 }
 40 int getdis(int x,int y){
 41     return val[x]+val[y]-2*val[getlca(x,y)];
 42 }
 43 int par[N],vis[N];
 44 void getroot(int x,int fa){
 45     size[x]=1;mx[x]=0;
 46     for(int i=head[x];i;i=ed[i].next){
 47         int v=ed[i].v;
 48         if(v==fa||vis[v])continue;
 49         getroot(v,x);
 50         size[x]+=size[v];
 51         mx[x]=max(mx[x],size[v]);
 52     }
 53     mx[x]=max(mx[x],allsize-size[x]);
 54     if(mx[x]<mx[root])root=x;
 55 }
 56 void work(int x){
 57     vis[x]=1;
 58     int now=allsize;
 59     for(int i=head[x];i;i=ed[i].next){
 60         int v=ed[i].v;
 61         if(vis[v])continue;
 62         if(size[v]>size[x])allsize=now-size[x];
 63         else allsize=size[v];
 64         root=0;getroot(v,0);
 65         par[root]=x;
 66         work(root);
 67     }
 68 }
 69 int sz,rot[N],lon[N<<8],ron[N<<8],mn[N<<8];
 70 void update(int &rt,int l,int r,int x,int y){
 71     if(!rt)rt=++sz,mn[rt]=inf;
 72     mn[rt]=min(mn[rt],y);
 73     if(l==r)return ;
 74     int mid=(l+r)>>1;
 75     if(x<=mid)update(lon[rt],l,mid,x,y);
 76     else update(ron[rt],mid+1,r,x,y);
 77 }
 78 int query(int rt,int l,int r,int x,int y){
 79     if(!rt)return inf;
 80     if(x<=l&&r<=y)return mn[rt];
 81     int mid=(l+r)>>1;
 82     if(y<=mid)return query(lon[rt],l,mid,x,y);
 83     if(x>mid)return query(ron[rt],mid+1,r,x,y);
 84     return min(query(lon[rt],l,mid,x,y),query(ron[rt],mid+1,r,x,y));
 85 }
 86 void build(){
 87     dfs(1,1,0);
 88     allsize=n;root=0;mx[0]=n+1;
 89     getroot(1,0);work(root);
 90     for(int i=1;i<=n;i++)
 91         for(int j=i;j;j=par[j])
 92             update(rot[j],1,n,i,getdis(i,j));
 93 }
 94 int query(int l,int r,int x){
 95     int ans=query(rot[x],1,n,l,r);
 96     for(int i=par[x];i;i=par[i])
 97         ans=min(ans,getdis(x,i)+query(rot[i],1,n,l,r));
 98     return ans;
 99 }
100 int main(){
101     scanf("%d",&n);
102     for(int i=1,u,v,w;i<n;i++){
103         scanf("%d%d%d",&u,&v,&w);
104         add(u,v,w);add(v,u,w);
105     }
106     build();
107     scanf("%d",&m);
108     int l,r,x;
109     while(m--){
110         scanf("%d%d%d",&l,&r,&x);
111         printf("%d\n",query(l,r,x));
112     }
113     return 0;
114 }
View Code

我爱拜仁。

5.3

今天三道水题,T1double炸精我又输出的lf然后就爆零了,以后要特别注意这一点。

考试看完题,发现都是原题,先写T1,然后T3,最后T2,都拍了拍,觉得挺稳的,然后T1就挂了。最后还写了一个多小时的果冻运输的暴搜,下午试了试效率极低。

T1,裸的旋转卡壳。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define N 100500
 7 #define LL long long
 8 using namespace std;
 9 int n,top,tim;
10 LL ans;
11 struct point{
12     LL x,y;
13     point(){x=y=0;}
14     point(LL a,LL b){x=a;y=b;}
15     point operator - (point a){return point(x-a.x,y-a.y);}
16     LL operator * (point a){return x*a.y-y*a.x;}
17 }p[N],q[N];
18 LL dis(point a){
19     return a.x*a.x+a.y*a.y;
20 }
21 bool cmp(point a,point b){
22     if((a-p[1])*(b-p[1])==0)return dis(a-p[1])<dis(b-p[1]);
23     return (a-p[1])*(b-p[1])>0;
24 }
25 void graham(){
26     for(int i=2;i<=n;i++)
27         if(p[i].x<p[1].x||(p[i].x==p[1].x&&p[i].y<p[i].y))
28             swap(p[1],p[i]);
29     sort(p+2,p+n+1,cmp);
30     top=1;q[top]=p[1];
31     for(int i=2;i<=n;i++){
32         while(top>1&&(p[i]-q[top])*(q[top]-q[top-1])>=0)top--;
33         q[++top]=p[i];
34     }
35 }
36 int main(){
37     scanf("%d",&n);
38     for(int i=1;i<=n;i++)
39         scanf("%lld%lld",&p[i].x,&p[i].y);
40     graham();
41     q[top+1]=q[1];
42     for(int i=1,j=2,k=1,l=2;i<=top;i++){
43         while((q[i+1]-q[i])*(q[j+1]-q[i])>(q[i+1]-q[i])*(q[j]-q[i])){
44             if(j==l){l++;if(l==top+1)l=1;}
45             j++;if(j==top+1)j=1;
46         }
47         while((q[i]-q[j])*(q[k+1]-q[j])>(q[i]-q[j])*(q[k]-q[j])){k++;if(k==top+1)k=1;}
48         while((q[j]-q[i])*(q[l+1]-q[i])>(q[j]-q[i])*(q[l]-q[i])){l++;if(l==top+1)l=1;}
49         ans=max(ans,(q[i]-q[j])*(q[k]-q[j])+(q[j]-q[i])*(q[l]-q[i]));
50     }
51     if(ans&1)printf("%lld.5\n",ans>>1);
52     else printf("%lld.0\n",ans>>1);
53     return 0;
54 }
View Code

T2,航海舰队弱化版,可以直接两种东西分开卷,也可以像我一样傻逼的按照bzoj4503一样搞一下。

 1 #pragma GCC optimize ("O3")
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cmath>
 7 #define mod 998244353
 8 #define N 526666
 9 using namespace std;
10 int n,m,q,l1,l2,tot,num,len,rev[N],ans[N];
11 int a[N],a2[N],one[N],b[N],c[N],bc[N],b2c[N],fin,fi,fj;
12 char s[505];
13 int qp(int a,int b){
14     int c=1;
15     for(;b;b>>=1,a=1ll*a*a%mod)
16         if(b&1)c=1ll*c*a%mod;
17     return c;
18 }
19 void ntt(int *a,int o){
20     register int i,j,k,dan,now,t;
21     for(i=0;i<len;++i)if(i<rev[i])swap(a[i],a[rev[i]]);
22     for(k=2;k<=len;k<<=1){
23         dan=qp(3,(o==1)?((mod-1)/k):(mod-1-(mod-1)/k));
24         for(i=0;i<len;i+=k){
25             now=1;
26             for(j=0;j<(k>>1);++j,now=1ll*now*dan%mod){
27                 t=1ll*a[i+j+(k>>1)]*now%mod;
28                 a[i+j+(k>>1)]=(a[i+j]-t+mod)%mod;
29                 a[i+j]=(a[i+j]+t)%mod;
30             }
31         }
32     }
33     if(o==-1){
34         int inv=qp(len,mod-2);
35         for(i=0;i<len;++i)a[i]=1ll*a[i]*inv%mod;
36     }
37 }
38 int main(){
39     scanf("%d%d",&n,&m);
40     for(int i=1;i<=n;i++){
41         scanf("%s",s+1);
42         for(int j=1;j<=m;j++){
43             if(s[j]=='G')a[tot++]=1;
44             else a[tot++]=2;
45         }
46     }
47     for(int i=0;i<tot;i++)a2[i]=a[i]*a[i];
48     for(int i=0;i<tot;i++)one[i]=1;
49     for(len=1;len<=(2*tot);len<<=1);
50     for(int i=0;i<len;i++){
51         if(i&1)rev[i]=(rev[i>>1]>>1)|(len>>1);
52         else rev[i]=rev[i>>1]>>1;
53     }
54     ntt(a2,1);
55     ntt(a,1);
56     ntt(one,1);
57     scanf("%d",&q);
58     while(q--){
59         scanf("%d%d",&l1,&l2);
60         num=0;
61         for(int i=1;i<=l1;i++){
62             scanf("%s",s+1);
63             for(int j=1;j<=l2;j++){
64                 if(s[j]=='G')b[num++]=1;
65                 else b[num++]=2;
66                 c[num-1]=1;
67             }
68             if(i==l1)break;
69             for(int j=l2+1;j<=m;j++){
70                 b[num++]=0;
71                 c[num-1]=0;
72             }
73         }
74         reverse(b,b+num);
75         reverse(c,c+num);
76         for(int i=0;i<num;i++){
77             b2c[i]=b[i]*b[i]*c[i];
78             bc[i]=mod-2*b[i]*c[i];
79         }
80         for(int i=num;i<len;i++)bc[i]=b2c[i]=c[i]=0;
81         ntt(c,1);ntt(bc,1);ntt(b2c,1);
82         for(int i=0;i<len;i++)
83             ans[i]=((1ll*a2[i]*c[i]%mod+1ll*a[i]*bc[i]%mod)%mod+1ll*one[i]*b2c[i]%mod)%mod;
84         ntt(ans,-1);
85         fin=l1*l2+1;
86         for(int i=1;i<=n-l1+1;i++)
87             for(int j=1;j<=m-l2+1;j++)
88                 if(ans[(i-1)*m+j+num-2]<fin){
89                     fin=ans[(i-1)*m+j+num-2];
90                     fi=i;fj=j;
91                 }
92         printf("%d %d\n",fi,fj);
93     }
94     return 0;
95 }
View Code

T3,弗洛伊德矩阵快速幂

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define inf 0x3f3f3f3f
 7 using namespace std;
 8 void getmin(int &a,int b){a>b?a=b:0;}
 9 int n,m,ans,up;
10 struct mart{
11     int a[303][303];
12     mart(){memset(a,0x3f,sizeof a);}
13 }A[11];
14 bool check(mart a){
15     for(int i=1;i<=n;i++)
16         if(a.a[i][i]<0)return 1;
17     return 0;
18 }
19 mart mul(mart a,mart b){
20     mart c;
21     for(int i=1;i<=n;i++)
22         for(int j=1;j<=n;j++)if(a.a[i][j]<inf)
23             for(int k=1;k<=n;k++)if(b.a[j][k]<inf)
24                 getmin(c.a[i][k],a.a[i][j]+b.a[j][k]);
25     return c;
26 }
27 int main(){
28     scanf("%d%d",&n,&m);
29     for(int i=1,u,v,w;i<=m;i++){
30         scanf("%d%d%d",&u,&v,&w);
31         A[0].a[u][v]=w;
32     }
33     for(int i=1;i<=n;i++)A[0].a[i][i]=0;
34     for(up=1;(1<<up)<=n;up++)
35         A[up]=mul(A[up-1],A[up-1]);up--;
36     for(int i=1;i<=n;i++)A[up+1].a[i][i]=0;
37     for(int i=up;~i;i--){
38         A[up+2]=mul(A[up+1],A[i]);
39         if(!check(A[up+2]))ans+=(1<<i),A[up+1]=A[up+2];
40         if(ans>n){puts("0");return 0;}
41     }
42     ans++;
43     if(ans>n)puts("0");
44     else printf("%d\n",ans);
45     return 0;
46 }
View Code

虚...

5.4

又tm炸了。考试先看T1,感觉十分不可做,写了30分暴力就弃疗了,看T2,更不可做,先写了60,然后找不着规律,推不出式子。然后看T3,辛辛苦苦打了好久,本来感觉40稳,没准还能多骗点分,然后因为评测机的种种傻逼,mle成15。没有然后了30+60+15=105 rank8

T1,kosaraju+bitset+分块+st表,kosalaju好简单啊!

  1 #pragma GCC optimize ("O3")
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <cmath>
  7 #include <cassert>
  8 #define N 155
  9 #define ull unsigned long long
 10 #define oo 0x7fffffffffffffff
 11 using namespace std;
 12 struct Bit{
 13     ull a[3];
 14     void clear(){a[0]=a[1]=a[2]=0;}
 15     int get(int x){return (a[x>>6]>>(x&63))&1;}
 16     void Or(int x){a[x>>6]|=1ll<<(x&63);}
 17     void Xor(int x){a[x>>6]^=1ll<<(x&63);}
 18     int Lowbit(){
 19         if(a[0])return __builtin_ctzll(a[0]);
 20         if(a[1])return __builtin_ctzll(a[1])+64;
 21         if(a[2])return __builtin_ctzll(a[2])+128;
 22         return -1;
 23     }
 24     Bit operator & (Bit B){
 25         Bit ans;
 26         ans.a[0]=a[0]&B.a[0];
 27         ans.a[1]=a[1]&B.a[1];
 28         ans.a[2]=a[2]&B.a[2];
 29         return ans;
 30     }
 31     bool operator ! (){return !a[0]&&!a[1]&&!a[2];}
 32 }vis,g1[N],g2[N],st1[600][10][N],st2[600][10][N];
 33 int n,m,mm,tot,qr,q[N],top,be[300500],en[600],lg[600],num,ans;
 34 struct data{int u,v;}d[300500];
 35 void dfs1(int x){
 36     vis.Xor(x);
 37     Bit now;
 38     while(1){
 39         now=vis&g1[x];
 40         if(!now)break;
 41         int v=now.Lowbit();
 42         dfs1(v);
 43     }
 44     q[++top]=x;
 45 }
 46 void dfs2(int x){
 47     vis.Xor(x);num++;
 48     Bit now;
 49     while(1){
 50         now=vis&g2[x];
 51         if(!now)break;
 52         int v=now.Lowbit();
 53         dfs2(v);
 54     }
 55 }
 56 int main(){
 57     scanf("%d%d%d",&n,&m,&qr);
 58     for(int i=1;i<=m;i++)scanf("%d%d",&d[i].u,&d[i].v);
 59     mm=sqrt(m);
 60     for(int i=1;i<=m;i++){
 61         be[i]=(i-1)/mm+1;
 62         en[be[i]]=i;
 63         st1[be[i]][0][d[i].u].Or(d[i].v);
 64         st2[be[i]][0][d[i].v].Or(d[i].u);
 65     }
 66     tot=be[m];
 67     for(int i=1,j=1,cnt=0;i<=tot;i++){
 68         if((j<<1)<i)j<<=1,cnt++;
 69         lg[i]=cnt;
 70     }
 71     for(int i=1;i<=lg[tot];i++){
 72         for(int j=1;j+(1<<i)-1<=tot;j++){
 73             for(int k=1;k<=n;k++){
 74                 st1[j][i][k].a[0]=st1[j][i-1][k].a[0]|st1[j+(1<<i-1)][i-1][k].a[0];
 75                 st1[j][i][k].a[1]=st1[j][i-1][k].a[1]|st1[j+(1<<i-1)][i-1][k].a[1];
 76                 st1[j][i][k].a[2]=st1[j][i-1][k].a[2]|st1[j+(1<<i-1)][i-1][k].a[2];
 77                 st2[j][i][k].a[0]=st2[j][i-1][k].a[0]|st2[j+(1<<i-1)][i-1][k].a[0];
 78                 st2[j][i][k].a[1]=st2[j][i-1][k].a[1]|st2[j+(1<<i-1)][i-1][k].a[1];
 79                 st2[j][i][k].a[2]=st2[j][i-1][k].a[2]|st2[j+(1<<i-1)][i-1][k].a[2];
 80             }
 81         }
 82     }
 83     int l,r;
 84     while(qr--){
 85         scanf("%d%d",&l,&r);
 86         for(int i=1;i<=n;i++)g1[i].clear(),g2[i].clear();
 87         if(be[l]==be[r]){
 88             for(int i=l;i<=r;i++){
 89                 g1[d[i].u].Or(d[i].v);
 90                 g2[d[i].v].Or(d[i].u);
 91             }
 92         }
 93         else{
 94             for(int i=l;i<=en[be[l]];i++){
 95                 g1[d[i].u].Or(d[i].v);
 96                 g2[d[i].v].Or(d[i].u);
 97             }
 98             for(int i=en[be[r]-1]+1;i<=r;i++){
 99                 g1[d[i].u].Or(d[i].v);
100                 g2[d[i].v].Or(d[i].u);
101             }
102             if(be[l]+1<be[r]){
103                 int k=lg[be[r]-be[l]-1];
104                 for(int i=1;i<=n;i++){
105                     g1[i].a[0]|=st1[be[l]+1][k][i].a[0]|st1[be[r]-(1<<k)][k][i].a[0];
106                     g1[i].a[1]|=st1[be[l]+1][k][i].a[1]|st1[be[r]-(1<<k)][k][i].a[1];
107                     g1[i].a[2]|=st1[be[l]+1][k][i].a[2]|st1[be[r]-(1<<k)][k][i].a[2];
108                     g2[i].a[0]|=st2[be[l]+1][k][i].a[0]|st2[be[r]-(1<<k)][k][i].a[0];
109                     g2[i].a[1]|=st2[be[l]+1][k][i].a[1]|st2[be[r]-(1<<k)][k][i].a[1];
110                     g2[i].a[2]|=st2[be[l]+1][k][i].a[2]|st2[be[r]-(1<<k)][k][i].a[2];
111                 }
112             }
113         }
114         vis.clear();
115         for(int i=1;i<=n;i++)vis.Or(i);
116         top=0;
117         for(int i=1;i<=n;i++)
118             if(vis.get(i))dfs1(i);
119         vis.clear();
120         for(int i=1;i<=n;i++)vis.Or(i);
121         ans=0;
122         for(int i=n;i;i--){
123             if(vis.get(q[i])){
124                 num=0;
125                 dfs2(q[i]);
126                 ans+=num*(num-1)/2;
127             }
128         }
129         printf("%d\n",ans);
130     }
131 }
View Code

T2,优秀的dp,f[i]表示i个点组成的有向完全强联通图的方案数。每一个有向完全图缩点后一定是一堆强联通块组成的一条链,然后1号点能走的就是他的强联通块大小以及后面的所有强联通块大小之和。

 1 #pragma GCC optimize ("O3")
 2 #include <bits/stdc++.h>
 3 #define N 2005
 4 using namespace std;
 5 int n,P,C[N][N],f[N],g[N],ans[N];
 6 int qp(int a,int b){
 7     int c=1;
 8     for(;b;b>>=1,a=1ll*a*a%P)
 9         if(b&1)c=1ll*c*a%P;
10     return c;
11 }
12 void UPD(int &a,int b){a=(a+b>=P)?(a+b-P):(a+b);}
13 int main(){
14     scanf("%d%d",&n,&P);
15     for(int i=0;i<=n;i++){
16         C[i][0]=1;
17         for(int j=1;j<=i;j++)
18             C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
19     }
20     g[0]=1;
21     for(int i=1;i<=n;i++)f[i]=g[i]=qp(2,i*(i-1)/2);
22     for(int i=1;i<=n;i++)
23         for(int j=1;j<i;j++)
24             UPD(f[i],P-1ll*C[i][j]*f[j]%P*g[i-j]%P);
25     for(int i=1;i<=n;i++)
26         for(int j=0;j<=n-i;j++)
27             UPD(ans[i+j],1ll*f[i]*C[n-1][i-1]%P*g[j]%P*C[n-i][j]%P*g[n-i-j]%P);
28     for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
29 }
View Code

T3,对于出现次数大于$\sqrt{n}$的左端点,我们O(n)扫来统计答案,其他的暴力分块查询。v.size()贼慢。

 1 #pragma GCC optimize ("O3")
 2 #include <bits/stdc++.h>
 3 #include <unordered_map>
 4 #define N 150005
 5 #define MP unordered_map<int,int>
 6 #define pb push_back
 7 #define min(a,b) ((a)<(b)?(a):(b))
 8 using namespace std;
 9 char B[1<<15],*S=B,*T=B;
10 #define getc (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
11 inline int read()
12 {
13     register int x=0;register char c=getc;
14     while(c<'0'|c>'9')c=getc;
15     while(c>='0'&c<='9')x=10*x+(c^48),c=getc;
16     return x;
17 }
18 MP pp;
19 vector <int> vv[N],v1[N],v2[N];
20 int n,m,nn,K,a[N],s[N],cnt[N],de1[N],de2[N],sum[N],vvv[N];
21 int tot,be[N],en[1050],val[N],tag[1050];
22 struct data{int l,r,w;}d[N];
23 inline void calc(int val){
24     register int i,j,u,v;
25     for(i=n,u=0,v=0;i;--i){
26         u+=de1[i];
27         cnt[i]=cnt[i+1];
28         if(s[i]==(val^K))cnt[i]++,v+=u;
29         for(j=0;j<v1[i+1].size();++j)
30             v-=(cnt[i+1]-cnt[d[v1[i+1][j]].r+1])*d[v1[i+1][j]].w;
31         if(s[i-1]==val)sum[i]+=v;
32     }
33     for(i=1,u=0,v=0;i<=n;++i){
34         u+=de2[i];
35         cnt[i]=cnt[i-1];
36         if(s[i-1]==val)cnt[i]++,v+=u;
37         for(j=0;j<v2[i-1].size();++j)
38             v-=(cnt[i-1]-cnt[d[v2[i-1][j]].l-1])*d[v2[i-1][j]].w;
39         if(s[i]==(val^K))sum[i+1]-=v;
40     }
41 }
42 int main(){
43 //freopen("test.in","r",stdin);
44 //freopen("3.out","w",stdout);
45     register int i,j,k,l,now,pos,sz;
46     n=read();m=read();K=read();
47     nn=555;
48     for(i=1;i<=n;++i){
49         a[i]=read();
50         s[i]=s[i-1]^a[i];
51         if(!pp[s[i-1]])pp[s[i-1]]=++tot,vvv[tot]=s[i-1];
52         vv[pp[s[i-1]]].pb(i);
53         be[i]=(i-1)/nn+1;
54         en[be[i]]=i;
55     }
56     for(i=1;i<=m;++i){
57         d[i].l=read();d[i].r=read();d[i].w=read();
58         de1[d[i].r]+=d[i].w;de1[d[i].l-1]-=d[i].w;
59         de2[d[i].l]+=d[i].w;de2[d[i].r+1]-=d[i].w;
60         v1[d[i].l].pb(i);v2[d[i].r].pb(i);
61     }
62     for(i=1;i<=tot;++i)
63         if(vv[i].size()>=nn)calc(vvv[i]);
64     for(i=n;i;--i){
65         sz=v2[i].size();
66         for(j=0;j<sz;++j){
67             l=d[v2[i][j]].l;
68             pos=min(en[be[l]],i);
69             if(pos-l+1>l-en[be[l]-1]){
70                 for(k=en[be[l]-1]+1;k<l;++k)val[k]-=d[v2[i][j]].w;
71                 tag[be[l]]+=d[v2[i][j]].w;
72             }
73             else{
74                 for(k=l;k<=pos;++k)val[k]+=d[v2[i][j]].w;
75             }
76             for(k=be[l]+1;k<=be[i];++k)tag[k]+=d[v2[i][j]].w;
77         }
78         sz=vv[pp[s[i]^K]].size();
79         if(sz<nn){
80             now=0;
81             for(j=0;j<sz;++j){
82                 pos=vv[pp[s[i]^K]][j];
83                 if(pos>i)break;
84                 sum[pos]+=val[pos]+tag[be[pos]];
85                 now+=val[pos]+tag[be[pos]];
86             }
87             sum[i+1]-=now;
88         }
89     }
90     for(i=1,now=0;i<=n;++i){
91         now=now+sum[i];
92         printf("%d ",now&(1073741823));
93     }puts("");
94     return 0;
95 }
View Code

 5.5

考的是jsoi round2 day2 被暴虐。

先看T1,计算几何,凸包求交,半平面交有70?然后看T2,50送的?T3,主席树裸题?然后先去写T2,写了20暴力,发现方案数不是很好搞,然后找了找规律,发现可以暴力枚举第一个块的长宽,然后组合数什么的乱搞一下,推完打完快2h了,然后赶紧去看T3,只会log2?不管了,先写吧,写完发现二分的log可以直接在线段树上跑,然后就去掉了,改了改拍上了,极限数据大概要跑3s左右,虚。又卡了卡常,没啥用,然后就剩30min左右了,赶紧去看T1,写了一半感觉自己写不出来半平面交了,刚打算弃辽,然后教练说延长15min,瞬间不虚,推了推式子,倒是一遍过样例了,之后也没啥时间了,就没测大点。40+50+100=190 rank1,T1被卡log了。貌似在js刚进前十?菜。

T1,闵科夫斯基和,没听说过。

 1 #pragma GCC optimize ("O3")
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cmath>
 7 #define N 100050
 8 #define LL long long
 9 using namespace std;
10 int n,m,qr,top,tot;
11 struct point{
12     int x,y;
13     point(){x=y=0;}
14     point(int a,int b){x=a;y=b;}
15     point operator + (point a){return point(x+a.x,y+a.y);}
16     point operator - (point a){return point(x-a.x,y-a.y);}
17     LL operator * (point a){return 1ll*x*a.y-1ll*y*a.x;}
18 }p1[N],p2[N],p[N],q[N],B;
19 LL getdis(point a){
20     return sqrt(1ll*a.x*a.x+1ll*a.y*a.y);
21 }
22 bool cmpp(point a,point b){
23     LL now=(a-B)*(b-B);
24     if(now==0)return getdis(a-B)<getdis(b-B);
25     return now>0;
26 }
27 void graham(point *a,int &n){
28     for(int i=2;i<=n;i++)
29         if(a[i].x<a[1].x||(a[i].x==a[1].x&&a[i].y<a[1].y))
30             swap(a[1],a[i]);
31     B=a[1];
32     sort(a+2,a+n+1,cmpp);
33     top=1;q[1]=a[1];
34     for(int i=2;i<=n;i++){
35         while(top>1&&(a[i]-q[top])*(q[top]-q[top-1])>=0)top--;
36         q[++top]=a[i];
37     }
38     for(int i=1;i<=top;i++)a[i]=q[i];
39     n=top;
40 }
41 
42 struct line{
43     point v;
44     double k;
45     line(){}
46     line(point a,point b){
47         v=b-a;
48         k=atan2(v.y,v.x);
49     }
50 }l[N];
51 #define _P -(acos(-1.0)/2.0)
52 bool cmpl(line a,line b){
53     if(a.k==_P)return 0;
54     if(b.k==_P)return 1;
55     if(a.k>_P&&b.k>_P)return a.k<b.k;
56     if(a.k<_P&&b.k<_P)return a.k<b.k;
57     return a.k>_P;
58 }
59 
60 int main(){
61     scanf("%d%d%d",&n,&m,&qr);
62     for(int i=1;i<=n;i++)scanf("%d%d",&p1[i].x,&p1[i].y);
63     for(int i=1;i<=m;i++){
64         scanf("%d%d",&p2[i].x,&p2[i].y);
65         p2[i].x*=-1;p2[i].y*=-1;
66     }
67     graham(p1,n);
68     graham(p2,m);
69     for(int i=1;i<n;i++)l[i]=line(p1[i],p1[i+1]);
70     l[n]=line(p1[n],p1[1]);
71     for(int i=1;i<m;i++)l[n+i]=line(p2[i],p2[i+1]);
72     l[n+m]=line(p2[m],p2[1]);
73     sort(l+1,l+n+m+1,cmpl);
74     p[1]=p1[1]+p2[1];
75     for(int i=1;i<n+m;i++)p[i+1]=p[i]+l[i].v;
76     tot=n+m;
77     graham(p,tot);
78     point now;
79     while(qr--){
80          int l=2,r=tot,mid,fin=1;
81          scanf("%d%d",&now.x,&now.y);
82          while(l<=r){
83              mid=(l+r)>>1;
84              if((p[mid]-p[1])*(now-p[1])>=0)fin=mid,l=mid+1;
85              else r=mid-1;
86          }
87          if(fin==tot||fin==1){puts("0");continue;}
88          if((now-p[fin])*(p[fin+1]-p[fin])>0)puts("0");
89          else puts("1");
90     }
91 }
View Code

T2倒是一道不错的题目,我们发现每走一步,相当于限制了lcm(n,m)步,因为如果(1,1)走到了(1,2),那么(n,2)就只能走到(n,3)。然后我们现在就只需走gcd步就能得到对应的遍历全图的方案,于是我们设第一个块竖着走了x步,横着走了y步,我们发现一个方案是合法的,当且仅当gcd(x,n)=1&&gcd(y,m)=1,这个是因为要遍历n和m的全部剩余系。然后我们就可以枚举x,然后对于每个块dp在这个块里撞到障碍的方案数,因为每个块走的是一样的,所以还要保证在之前的所有块中这种走法是合理的。时间复杂度$O(nm\frac{gcd(n,m)}{4})$,常数极小。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define mod 998244353
 7 #define N 55
 8 using namespace std;
 9 int T,n,m,l,g,ans,C[N<<1][N<<1],blo[N][N],f1[N][N],f2[N][N],vis[N][N];
10 int gcd(int a,int b){return !b?a:gcd(b,a%b);}
11 void UPD(int &a,int b){a=(a+b>=mod)?(a+b-mod):(a+b);}
12 char s[N];
13 int main(){
14     scanf("%d",&T);
15     for(int i=0;i<=100;i++){
16         C[i][0]=1;
17         for(int j=1;j<=i;j++)
18             C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
19     }
20     while(T--){
21         scanf("%d%d",&n,&m);
22         for(int i=0;i<n;i++){
23             scanf("%s",s);
24             for(int j=0;j<m;j++)
25                 blo[i][j]=s[j]-'0';
26         }
27         g=gcd(n,m);
28         l=n*m/g;
29         ans=0;
30         for(int x=1,y,nx,ny,rest;x<=g;x++){
31             if(gcd(x,n)!=1||gcd(g-x,m)!=1)continue;
32             y=g-x;
33             nx=ny=0;
34             memset(vis,0,sizeof vis);
35             memset(f1,0,sizeof f1);
36             memset(f2,0,sizeof f2);
37             for(int i=0;i<=x;i++){
38                 f1[i][0]=1;
39                 for(int j=1;j<=y;j++)f1[i][j]=(f1[i][j-1]+f1[i-1][j])%mod;
40             }
41             for(int i=x;~i;i--){
42                 f2[i][y]=1;
43                 for(int j=y-1;~j;j--)f2[i][j]=(f2[i][j+1]+f2[i+1][j])%mod;
44             }
45             rest=C[x+y][x];
46             for(int t=1;t<=l;t++){
47                 for(int i=0;i<=x;i++){
48                     for(int j=0;j<=y;j++){
49                         if(j==0){
50                             if(i==0)f1[i][j]=1;
51                             else f1[i][j]=f1[i-1][j];
52                         }
53                         else{
54                             if(i==0)f1[i][j]=f1[i][j-1];
55                             else f1[i][j]=(f1[i-1][j]+f1[i][j-1])%mod;
56                         }
57                         if(vis[i][j])f1[i][j]=0;
58                         if(blo[(nx+i)%n][(ny+j)%m]){
59                             UPD(ans,1ll*f1[i][j]*f2[i][j]%mod*((t-1)*g+i+j)%mod);
60                             UPD(rest,mod-1ll*f1[i][j]*f2[i][j]%mod);
61                             vis[i][j]=1;f1[i][j]=0;
62                         }
63                     }
64                 }
65                 if(!rest)break;
66                 for(int i=x;~i;i--){
67                     for(int j=y;~j;j--){
68                         if(j==y){
69                             if(i==x)f2[i][j]=1;
70                             else f2[i][j]=f2[i+1][j];
71                         }
72                         else{
73                             if(i==x)f2[i][j]=f2[i][j+1];
74                             else f2[i][j]=(f2[i+1][j]+f2[i][j+1])%mod;
75                         }
76                         if(vis[i][j])f2[i][j]=0;
77                     }
78                 }
79                 nx=(nx+x)%n;
80                 ny=(ny+y)%m;
81             }
82         }
83         printf("%d\n",ans);
84     }
85     return 0;
86 }
View Code

T3,傻逼主席树。

 1 #pragma GCC optimize ("O3")
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cmath>
 7 #define N 500500
 8 #define maxn 2000000
 9 #define LL long long
10 using namespace std;
11 char B[1<<15],*S=B,*T=B;
12 #define getc (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
13 inline int read()
14 {
15     register int x=0;register char c=getc;
16     while(c<'0'|c>'9')c=getc;
17     while(c>='0'&c<='9')x=10*x+(c^48),c=getc;
18     return x;
19 }
20 int n,m;
21 int sz,root[N],lon[N<<5],ron[N<<5],s1[N<<5];
22 LL s2[N<<5];
23 void insert(int &rt,int o,int l,int r,int x){
24     rt=++sz;
25     lon[rt]=lon[o],ron[rt]=ron[o];
26     s1[rt]=s1[o]+1;s2[rt]=s2[o]+x;
27     if(l==r)return ;
28     int mid=(l+r)>>1;
29     if(x<=mid)insert(lon[rt],lon[o],l,mid,x);
30     else insert(ron[rt],ron[o],mid+1,r,x);
31 }
32 void query(int rt,int o,int l,int r,int x,int y,int &num,LL &sum){
33     if(x<=l&&r<=y){num+=s1[rt]-s1[o];sum+=s2[rt]-s2[o];return;}
34     int mid=(l+r)>>1;
35     if(x<=mid)query(lon[rt],lon[o],l,mid,x,y,num,sum);
36     if(y>mid)query(ron[rt],ron[o],mid+1,r,x,y,num,sum);
37 }
38 int getpos(int rt,int o,int l,int r,int x,int &sum){
39     if(l==r)return l;
40     int mid=(l+r)>>1;
41     if(mid<x||(sum+s1[lon[rt]]-s1[lon[o]]>=mid-x+1)){
42         sum+=s1[lon[rt]]-s1[lon[o]];
43         return getpos(ron[rt],ron[o],mid+1,r,x,sum);
44     }
45     else return getpos(lon[rt],lon[o],l,mid,x,sum);
46 }
47 int main(){
48     n=read();m=read();
49     for(int i=1,x;i<=n;i++){
50         x=read();
51         insert(root[i],root[i-1],1,maxn,x);
52     }
53     int l,r,k,num1,num2,pos,cnt;
54     LL ans,sum1,sum2;
55     while(m--){
56         l=read();r=read();k=read();
57         ans=0;
58         num1=sum1=num2=sum2=0;
59         if(k>1){
60             query(root[r],root[l-1],1,maxn,1,k-1,num1,sum1);
61             ans+=1ll*num1*k-sum1+1ll*(num1-1)*num1/2;
62         }
63         if(!num1)pos=k-1;
64         else{
65             cnt=0;
66             pos=getpos(root[r],root[l-1],1,maxn,k,cnt)-1;
67         }
68         if(k<=pos){
69             query(root[r],root[l-1],1,maxn,k,pos,num2,sum2);
70             ans+=1ll*pos*num2-sum2-1ll*(num2-1)*num2/2;
71             num2=sum2=0;
72         }
73         query(root[r],root[l-1],1,maxn,pos+1,maxn,num2,sum2);
74         ans+=sum2-1ll*num2*(pos+1)-1ll*(num2-1)*num2/2;
75         printf("%lld\n",ans);
76     }
77     return 0;
78 }
View Code

加油加油,gaygay!

CTSC Day1

考试鸽了半小时。。先看T1,我不会??!血量什么的可以O(m)维护,那么查询呢?对于每个人单独算贡献,于是我们要算除去他之外的人有i个人存活的概率,貌似O(n3)可以过70分,然后写写写,写完过了样例,没想着优化,赶紧去看T2,又是猫?又是树上lca乱搞?wc那题没改啊,gg了!先写了暴力分,然后脑子里突然想错题意了,yy了好久还是失败了。赶紧去看T3,感觉暴搜并没有那么多分,但还是写了。GG,70+40+25=135,T2这个照着错误的题意想的事好像干了好多遍了,以后一定要注意。

5.8自己考了一场,全程不在状态,就写了点暴力和骗分。貌似三道题都很吊??

CTSC Day2

这次倒是准时进场了。先看T1,裸的log2二分主席树,写完没毛病,过了大样例,还是不放心,写了个暴力对拍。然后看T2,一点不会。看T3,题答,然后开始搞,先搜过了前两个点,然后第三个点加了好多减枝才搜过去,后来又搞出来了第四个点和第七个点,然后快没时间了,吧T2的0分暴力写了好久,还加了一堆减枝,希望有分,最后写了T3第五个点的dp发现只有3分,我也很无奈啊。最后100+0+58=158,貌似第六个点可以直接贪心。GG。

5.10又考了一场,全场写T1,卡T1,写暴力,没了。

APIO

先把题目都读了一遍,发现果然都不可做的样子,然后先开T3,打算先写树的部分分,然后写了一个多小时,交了若干遍才发现图有可能不联通。然后赶紧改了拿到了树的分,发现链的gg了?好吧,可能有环,又写了,然后去写T2,本来以为有不少分都是可以写的,后来发现是我想多了。之后又写了T1的暴力。最后又是照着错误的题意去想T1,好不容易写完了,发现题意又想错了,最后发现T3的仙人掌部分分很好拿的样子,然而最后也没写完。

12+19+36=67 大概是这个分数吧。

打了两个ag回来,还是很不甘心的,尤其两场考试中都有很长的时间在想错误的题意,我也不知道我是怎么了,大赛经验啊。。。

稳住,我们能赢。

5.16

今天考试总体来说状态不够好。今天身体不是很舒服,考试的时候头也疼,还特别困。 

说考试吧,看到三道题,并没有发现T2是原题,于是先写了个点双,后来发现不对,改成强联通分量,然后写网络流加反向inf边的时候才想起来这道题原来做过,于是又写了个不缩点的,两边拍上了,感觉不错,这时候大概90min了。然后看T1,觉得是一个很恶心的数据结构,又去看T3,数学或是dp的一个计数题,但是感觉怎么写都需要当前填数的状态,于是写了暴力弃掉了,这时候大概还有不到2h。之后去把T1的暴力写了,之后yy了一个随机数据跑的很快的骗分,写上了,两边也拍上了,这时候差不多就结束了。最后40+70+50=160,T1骗分就多了10分,T2还是不清楚题的本质,只记得要加反向边,却没有深入思考原因,于是gg,T3暴力多跑了10分,貌似都是50。

关于T3的一点思考:就像题解里说的:“对排列计数,不可能从左到右填数。”因为一旦这样,当前所用数的状态就是不能避免需要记录的了,所以我们需要宏观地来考虑整个过程,比如从小到大来填,这时就需要记录一些必要的信息:分成了几段,两端点的状态。但是至少需要的混乱度我觉得还是比较巧妙或者说是我想不到的,但是这个的确也是必要的,还是做题少吧,多做题,多思考。。

T1:对于序列维护一个线段树,支持区间减,求最小值,然后对于左右端点分别维护一个并查集,每个并查集维护左(右)端点相同的区间,每次删掉一个区间就在并查集里切掉一些,然后将他们合并起来,因为每切一个就会合并起来,所以这个的复杂度是O(n)的,线段树是log的没有问题。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define N 300500
 7 using namespace std;
 8 int n,m,fa1[N],fa2[N],lp[N],rp[N],ll1[N],rr1[N],ll2[N],rr2[N];
 9 int minn[N<<2],lazy[N<<2],pos[N<<2];
10 int find1(int x){return x==fa1[x]?x:fa1[x]=find1(fa1[x]);}
11 int find2(int x){return x==fa2[x]?x:fa2[x]=find2(fa2[x]);}
12 void change(int rt,int x){
13     lazy[rt]+=x;
14     minn[rt]-=x;
15 }
16 void pushup(int rt){
17     if(minn[rt<<1]<=minn[rt<<1|1])minn[rt]=minn[rt<<1],pos[rt]=pos[rt<<1];
18     else minn[rt]=minn[rt<<1|1],pos[rt]=pos[rt<<1|1];
19 }
20 void pushdown(int rt){
21     if(lazy[rt]){
22         change(rt<<1,lazy[rt]);
23         change(rt<<1|1,lazy[rt]);
24         lazy[rt]=0;
25     }
26 }
27 void build(int rt,int l,int r){
28     if(l==r){
29         minn[rt]=rp[l]-lp[l];
30         pos[rt]=l;
31         return ;
32     }
33     int mid=(l+r)>>1;
34     build(rt<<1,l,mid);
35     build(rt<<1|1,mid+1,r);
36     pushup(rt);
37 }
38 void update(int rt,int l,int r,int x,int y,int z){
39     if(x<=l&&r<=y){
40         change(rt,z);
41         return ;
42     }
43     pushdown(rt);
44     int mid=(l+r)>>1;
45     if(x<=mid)update(rt<<1,l,mid,x,y,z);
46     if(y>mid)update(rt<<1|1,mid+1,r,x,y,z);
47     pushup(rt);
48 }
49 void del(int rt,int l,int r,int x){
50     if(l==r){
51         minn[rt]=0x7fffffff;
52         pos[rt]=0;
53         return ;
54     }
55     pushdown(rt);
56     int mid=(l+r)>>1;
57     if(x<=mid)del(rt<<1,l,mid,x);
58     else del(rt<<1|1,mid+1,r,x);
59     pushup(rt);
60 }
61 int main(){
62     scanf("%d%d",&m,&n);
63     for(int i=1;i<=n;i++){
64         scanf("%d%d",&lp[i],&rp[i]);
65         fa1[i]=fa2[i]=i;
66         ll1[i]=rr1[i]=i;
67         ll2[i]=rr2[i]=i;
68     }
69     build(1,1,n);
70     for(int i=1;i<=n;i++){
71         int p=pos[1];
72         printf("%d\n",p);
73         int l=lp[find1(p)],r=rp[find2(p)];
74         for(int j=p+1;j<=n&&lp[find1(j)]<r;j=rr1[find1(j)]+1){
75             update(1,1,n,ll1[find1(j)],rr1[find1(j)],r-lp[find1(j)]);
76             int nr=rr1[find1(j)];
77             fa1[find1(j)]=find1(p+1);
78             ll1[find1(j)]=p+1;rr1[find1(j)]=nr;
79             lp[find1(j)]=r;
80         }
81         for(int j=p-1;j&&rp[find2(j)]>l;j=ll2[find2(j)]-1){
82             update(1,1,n,ll2[find2(j)],rr2[find2(j)],rp[find2(j)]-l);
83             int nl=ll2[find2(j)];
84             fa2[find2(j)]=find2(p-1);
85             rr2[find2(j)]=p-1;ll2[find2(j)]=nl;
86             rp[find2(j)]=l;
87         }
88         del(1,1,n,p);
89     }
90     return 0;
91 }
View Code

T2,网络流,这里要注意加反向边的时候一定要保证这条边能被到达。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <vector>
 7 #include <queue>
 8 #define inf 2333333333333ll
 9 #define N 102
10 #define LL long long
11 using namespace std;
12 int q[N],he,ta,n,m;
13 int e=2,head[N];
14 struct edge{
15     int u,v,next;
16     LL f;
17 }ed[5005];
18 void add(int u,int v,LL f){
19     ed[e].u=u;ed[e].v=v;ed[e].f=f;
20     ed[e].next=head[u];head[u]=e++;
21     ed[e].u=v;ed[e].v=u;ed[e].f=0;
22     ed[e].next=head[v];head[v]=e++;
23 }
24 int dep[N],S,T;
25 bool bfs(){
26     memset(dep,0,sizeof dep);
27     dep[S]=1;he=ta=1;q[1]=S;
28     while(he<=ta){
29         int x=q[he++];
30         for(int i=head[x];i;i=ed[i].next){
31             if(ed[i].f&&!dep[ed[i].v]){
32                 dep[ed[i].v]=dep[x]+1;
33                 if(ed[i].v==T)return 1;
34                 q[++ta]=ed[i].v;
35             }
36         }
37     }
38     return 0;
39 }
40 LL dfs(int x,LL f){
41     if(x==T||!f)return f;
42     LL ans=0;
43     for(int i=head[x];i;i=ed[i].next){
44         if(ed[i].f&&dep[ed[i].v]==dep[x]+1){
45             LL nxt=dfs(ed[i].v,min(f,ed[i].f));
46             ans+=nxt,f-=nxt,ed[i].f-=nxt,ed[i^1].f+=nxt;
47             if(!f)break;
48         }
49     }
50     if(!ans)dep[x]=-2;
51     return ans;
52 }
53 LL dinic(){
54     LL ans=0;
55     while(bfs())ans+=dfs(S,inf);
56     if(!ans||ans>=inf)return -1;
57     return ans;
58 }
59 bool vis[N];
60 void dfs(int x){
61     vis[x]=1;
62     for(int i=head[x];i;i=ed[i].next)if(!(i&1)){
63         ed[i^1].f=inf;
64         if(!vis[ed[i].v])dfs(ed[i].v);
65     }
66 }
67 int main(){
68     scanf("%d%d",&n,&m);
69     LL w;
70     for(int i=1,u,v;i<=m;i++){
71         scanf("%d%d%lld",&u,&v,&w);
72         add(++u,++v,w);
73     }
74     S=1;T=n;
75     dfs(S);
76     printf("%lld\n",dinic());
77     return 0;
78 }
View Code

T3,很优秀的一个dp,我们考虑从小到大填,需要记录的有当前的段数,两端点的状态以及把它填平需要的混乱度。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define mod 1000000007
 7 using namespace std;
 8 int n,m,ans,a[105],f[2][105][1005][3];
 9 void UPD(int &a,int b){a=(a+b>=mod)?(a+b-mod):(a+b);}
10 int main(){
11     scanf("%d%d",&n,&m);
12     if(n==1){
13         puts("1");
14         return 0;
15     }
16     for(int i=1;i<=n;i++)
17         scanf("%d",&a[i]);
18     sort(a+1,a+n+1);
19     f[1][1][0][0]=1;
20     f[1][1][0][1]=2;
21     int ii=1;
22     for(int i=2;i<=n;i++){
23         ii^=1;
24         memset(f[ii],0,sizeof f[ii]);
25         for(int j=1;j<i;j++){
26             for(int k=0;k<=m;k++){
27                 for(int l=0;l<=2;l++){
28                     int w=k+(a[i]-a[i-1])*(2*j-l),ff=f[ii^1][j][k][l];
29                     if(!ff)continue;
30                     if(w>m)continue;
31                     if(l<2){
32                         UPD(f[ii][j][w][l+1],1ll*ff*(2-l)%mod);
33                         UPD(f[ii][j+1][w][l+1],1ll*ff*(2-l)%mod);
34                     }
35                     UPD(f[ii][j-1][w][l],1ll*ff*(j-1)%mod);
36                     UPD(f[ii][j+1][w][l],1ll*ff*(j-1+(2-l))%mod);
37                     UPD(f[ii][j][w][l],1ll*ff*(2*j-l)%mod);
38                 }
39             }
40         }
41     }
42     for(int i=0;i<=m;i++)UPD(ans,f[ii][1][i][2]);
43     printf("%d\n",ans);
44     return 0;
45 }
View Code

加油!!!

5.17

pku的acm模拟赛

先看A,字符串匹配的题,要求是反回文,有点意思,好像可做。然后看B,一看就是数据结构码农题,弃弃弃。C是个数学题?然后发现D是个签到题,赶紧水了过去,E是个期望?F是个树形dp?G是个dp或网络流?然后在我决定做哪个题的时候,发现lc C题A了??赶紧去看,写了个复杂度不对的暴力,交,A了???然后发现一堆人都水过去了,0ms,0kb?我猜没有测试点,然后加上测试点之后,hzoi全员fst,那不行啊,想,死磕,发现这个和缩进优化一样直接处理个前缀和就行了,然后写,wa?没加case,加上A了,然后去想G的dp,写了写发现不可写,然后又去想F,状态定义也不太清楚,又推了推E的式子,挺像fft的,但是模数不对,复杂度也不对,就没接着搞,最后又去想了想A,也没想出来。

两道题,不够啊。。

A,对于每个串,我们首先把原串和反着的反串插进AC自动机,如001就插入001和011,然后还要再处理一个状态就是中间如果出现这个串原串也能匹配上,001的话我们还要插入00,这样直接在AC自动机上dp就可以了,最后一步要特殊转移。

 1 #pragma GCC optimize ("O3")
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cmath>
 7 #define N 333
 8 #define mod 998244353
 9 using namespace std;
10 char s[22];
11 int T,n,m,ans,root,sz,q[N],he,ta;
12 int ch[N][2],fail[N],st1[N],st2[N],f[105][N][1<<6|1];
13 void UPD(int &a,int b){a=(a+b>=mod)?(a+b-mod):(a+b);}
14 void insert(char *s,int id){
15     int len=strlen(s);
16     int now;
17     for(int i=0;len-i>=i;i++){
18         bool flag=1;
19         for(int j=i-1;~j;j--)
20             if(s[j]==s[(i)+(i-1-j)]){flag=0;break;}
21         if(flag){
22             now=root;
23             for(int j=len-1;j>=i;j--){
24                 int t=(s[j]-'0')^1;
25                 if(!ch[now][t])ch[now][t]=++sz;
26                 now=ch[now][t];
27             }
28             st2[now]|=(1<<id-1);
29             if(!i)st1[now]|=(1<<id-1);
30         }
31     }
32     for(int i=len-1;len-1-i<i+1;i--){
33         bool flag=1;
34         for(int j=i+1;j<len;j++)
35             if(s[j]==s[(i)-(j-i-1)]){flag=0;break;}
36         if(flag){
37             now=root;
38             for(int j=0;j<=i;j++){
39                 int t=s[j]-'0';
40                 if(!ch[now][t])ch[now][t]=++sz;
41                 now=ch[now][t];
42             }
43             st2[now]|=(1<<id-1);
44             if(i==len-1)st1[now]|=(1<<id-1);
45         }
46     }
47 }
48 int main(){
49     scanf("%d",&T);
50     while(T--){
51         scanf("%d%d",&n,&m);
52         root=sz=1;
53         memset(ch,0,sizeof ch);
54         memset(st1,0,sizeof st1);
55         memset(st2,0,sizeof st2);
56         for(int i=1;i<=n;i++){
57             scanf("%s",s);
58             insert(s,i);
59         }
60         ch[0][0]=ch[0][1]=1;
61         he=ta=1;q[1]=1;fail[1]=0;
62         while(he<=ta){
63             int x=q[he++];
64             for(int i=0;i<2;i++){
65                 if(ch[x][i]){
66                     fail[ch[x][i]]=ch[fail[x]][i];
67                     q[++ta]=ch[x][i];
68                 }
69                 else ch[x][i]=ch[fail[x]][i];
70             }
71             st1[x]|=st1[fail[x]];
72             st2[x]|=st2[fail[x]];
73         }
74         memset(f,0,sizeof f);
75         f[0][1][0]=1;
76         for(int i=1;i<m;i++){
77             for(int j=1;j<=sz;j++){
78                 for(int k=0;k<(1<<n);k++)if(f[i-1][j][k]){
79                     UPD(f[i][ch[j][0]][k|st1[ch[j][0]]],f[i-1][j][k]);
80                     UPD(f[i][ch[j][1]][k|st1[ch[j][1]]],f[i-1][j][k]);
81                 }
82             }
83         }
84         for(int i=1;i<=sz;i++){
85             for(int j=0;j<(1<<n);j++)if(f[m-1][i][j]){
86                 UPD(f[m][ch[i][0]][j|st1[ch[i][0]]|st2[ch[i][0]]],f[m-1][i][j]);
87                 UPD(f[m][ch[i][1]][j|st1[ch[i][1]]|st2[ch[i][1]]],f[m-1][i][j]);
88             }
89         }
90         ans=0;
91         for(int i=1;i<=sz;i++)if(f[m][i][(1<<n)-1])
92             UPD(ans,f[m][i][(1<<n)-1]);
93         printf("%d\n",ans);
94     }
95     return 0;
96 }
View Code

B,因为一个可能重复拼在一起,所以我们要可持久化平衡树,但是我们还是没法快速把一个区间复制多次,于是我们考虑快速幂(倍增),注意要回收空间。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #define N 200500
  7 #define LL long long 
  8 using namespace std;
  9 int n,m,a[N],tot,cnt;
 10 #define tp pair<Treap*,Treap*>
 11 struct Treap{
 12     Treap *ch[2];
 13     int size,val;
 14     LL sum;
 15     void pushup(){
 16         sum=ch[0]->sum+ch[1]->sum+val;
 17         size=ch[0]->size+ch[1]->size+1;
 18     }
 19 }*null,*org,*root,mem[N<<5];
 20 Treap * newTreap(int v){
 21     Treap *rt=mem+(++tot);
 22     rt->ch[0]=rt->ch[1]=null;
 23     rt->size=1;rt->val=rt->sum=v;
 24 }
 25 Treap * copy(Treap *x){
 26     Treap *rt=mem+(++tot);
 27     *rt=*x;return rt;
 28 }
 29 tp split(Treap *o,int k){
 30     if(o==null)return tp(null,null);
 31     Treap *rt=copy(o);
 32     tp x;
 33     if(o->ch[0]->size>=k){
 34         x=split(rt->ch[0],k);
 35         rt->ch[0]=x.second;
 36         rt->pushup();
 37         x.second=rt;
 38     }
 39     else{
 40         x=split(rt->ch[1],k-o->ch[0]->size-1);
 41         rt->ch[1]=x.first;
 42         rt->pushup();
 43         x.first=rt;
 44     }
 45     return x;
 46 }
 47 Treap * merge(Treap *a,Treap *b){
 48     if(a==null)return b;
 49     if(b==null)return a;
 50     if(rand()%(a->size+b->size)<a->size){
 51         Treap *rt=copy(a);
 52         rt->ch[1]=merge(rt->ch[1],b);
 53         rt->pushup();
 54         return rt;
 55     }
 56     else{
 57         Treap *rt=copy(b);
 58         rt->ch[0]=merge(a,rt->ch[0]);
 59         rt->pushup();
 60         return rt;
 61     }
 62 }
 63 void travel(Treap *rt){
 64     if(rt==null)return ;
 65     travel(rt->ch[0]);
 66     a[++cnt]=rt->val;
 67     travel(rt->ch[1]);
 68 }
 69 Treap * build(int l,int r){
 70     if(l>r)return null;
 71     int mid=(l+r)>>1;
 72     Treap *rt=newTreap(a[mid]);
 73     rt->ch[0]=build(l,mid-1);
 74     rt->ch[1]=build(mid+1,r);
 75     rt->pushup();
 76     return rt;
 77 }
 78 void rebuild(){
 79     tot=n;cnt=0;
 80     travel(root);
 81     root=build(1,n);
 82 }
 83 LL query(int x){
 84     Treap *now=root;
 85     LL ans=0;
 86     while(1){
 87         if(now==null)return ans;
 88         if(now->ch[0]->size>=x)now=now->ch[0];
 89         else ans+=now->ch[0]->sum+now->val,x-=now->ch[0]->size+1,now=now->ch[1];
 90     }
 91 }
 92 Treap * qp (Treap *a,int b){
 93     Treap *c=null;
 94     for(;b;b>>=1,a=merge(a,a))
 95         if(b&1)c=merge(c,a);
 96     return c;
 97 }
 98 void work(int l,int r){
 99     int k;scanf("%d",&k);
100     tp x=split(root,l-1);
101     tp y=split(x.second,r-l+1);
102     tp z=split(x.first,l-k-1);
103     tp w=split(z.second,(r-l+1)%k);
104     Treap *rt=qp(z.second,(r-l+1)/k);
105     rt=merge(rt,w.first);
106     root=merge(merge(x.first,rt),y.second);
107     if((N<<5)-tot<1000)rebuild();
108 }
109 void update(int l,int r){
110     tp x=split(root,l-1);
111     tp y=split(x.second,r-l+1);
112     tp z=split(org,l-1);
113     tp w=split(z.second,r-l+1);
114     root=merge(merge(x.first,w.first),y.second);
115     if((N<<5)-tot<1000)rebuild();
116 }
117 int main(){
118     null=mem;
119     null->ch[0]=null->ch[1]=null;
120     null->size=null->val=null->sum=0;
121     scanf("%d%d",&n,&m);
122     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
123     root=org=build(1,n);
124     int o,l,r;
125     while(m--){
126         scanf("%d%d%d",&o,&l,&r);
127         if(o==1)printf("%lld\n",query(r)-query(l-1));
128         if(o==2)work(l,r);
129         if(o==3)update(l,r);
130     }
131     return 0;
132 }
View Code

C,我们要的是$\sum_{i=1}^{mx}{(-\mu{(i)}) \cdot \prod_{j=1}^{n}{ \lfloor {\frac{a_{j}}{i}} \rfloor}}$ ,直接预处理前缀和然后调和级数。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define mod 1000000007
 7 #define N 100500
 8 using namespace std;
 9 int mu[N],prime[N],vis[N],tot;
10 int T,n,ans,mn,mx,s[N],a[N];
11 void init(){
12     mu[1]=1;
13     for(int i=2;i<=100000;i++){
14         if(!vis[i]){
15             prime[++tot]=i;
16             mu[i]=-1;
17         }
18         for(int j=1;j<=tot&&i*prime[j]<=100000;j++){
19             vis[i*prime[j]]=1;
20             if(i%prime[j]==0){
21                 mu[i*prime[j]]=0;
22                 break;
23             }
24             mu[i*prime[j]]=-mu[i];
25         }
26     }
27 }
28 void UPD(int &a,int b){a=(a+b>=mod)?(a+b-mod):(a+b);}
29 int qp(int a,int b){
30     int c=1;
31     for(;b;b>>=1,a=1ll*a*a%mod)
32         if(b&1)c=1ll*c*a%mod;
33     return c;
34 }
35 int main(){
36     init();
37     scanf("%d",&T);
38     for(int ca=1;ca<=T;ca++){
39         scanf("%d",&n);
40         mn=0x3fffffff;mx=0;
41         memset(s,0,sizeof s);
42         for(int i=1;i<=n;i++){
43             scanf("%d",&a[i]);
44             mn=min(mn,a[i]);
45             mx=max(mx,a[i]);
46             s[a[i]]++;
47         }
48         for(int i=1;i<=mx;i++)s[i]=s[i-1]+s[i];
49         ans=0;
50         for(int i=2,now,j;i<=mn;i++)if(mu[i]){
51             for(now=j=1;j*i<=mx;j++)
52                 now=1ll*now*qp(j,s[min(mx,(j+1)*i-1)]-s[j*i-1])%mod;
53             if(mu[i]<0)UPD(ans,now);
54             else UPD(ans,mod-now);
55         }
56         printf("Case #%d: %d\n",ca,ans);
57     }
58     return 0;
59 }
View Code

 D,签到题,乱判就行。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 using namespace std;
 7 int T,bo[10],x[10];
 8 char s[10][30];
 9 int getnum(int x){
10     bo[1]=(s[1][x+1]=='X');
11     bo[2]=(s[2][x]=='X');
12     bo[3]=(s[2][x+3]=='X');
13     bo[4]=(s[4][x+1]=='X');
14     bo[5]=(s[5][x]=='X');
15     bo[6]=(s[5][x+3]=='X');
16     bo[7]=(s[7][x+1]=='X');
17     if((bo[1])&&(bo[2])&&(bo[3])&&(!bo[4])&&(bo[5])&&(bo[6])&&(bo[7]))return 0;
18     if((!bo[1])&&(!bo[2])&&(bo[3])&&(!bo[4])&&(!bo[5])&&(bo[6])&&(!bo[7]))return 1;
19     if((bo[1])&&(!bo[2])&&(bo[3])&&(bo[4])&&(bo[5])&&(!bo[6])&&(bo[7]))return 2;
20     if((bo[1])&&(!bo[2])&&(bo[3])&&(bo[4])&&(!bo[5])&&(bo[6])&&(bo[7]))return 3;
21     if((!bo[1])&&(bo[2])&&(bo[3])&&(bo[4])&&(!bo[5])&&(bo[6])&&(!bo[7]))return 4;
22     if((bo[1])&&(bo[2])&&(!bo[3])&&(bo[4])&&(!bo[5])&&(bo[6])&&(bo[7]))return 5;
23     if((bo[1])&&(bo[2])&&(!bo[3])&&(bo[4])&&(bo[5])&&(bo[6])&&(bo[7]))return 6;
24     if((bo[1])&&(!bo[2])&&(bo[3])&&(!bo[4])&&(!bo[5])&&(bo[6])&&(!bo[7]))return 7;
25     if((bo[1])&&(bo[2])&&(bo[3])&&(bo[4])&&(bo[5])&&(bo[6])&&(bo[7]))return 8;
26     if((bo[1])&&(bo[2])&&(bo[3])&&(bo[4])&&(!bo[5])&&(bo[6])&&(bo[7]))return 9;
27 }
28 int main(){
29     scanf("%d",&T);
30     while(T--){
31         for(int i=1;i<=7;i++)
32             scanf("%s",s[i]);
33         x[1]=getnum(0);
34         x[2]=getnum(5);
35         x[3]=getnum(12);
36         x[4]=getnum(17);
37         printf("%d%d:%d%d\n",x[1],x[2],x[3],x[4]);
38     }
39 }
View Code

E,化完式子是$3^{n} \cdot {\sum_{d=1}^{n} { \phi{(d)} \sum_{i=1}^{ \lfloor {\frac{n}{d}} \rfloor} }   \sum_{j=1}^{ \lfloor {\frac{n}{d}} \rfloor  - i}   C_{n}^{id} \cdot C_{n-id}^{jd}    }$

然后就可以愉快的任意模数FFT了,代码咕咕咕了555。对于任意模数fft可以看这里

F题就是一个树形dp,但是状态的确很难想到,关键的一维0和1代表当前点是否一定在这个最大匹配里,别的套路转移就好,转移时还要考虑这条边是否删去。

 1 #pragma GCC optimize ("O3")
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cmath>
 7 #define mod 998244353
 8 #define N 50005
 9 using namespace std;
10 int e,head[N];
11 struct edge{
12     int v,next;
13 }ed[N<<1];
14 void add(int u,int v){
15     ed[e].v=v;
16     ed[e].next=head[u];
17     head[u]=e++;
18 }
19 void UPD(int &a,int b){
20     a=(a+b>=mod)?(a+b-mod):(a+b);
21 }
22 int T,n,m,size[N],f[N][205][2],g[405][2];
23 void dfs(int x,int fa){
24     size[x]=1;
25     f[x][0][0]=1;
26     for(int i=head[x];i;i=ed[i].next){
27         int v=ed[i].v;
28         if(v==fa)continue;
29         dfs(v,x);
30         memset(g,0,sizeof g);
31         for(int j=0;j<=size[x];j++){
32             if(!f[x][j][0]&&!f[x][j][1])continue;
33             for(int k=0;k<=size[v];k++){
34                 UPD(g[j+k][0],1ll*f[x][j][0]*f[v][k][0]%mod);
35                 UPD(g[j+k+1][1],1ll*f[x][j][0]*f[v][k][0]%mod);
36                 UPD(g[j+k][0],2ll*f[x][j][0]*f[v][k][1]%mod);
37                 UPD(g[j+k][1],2ll*f[x][j][1]*(f[v][k][0]+f[v][k][1])%mod);
38             }
39         }
40         size[x]=min(m-1,size[x]+size[v]);
41         for(int j=0;j<=size[x];j++){
42             f[x][j][0]=(g[j][0]+g[j+m][0])%mod;
43             f[x][j][1]=(g[j][1]+g[j+m][1])%mod;
44         }
45     }
46 }
47 int main(){
48     scanf("%d",&T);
49     while(T--){
50         e=1;memset(head,0,sizeof head);
51         scanf("%d%d",&n,&m);
52         for(int i=1,u,v;i<n;i++){
53             scanf("%d%d",&u,&v);
54             add(u,v);add(v,u);
55         }
56         memset(f,0,sizeof f);
57         dfs(1,0);
58         printf("%d\n",(f[1][0][0]+f[1][0][1])%mod);
59     }
60     return 0;
61 }
View Code

G,又是wqs二分,我又没有想到,想斜率,斜率,斜率。二分减去的权值,然后做最小匹配并记录边数就好了。

 1 #pragma GCC optimize ("O3")
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cmath>
 7 #define LL long long
 8 #define N 40050
 9 #define inf 0x3f3f3f3f3f3f3f3f
10 using namespace std;
11 char B[1<<15],*S=B,*T=B;
12 #define getc (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
13 inline int read()
14 {
15     int x=0;char ch=getc;
16     while(ch<'0'|ch>'9')ch=getc;
17     while(ch>='0'&ch<='9')x=10*x+(ch^48),ch=getc;
18     return x;
19 }
20 int a[N][6],b[N][6],n,m,K,Tim;
21 int g[2][33],now,last,num;
22 LL f[2][33],Ans,ans;
23 void dp(int i,int j,LL v){
24     now^=1;last^=1;
25     memset(f[now],0x3f,sizeof f[now]);
26     f[now][0]=g[now][0]=0;
27     for(register int k=0,x,y,nk;k<(1<<m+1);++k)if(f[last][k]<inf){
28         x=(k>>j-1)&1,y=(k>>j)&1;
29         LL nf=f[last][k],ng=g[last][k];
30         if(x&&y)continue;
31         if(x){
32             nk=k^(1<<j-1);
33             if(nf<f[now][nk]||(nf==f[now][nk]&&ng>g[now][nk]))
34                 f[now][nk]=nf,g[now][nk]=ng;
35         }
36         else if(y){
37             nk=k^(1<<j);
38             if(nf<f[now][nk]||(nf==f[now][nk]&&ng>g[now][nk]))
39                 f[now][nk]=nf,g[now][nk]=ng;
40         }
41         else if(!x&&!y){
42             if(i<n){
43                 nk=k^(1<<j-1);
44                 if(nf+a[i][j]-v<f[now][nk]||(nf+a[i][j]-v==f[now][nk]&&ng+1>g[now][nk]))
45                     f[now][nk]=nf+a[i][j]-v,g[now][nk]=ng+1;
46             }
47             if(j<m){
48                 nk=k^(1<<j);
49                 if(nf+b[i][j]-v<f[now][nk]||(nf+b[i][j]-v==f[now][nk]&&ng+1>g[now][nk]))
50                     f[now][nk]=nf+b[i][j]-v,g[now][nk]=ng+1;
51             }
52             if(nf<f[now][k]||(nf==f[now][k]&&ng>g[now][k]))
53                 f[now][k]=nf,g[now][k]=ng;
54         }
55     }
56 }
57 bool work(LL x){
58     now=0;last=1;
59     memset(f[now],0x3f,sizeof f[now]);
60     memset(g,0,sizeof g);
61     f[now][0]=g[now][0]=0;
62     for(int i=1;i<=n;++i){
63         for(int j=1;j<=m;++j)
64             dp(i,j,x);
65         for(int j=(1<<m+1)-1;~j;--j){
66             if(j&1)f[now][j]=inf,g[now][j]=0;
67             else f[now][j]=f[now][j>>1],g[now][j]=g[now][j>>1];
68         }
69     }
70     ans=inf;
71     for(int i=0;i<(1<<m);i++)
72         if(f[now][i]<ans){ans=f[now][i],num=g[now][i];}
73     Ans=ans;
74     return num>=K;
75 }
76 int main(){
77     scanf("%d",&Tim);
78     while(Tim--){
79         n=read();m=read();K=read();
80         for(int i=1;i<n;++i)
81             for(int j=1;j<=m;++j)a[i][j]=read();
82         for(int i=1;i<=n;++i)
83             for(int j=1;j<m;++j)b[i][j]=read();
84         LL l=1,r=1e14,mid,fin=0;
85         while(l<=r){
86             mid=(2*l+r)/3;
87             if(work(mid))fin=mid,r=mid-1;
88             else l=mid+1;
89         }
90         work(fin);
91         printf("%lld\n",Ans+fin*K);
92     }
93 }
View Code

水平不行啊。

5.18

今天的话。前两个小时都在推T2的式子,后来推出来30分了,写上了,不过非常慢。又卡了卡常。之后看了看T1,感觉两个部分分都可以做,但是都没有写,看了看T3,不会。然后纠结去干T1还是T3,然而我树上莫队并不太会,链上的推的式子也很恶心,于是最后去想T3,然后发现是道水题,赶紧写了,因为方便,就先用int写了,没开long long,最后还剩2min的时候拍上了,赶紧把int都改成了long long结果inf没有改,就gg了。0+20+30=50。

T3,发现每个点一定和他第k+1个祖先颜色相同,于是把树缩上去之后dp就好了。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define LL long long
 7 #define inf 0x3fffffffffffffff
 8 #define N 2050
 9 using namespace std;
10 int T,up,n,K,m;
11 int a[10000005],b[10000005],pp[10000005];
12 LL f[N][205],s[N][205],ned[N][205],g[205];
13 namespace Read{
14     unsigned int SA, SB, SC;int p, A, B;
15     unsigned int rng61(){
16         SA ^= SA << 16;
17         SA ^= SA >> 5;
18         SA ^= SA << 1;
19         unsigned int t = SA;
20         SA = SB;
21         SB = SC;
22         SC ^= t ^ SA;
23         return SC;
24     }
25     void gen(){
26         scanf("%d%d%d%d%u%u%u%d%d", &n, &K, &m, &p, &SA, &SB, &SC, &A, &B);
27         for(int i = 1; i <= p; i++)scanf("%d%d", &a[i], &b[i]);
28         for(int i = p + 1; i <= n; i++){
29             a[i] = rng61() % A + 1;
30             b[i] = rng61() % B + 1;
31         }
32     }
33 }
34 bool dfs(int x){
35     if((x<<1)>up&&(x<(1<<K))){
36         memset(f[x],0,sizeof f[x]);
37         return 0;
38     }
39     if((x<<1)>up){
40         for(int i=0;i<m;i++)f[x][i]=ned[x][i];
41         return 1;
42     }
43     bool bo=0;
44     if((x<<1)<=up)bo|=dfs(x<<1);
45     if((x<<1|1)<=up)bo|=dfs(x<<1|1);
46     for(int i=0;i<m;i++)g[i]=0;
47     if((x<<1)<=up)for(int i=0;i<m;i++)g[i]+=f[x<<1][i];
48     if((x<<1|1)<=up)for(int i=0;i<m;i++)g[i]+=f[x<<1|1][i];
49     if(x>=(1<<K))bo=1;
50     if(!bo){
51         memset(f[x],0,sizeof f[x]);
52         return 0;
53     }
54     for(int i=0;i<m;i++){
55         f[x][i]=inf;
56         for(int j=0;j<m;j++)
57             f[x][i]=min(f[x][i],g[j]+ned[x][(i-j+m)%m]);
58     }
59     return 1;
60 }
61 int main(){
62 //freopen("test.in","r",stdin);
63     scanf("%d",&T);
64     while(T--){
65         Read::gen();
66         up=min(n,(1<<K+1)-1);
67         memset(s,0,sizeof s);
68         for(int i=1;i<=up;i++)pp[i]=i,s[i][a[i]%m]+=b[i];
69         for(int i=(1<<K+1);i<=n;i++){
70             pp[i]=pp[i>>(K+1)];
71             s[pp[i]][a[i]%m]+=b[i];
72         }
73         for(int i=1;i<=up;i++){
74             for(int j=0;j<m;j++){
75                 ned[i][j]=0;
76                 for(int k=0;k<m;k++)
77                     ned[i][j]+=s[i][k]*((j-k+m)%m);
78             }
79         }
80         dfs(1);
81         printf("%lld\n",f[1][0]);
82     }
83 }
View Code

保持思考。

5.19

心情不好不想写了怎么办。。

5.20

还是写写吧。

首先是昨天的IOI赛制,看完T1,并不难想,但很不想写,看T2,割点裸题?yy了一下好像要用圆方树,但我还是不会,然后看T3,貌似不是很难推。然后先去看T3,写了几个式子都不对,有点难搞,这时候发现WQ把T2A了??!抉择了一下决定去写T2,写了1h写完了个假的圆方树,结果过不了第二个样例,然后yy了一下,搞了种类似缩点的打法,过了,交!A了。然后接着去看T3,感觉有规律,最后打出来了个表,要分解质因数,然后没时间了。0+100+0=100 rank2。

题解一会补。

T2,裸的圆方树+虚树。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <vector>
  7 #define N 200500
  8 #define pb push_back
  9 using namespace std;
 10 int e=1,head[N];
 11 struct edge{
 12     int v,next;
 13 }ed[N<<1];
 14 void add(int u,int v){
 15     ed[e].v=v;
 16     ed[e].next=head[u];
 17     head[u]=e++;
 18 }
 19 vector <int> V[N];
 20 int n,m,qr,T,K,ans,q[N],tim;
 21 int dfn[N],low[N],top,sta[N],root,son,ge[N],tot;
 22 void tarjan(int x){
 23     dfn[x]=low[x]=++tim;
 24     sta[++top]=x;
 25     for(int i=0;i<V[x].size();i++){
 26         int v=V[x][i];
 27         if(dfn[v]){
 28             low[x]=min(low[x],dfn[v]);
 29             continue;
 30         }
 31         tarjan(v);
 32         low[x]=min(low[x],low[v]);
 33         if(dfn[x]<=low[v]){
 34             int y;tot++;
 35             do{
 36                 y=sta[top--];
 37                 add(y,n+tot);
 38                 add(n+tot,y);
 39             }while(y!=v);
 40             add(x,n+tot);
 41             add(n+tot,x);
 42             if(x==root)son++;
 43             else ge[x]=1;
 44         }
 45     }
 46 }
 47 int fa[N],dep[N],val[N],s[N],seq[N<<1],num,pos[N],mn[N<<1][20],lg[N<<1];
 48 void dfs(int x){
 49     dep[x]=dep[fa[x]]+1;
 50     s[x]=s[fa[x]]+val[x];
 51     seq[++num]=x;pos[x]=num;
 52     for(int i=head[x];i;i=ed[i].next){
 53         int v=ed[i].v;
 54         if(v==fa[x])continue;
 55         fa[v]=x;dfs(v);
 56         seq[++num]=x;
 57     }
 58 }
 59 int Min(int x,int y){return dep[x]<dep[y]?x:y;}
 60 void st_init(){
 61     for(int i=1,j=1,cnt=0;i<=num;i++){
 62         if(i>(j<<1))j<<=1,cnt++;
 63         lg[i]=cnt;
 64     }
 65     for(int i=1;i<=num;i++)mn[i][0]=seq[i];
 66     for(int i=1;i<=lg[num];i++)
 67         for(int j=1;j+(1<<i)-1<=num;j++)
 68             mn[j][i]=Min(mn[j][i-1],mn[j+(1<<i-1)][i-1]);
 69 }
 70 int getlca(int x,int y){
 71     x=pos[x];y=pos[y];
 72     if(x>y)swap(x,y);
 73     int k=lg[y-x+1];
 74     return Min(mn[x][k],mn[y-(1<<k)+1][k]);
 75 }
 76 bool cmp(int a,int b){
 77     return pos[a]<pos[b];
 78 }
 79 int getans(int x,int y){
 80     if(!y)return 0;
 81     return s[y]-s[x];
 82 }
 83 void init(){
 84     for(int i=1;i<=n;i++)V[i].clear();
 85     e=1;memset(head,0,sizeof head);
 86     top=tim=tot=num=0;
 87     memset(ge,0,sizeof ge);
 88     memset(fa,0,sizeof fa);
 89     memset(val,0,sizeof val);
 90     memset(dfn,0,sizeof dfn);
 91 }
 92 int main(){
 93     scanf("%d",&T);
 94     while(T--){
 95         scanf("%d%d",&n,&m);
 96         init();
 97         for(int i=1,u,v;i<=m;i++){
 98             scanf("%d%d",&u,&v);
 99             V[u].pb(v),V[v].pb(u);
100         }
101         root=1;son=0;
102         tarjan(1);
103         if(son>=2)ge[1]=1;
104         for(int i=1;i<=n;i++)if(ge[i])val[i]=1;
105         dfs(1);
106         st_init();
107         scanf("%d",&qr);
108         while(qr--){
109             scanf("%d",&K);
110             ans=0;
111             for(int i=1;i<=K;i++){
112                 scanf("%d",&q[i]);
113                 if(ge[q[i]])ans--;
114             }
115             sort(q+1,q+K+1,cmp);
116             sta[1]=q[1];top=1;
117             for(int i=2;i<=K;i++){
118                 int a=q[i],b=getlca(q[i],sta[top]),c=0;
119                 while(dep[sta[top]]>dep[b])
120                     ans+=getans(sta[top],c),c=sta[top--];
121                 ans+=getans(b,c);
122                 if(sta[top]!=b)sta[++top]=b;
123                 sta[++top]=a;
124             }
125             while(top>1)ans+=getans(sta[top-1],sta[top]),top--;
126             ans+=val[sta[1]];
127             printf("%d\n",ans);
128         }
129     }
130     return 0;
131 }
View Code

T3,首先我们设$f[i]$为最小循环节为i的方案数,可以发现$\sum_{d|m}{f[d]}=k^{    \lceil  \frac{m}{2} \rceil    }$,然后推一推式子就好了,其实挺麻烦的,不如打表,但是做法都是一样的,要分解质因数。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #define int long long
  7 using namespace std;
  8 int n,m,K,ans,mod,T;
  9 int p[55],cnt,mi[55],pk[55][66];
 10 int R(int x){
 11     return rand()*rand()%x;
 12 }
 13 int mul(int a,int b,int p){
 14     return (a*b-(int)(((long double)a*b+0.5)/p)*p+p)%p;
 15 }
 16 int qp(int a,int b,int c){
 17     int ans=1;
 18     for(;b;b>>=1,a=mul(a,a,c))
 19         if(b&1)ans=mul(ans,a,c);
 20     return ans;
 21 }
 22 int prime[10]={0,2,3,5,7,11};
 23 bool miller_rabin(int x){
 24     if(x==1)return 0;
 25     for(int i=1;i<=5;i++)if(x==prime[i])return 1;
 26     for(int i=1;i<=5;i++)if(x%prime[i]==0)return 0;
 27     int y=x-1,cnt=0;
 28     while(!(y&1))y>>=1,cnt++;
 29     for(int i=1;i<=5;i++){
 30         int now=qp(prime[i],y,x),nxt;
 31         for(int j=1;j<=cnt;j++){
 32             nxt=mul(now,now,x);
 33             if(nxt==1&&now!=1&&now!=x-1)return 0;
 34             now=nxt;
 35         }
 36         if(nxt!=1)return 0;
 37     }
 38     return 1;
 39 }
 40 int gcd(int a,int b){return !b?a:gcd(b,a%b);}
 41 int pollard_rho(int x,int y){
 42     int c=R(x-1)+1,d=c,g=1;
 43     for(int i=1,j=2;g==1;i++){
 44         c=(mul(c,c,x)+y)%x;
 45         g=gcd(abs(c-d),x);
 46         if(i==j)d=c,j<<=1;
 47     }
 48     return g;
 49 }
 50 void divide(int x){
 51     if(x==1)return ;
 52     if(miller_rabin(x)){
 53         p[++cnt]=x;
 54         return ;
 55     }
 56     int now=x;
 57     while(now==x)now=pollard_rho(x,R(x-1));
 58     divide(now);
 59     divide(x/now);
 60 }
 61 int getg(int x){
 62     return qp(K,(x+1)/2,mod);
 63 }
 64 int geth(int x){
 65     return (x&1?x:(x>>1))%mod;
 66 }
 67 void UPD(int &a,int b){
 68     a=(a+b>=mod)?(a+b-mod):(a+b);
 69 }
 70 void dfs(int x,int d,int now){
 71     if(x==m+1){
 72         if((d&1)&&(!((n/d)&1)))return;
 73         //printf("d==%lld  n/d==%lld  now==%lld  g=%lld  h=%lld\n",d,n/d,now,getg(d),geth(d));
 74         UPD(ans,getg(d)*geth(d)%mod*(now%mod+mod)%mod);
 75         return ;
 76     }
 77     for(int i=0;i<=mi[x];i++)
 78         dfs(x+1,d*pk[x][i],(i==mi[x])?now:now*(1-p[x]));
 79 }
 80 signed main(){
 81     scanf("%lld",&T);
 82     while(T--){
 83         scanf("%lld%lld%lld",&n,&K,&mod);K%=mod;
 84         cnt=0;
 85         divide(n);
 86         sort(p+1,p+cnt+1);
 87         m=0;
 88         for(int i=1,j=1;i<=cnt;i=j){
 89             p[++m]=p[i];mi[m]=0;
 90             pk[m][0]=1;
 91             for(;j<=cnt&&p[j]==p[i];j++){
 92                 mi[m]++;
 93                 pk[m][mi[m]]=pk[m][mi[m]-1]*p[i];
 94             }
 95         }
 96         //for(int i=1;i<=m;i++)printf("%lld  %lld\n",p[i],mi[i]);
 97         ans=0;
 98         dfs(1,1,1);
 99         printf("%lld\n",ans);
100     }
101     return 0;
102 }
正解的式子
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define int long long
 7 using namespace std;
 8 int n,m,K,ans,mod,T;
 9 int p[55],cnt,mi[55],pk[55][66];
10 int R(int x){
11     return rand()*rand()%x;
12 }
13 int mul(int a,int b,int p){
14     return (a*b-(int)(((long double)a*b+0.5)/p)*p+p)%p;
15 }
16 int qp(int a,int b,int c){
17     int ans=1;
18     for(;b;b>>=1,a=mul(a,a,c))
19         if(b&1)ans=mul(ans,a,c);
20     return ans;
21 }
22 int prime[10]={0,2,3,5,7,11};
23 bool miller_rabin(int x){
24     if(x==1)return 0;
25     for(int i=1;i<=5;i++)if(x==prime[i])return 1;
26     for(int i=1;i<=5;i++)if(x%prime[i]==0)return 0;
27     int y=x-1,cnt=0;
28     while(!(y&1))y>>=1,cnt++;
29     for(int i=1;i<=5;i++){
30         int now=qp(prime[i],y,x),nxt;
31         for(int j=1;j<=cnt;j++){
32             nxt=mul(now,now,x);
33             if(nxt==1&&now!=1&&now!=x-1)return 0;
34             now=nxt;
35         }
36         if(nxt!=1)return 0;
37     }
38     return 1;
39 }
40 int gcd(int a,int b){return !b?a:gcd(b,a%b);}
41 int pollard_rho(int x,int y){
42     int c=R(x-1)+1,d=c,g=1;
43     for(int i=1,j=2;g==1;i++){
44         c=(mul(c,c,x)+y)%x;
45         g=gcd(abs(c-d),x);
46         if(i==j)d=c,j<<=1;
47     }
48     return g;
49 }
50 void divide(int x){
51     if(x==1)return ;
52     if(miller_rabin(x)){
53         p[++cnt]=x;
54         return ;
55     }
56     int now=x;
57     while(now==x)now=pollard_rho(x,R(x-1));
58     divide(now);
59     divide(x/now);
60 }
61 void UPD(int &a,int b){
62     a=(a+b>=mod)?(a+b-mod):(a+b);
63 }
64 void dfs(int x,int pos,int now){
65     if(x==m+1){
66         UPD(ans,(now%mod+mod)%mod*qp(K,(pos+1)/2,mod)%mod);
67         return ;
68     }
69     if(p[x]!=2)
70         for(int i=0;i<=mi[x];i++)
71             dfs(x+1,pos*pk[x][i],(i==mi[x])?now*pk[x][i]:now*(pk[x][i]*(1-p[x])));
72     else
73         for(int i=0;i<mi[x];i++)
74             dfs(x+1,pos*pk[x][i+1],(i==mi[x]-1)?now*pk[x][i]:now*(pk[x][i]*(1-p[x])));
75 }
76 signed main(){
77 //freopen("test.in","r",stdin);
78     scanf("%lld",&T);
79     while(T--){
80         scanf("%lld%lld%lld",&n,&K,&mod);K%=mod;
81         cnt=0;
82         divide(n);
83         sort(p+1,p+cnt+1);
84         m=0;
85         for(int i=1,j=1;i<=cnt;i=j){
86             p[++m]=p[i];mi[m]=0;
87             pk[m][0]=1;
88             for(;j<=cnt&&p[j]==p[i];j++){
89                 mi[m]++;
90                 pk[m][mi[m]]=pk[m][mi[m]-1]*p[i];
91             }
92         }
93         ans=0;
94         dfs(1,1,1);
95         printf("%lld\n",ans);
96     }
97     return 0;
98 }
打表的式子

今天更爆炸,上来玩了题答的前三个点,然后看了眼状态,wqA了T2,然后去搞,没搞出来,然后lc又在旁边大喊大叫说自己A了T1,之后写了个20分,打了个表,其实都要找出来了没仔细看,然后gg。T2puts("2")。0+25+58=83,T1幂处理的s的,T2暴力O(n^2)95?T3数组开小白扔10分?,什么玩意啊。。。操。。。菜!

T1式子懒得写了,就是一堆插板法合并起来。我的表都打出来了啊,就差一点,QAQ。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define N 1000500
 7 using namespace std;
 8 int n,m,s,invs,mx,mod,ans,fac[N<<2],inv[N<<2],pw[N<<2];
 9 void UPD(int &a,int b){
10     a=(a+b>=mod)?(a+b-mod):(a+b);
11 }
12 int qp(int a,int b){
13     int c=1;
14     for(;b;b>>=1,a=1ll*a*a%mod)
15         if(b&1)c=1ll*c*a%mod;
16     return c;
17 }
18 int C(int n,int m){
19     if(m>n||m<0)return 0;
20     if(m==0||m==n)return 1;
21     return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
22 }
23 int main(){
24     scanf("%d%d%d%d",&n,&m,&s,&mod);
25     mx=2*m+n+s;
26     fac[0]=1;
27     for(int i=1;i<=mx;i++)fac[i]=1ll*fac[i-1]*i%mod;
28     inv[mx]=qp(fac[mx],mod-2);
29     for(int i=mx;i;i--)inv[i-1]=1ll*inv[i]*i%mod;
30     invs=qp(s+1,mod-2);
31     pw[0]=qp(s+1,1ll*n*m%(mod-1));
32     for(int i=1;i<=(n+m)<<1;i++)pw[i]=1ll*pw[i-1]*invs%mod;
33     for(int i=0;i<=m-2;i++)
34         UPD(ans,1ll*C(n-2+i,i)*C(n+m+s+i-3,s-n+1)%mod*pw[((i+n-1)<<1|1)+(m-i-1)]%mod);
35     for(int i=0;i<=n-2&&i<=s;i++)
36         UPD(ans,1ll*C(m-2+i,i)*C(2*m+n+s-4,s-i)%mod*pw[((i+m-1)<<1|1)+(n-i-1)]%mod);
37     printf("%d\n",ans);
38     return 0;
39 }
View Code

T2,最小链覆盖等于最长反链,具体我也不是特别懂。然后就是个裸的cdq啦。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define N 200500
 7 using namespace std;
 8 struct data{int id,x1,x2,x3,x4;}d[N];
 9 bool cmpx1(data a,data b){return a.x1<b.x1;}
10 bool cmpx2(data a,data b){return a.x2<b.x2;}
11 int n,num[N],num_cnt,f[N],c[N],ans;
12 void add(int x,int y){for(;x<=num_cnt;x+=x&-x)c[x]=max(c[x],y);}
13 int query(int x){int y=0;for(;x;x-=x&-x)y=max(y,c[x]);return y;}
14 void clear(int x){for(;x<=num_cnt;x+=x&-x)c[x]=0;}
15 void cdq(int l,int r){
16     if(l==r){
17         f[d[l].id]=max(f[d[l].id],1);
18         return ;
19     }
20     int mid=(l+r)>>1;
21     cdq(l,mid);
22     sort(d+l,d+mid+1,cmpx2);
23     sort(d+mid+1,d+r+1,cmpx1);
24     for(int i=mid+1,j=l;i<=r;i++){
25         for(;j<=mid&&d[j].x2<d[i].x1;j++)
26             add(d[j].x4,f[d[j].id]);
27         f[d[i].id]=max(f[d[i].id],query(d[i].x3)+1);
28     }
29     for(int i=l;i<=mid;i++)clear(d[i].x4);
30     cdq(mid+1,r);
31 }
32 int main(){
33     scanf("%d",&n);
34     for(int i=1;i<=n;i++){
35         d[i].id=i;
36         scanf("%d%d%d%d",&d[i].x1,&d[i].x2,&d[i].x3,&d[i].x4);
37         num[++num_cnt]=d[i].x3;
38         num[++num_cnt]=d[i].x4;
39     }
40     sort(num+1,num+num_cnt+1);
41     for(int i=1;i<=n;i++)
42         d[i].x3=lower_bound(num+1,num+num_cnt+1,d[i].x3)-num,
43         d[i].x4=lower_bound(num+1,num+num_cnt+1,d[i].x4)-num;
44     sort(d+1,d+n+1,cmpx1);
45     cdq(1,n);
46     for(int i=1;i<=n;i++)ans=max(ans,f[i]);
47     printf("%d\n",ans);
48     return 0;
49 }
View Code

T3最小生成树有68分,正解好像是发现点构成了一些直线,然后巴拉巴拉什么的。

加油加油!!!!!!!

5.24IOI赛制

考试先看T1,不太会,然后想了一会,发现就是三维偏序,log2稳T,写了个cdq和暴力拍,没事就交了,60分,然后看后两题都只会暴力的样子,然后先写了T2的25分暴力,然后想40分,要处理所有回文串的出现次数?不行啊。然后看T3,尝试着puts2,10分,加了个puts0,40,又写了个快速幂,60。

T1,把三个两两组合做二维偏序,答案就是所有的减去这三个答案再除以2。证明的话,110+111+101+111+011+111=3*111+(110+101+011)=C(n,2)+2*111;

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define LL long long
 7 #define N 2000500
 8 using namespace std;
 9 int n,c[N];
10 void add(int x){for(;x<=n;x+=x&-x)c[x]++;}
11 int query(int x){int ans=0;for(;x;x-=x&-x)ans+=c[x];return ans;}
12 LL ans;
13 struct data{int a,b,c;}d[N],tmp[N];
14 bool cmpa(data a,data b){return a.a<b.a;}
15 bool cmpb(data a,data b){return a.b<b.b;}
16 LL seed;
17 LL Rand(){return seed=((seed*19260817)^233333)&((1<<24)-1);}
18 LL work1(){
19     LL ans=0;
20     memset(c,0,sizeof c);
21     sort(d+1,d+n+1,cmpa);
22     for(int i=1;i<=n;i++){
23         ans+=query(d[i].b);
24         add(d[i].b);
25     }
26     return ans;
27 }
28 LL work2(){
29     LL ans=0;
30     memset(c,0,sizeof c);
31     sort(d+1,d+n+1,cmpa);
32     for(int i=1;i<=n;i++){
33         ans+=query(d[i].c);
34         add(d[i].c);
35     }
36     return ans;
37 }
38 LL work3(){
39     LL ans=0;
40     memset(c,0,sizeof c);
41     sort(d+1,d+n+1,cmpb);
42     for(int i=1;i<=n;i++){
43         ans+=query(d[i].c);
44         add(d[i].c);
45     }
46     return ans;
47 }
48 int main(){
49     scanf("%d",&n);
50     for(int i=1;i<=n;i++)d[i].a=d[i].b=d[i].c=i;
51     scanf("%lld",&seed);for(int i=1;i<=n;i++)swap(d[i].a,d[Rand()%i+1].a);
52     scanf("%lld",&seed);for(int i=1;i<=n;i++)swap(d[i].b,d[Rand()%i+1].b);
53     scanf("%lld",&seed);for(int i=1;i<=n;i++)swap(d[i].c,d[Rand()%i+1].c);
54     ans=work1()+work2()+work3()-1ll*n*(n-1)/2;
55     printf("%lld\n",ans/2);
56     return 0;
57 }
View Code

T2,回文自动机+树剖,复习了回文自动机,不错。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #define int long long
  7 #define N 200005
  8 using namespace std;
  9 struct data{
 10     char o[10];
 11     int x,l1,r1,l2,r2;
 12 }d[N];
 13 int n,m,a[N],s[N],L,nowl,nowr,pp1[N],pp2[N];
 14 int e=1,head[N];
 15 struct edge{
 16     int v,next;
 17 }ed[N];
 18 void add(int u,int v){
 19     ed[e].v=v;
 20     ed[e].next=head[u];
 21     head[u]=e++;
 22 }
 23 int ch[N][26],fail[N],len[N],tot;
 24 int getfail(int x,int p){
 25     while(s[p]!=s[p-len[x]-1])x=fail[x];
 26     return x;
 27 }
 28 int getfail1(int x,int p){
 29     while(s[p]!=s[p+len[x]+1])x=fail[x];
 30     return x;
 31 }
 32 void extend(int pos,int c){
 33     int p=getfail(pp1[pos-1],pos);
 34     if(!ch[p][c]){
 35         int np=++tot;
 36         len[np]=len[p]+2;
 37         int q=getfail(fail[p],pos);
 38         fail[np]=ch[q][c];
 39         ch[p][c]=np;
 40         add(fail[np],np);
 41     }
 42     pp1[pos]=ch[p][c];
 43 }
 44 void travel(int x,int pos){
 45     pp2[x]=pos;
 46     if(x==1)return ;
 47     int p=getfail1(pos,x-1);
 48     travel(x-1,ch[p][s[x-1]]); 
 49 }
 50 int dep[N],size[N],son[N],top[N],id[N],pp[N],num,fa[N][20],LCA;
 51 int sum[N<<2],sum_val[N<<2],lazy[N<<2];
 52 void dfs1(int x,int d){
 53     dep[x]=d;size[x]=1;
 54     son[x]=tot+1;
 55     for(int i=1;(1<<i)<=dep[x];i++)
 56         fa[x][i]=fa[fa[x][i-1]][i-1];
 57     for(int i=head[x];i;i=ed[i].next){
 58         int v=ed[i].v;
 59         fa[v][0]=x;dfs1(v,d+1);
 60         size[x]+=size[v];
 61         if(size[v]>size[son[x]])son[x]=v;
 62     }
 63 }
 64 void dfs2(int x,int t){
 65     id[x]=++num,pp[num]=x,top[x]=t;
 66     if(son[x]!=tot+1)dfs2(son[x],t);
 67     for(int i=head[x];i;i=ed[i].next){
 68         int v=ed[i].v;
 69         if(v==son[x])continue;
 70         dfs2(v,v);
 71     }
 72 }
 73 void build(int rt,int l,int r){
 74     if(l==r){
 75         sum[rt]=len[pp[l]]>0?len[pp[l]]:0;
 76         return ;
 77     }
 78     int mid=(l+r)>>1;
 79     build(rt<<1,l,mid);
 80     build(rt<<1|1,mid+1,r);
 81     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
 82 }
 83 void update_lazy(int rt,int x){
 84     lazy[rt]+=x;
 85     sum_val[rt]+=x*sum[rt];
 86 }
 87 void pushdown(int rt){
 88     if(lazy[rt]){
 89         update_lazy(rt<<1,lazy[rt]);
 90         update_lazy(rt<<1|1,lazy[rt]);
 91         lazy[rt]=0;
 92     }
 93 }
 94 void pushup(int rt){
 95     sum_val[rt]=sum_val[rt<<1]+sum_val[rt<<1|1];
 96 }
 97 void update(int rt,int l,int r,int x,int y){
 98     if(x<=l&&r<=y){
 99         update_lazy(rt,1);
100         return ;
101     }
102     pushdown(rt);
103     int mid=(l+r)>>1;
104     if(x<=mid)update(rt<<1,l,mid,x,y);
105     if(y>mid)update(rt<<1|1,mid+1,r,x,y);
106     pushup(rt);
107 }
108 int query(int rt,int l,int r,int x,int y){
109     if(x<=l&&r<=y)return sum_val[rt];
110     int mid=(l+r)>>1;
111     pushdown(rt);
112     if(y<=mid)return query(rt<<1,l,mid,x,y);
113     if(x>mid)return query(rt<<1|1,mid+1,r,x,y);
114     return query(rt<<1,l,mid,x,y)+query(rt<<1|1,mid+1,r,x,y);
115 }
116 void update(int x){
117     do{
118         update(1,1,tot+1,id[top[x]],id[x]);
119         x=fa[top[x]][0];
120     }while(x<=tot);
121 }
122 void extendr(int pos){
123     int x=pp1[pos];
124     for(int i=18;~i;i--)
125         if(pos-len[fa[x][i]]+1<nowl)x=fa[x][i];
126     if(pos-len[x]+1<nowl)x=fa[x][0];
127     update(x);
128 }
129 void extendl(int pos){
130     int x=pp2[pos];
131     for(int i=18;~i;i--)
132         if(pos+len[fa[x][i]]-1>nowr)x=fa[x][i];
133     if(pos+len[x]-1>nowr)x=fa[x][0];
134     update(x);
135 }
136 int query(int x,int y){
137     int ans=0;
138     while(top[x]!=top[y]){
139         if(dep[top[x]]<dep[top[y]])swap(x,y);
140         ans+=query(1,1,tot+1,id[top[x]],id[x]);
141         x=fa[top[x]][0];
142     }
143     if(dep[x]>dep[y])swap(x,y);
144     ans+=query(1,1,tot+1,id[x],id[y]);
145     LCA=x;
146     return ans;
147 }
148 void queryr(int l1,int r1,int l2,int r2){
149     int x=pp2[l1],y=pp2[l2];
150     for(int i=18;~i;i--)
151         if(l1+len[fa[x][i]]-1>r1)x=fa[x][i];
152     if(l1+len[x]-1>r1)x=fa[x][0];
153     for(int i=18;~i;i--)
154         if(l2+len[fa[y][i]]-1>r2)y=fa[y][i];
155     if(l2+len[y]-1>r2)y=fa[y][0];
156     int ans=query(x,y);
157     if((len[LCA]<(r1-l1+1)&&len[LCA]<(r2-l2+1))&&s[l1+len[LCA]]==s[l2+len[LCA]])
158         ans-=query(1,1,tot+1,id[LCA],id[LCA]);
159     printf("%lld\n",ans);
160 }
161 void queryl(int l1,int r1,int l2,int r2){
162     int x=pp1[r1],y=pp1[r2];
163     for(int i=18;~i;i--)
164         if(r1-len[fa[x][i]]+1<l1)x=fa[x][i];
165     if(r1-len[x]+1<l1)x=fa[x][0];
166     for(int i=18;~i;i--)
167         if(r2-len[fa[y][i]]+1<l2)y=fa[y][i];
168     if(r2-len[y]+1<l2)y=fa[y][0];
169     int ans=query(x,y);
170     if((len[LCA]<(r1-l1+1)&&len[LCA]<(r2-l2+1))&&s[r1-len[LCA]]==s[r2-len[LCA]])
171         ans-=query(1,1,tot+1,id[LCA],id[LCA]);
172     printf("%lld\n",ans);
173 }
174 signed main(){
175     scanf("%lld%lld",&n,&m);
176     for(int i=1;i<=n;i++)
177         scanf("%lld",&a[i]);
178     for(int i=1;i<=m;i++){
179         scanf("%s",d[i].o);
180         if(d[i].o[0]=='a')
181             scanf("%lld",&d[i].x);
182         else scanf("%lld%lld%lld%lld",&d[i].l1,&d[i].r1,&d[i].l2,&d[i].r2);
183     }
184     s[0]=-1;
185     for(int i=m;i;i--)
186         if(d[i].o[0]=='a'&&d[i].o[3]=='l')
187             s[++L]=d[i].x;
188     nowl=L+1;
189     for(int i=1;i<=n;i++)s[++L]=a[i];
190     nowr=L;
191     for(int i=1;i<=m;i++)
192         if(d[i].o[0]=='a'&&d[i].o[3]=='r')
193             s[++L]=d[i].x;
194     s[L+1]=-1;
195     tot=1;len[1]=-1;
196     fail[0]=fail[1]=1;
197     add(1,0);
198     for(int i=1;i<=L;i++)
199         extend(i,s[i]);
200     travel(L+1,0);
201     fa[1][0]=tot+1;
202     dfs1(1,1);
203     dfs2(1,1);
204     build(1,1,tot+1);
205     for(int i=nowl;i<=nowr;i++)extendr(i);
206     for(int i=1;i<=m;i++){
207         if(d[i].o[0]=='t'){
208             if(d[i].o[5]=='l')queryl(nowl-1+d[i].l1,nowl-1+d[i].r1,nowl-1+d[i].l2,nowl-1+d[i].r2);
209             else queryr(nowl-1+d[i].l1,nowl-1+d[i].r1,nowl-1+d[i].l2,nowl-1+d[i].r2);
210         }
211         else{
212             if(d[i].o[3]=='l')extendl(--nowl);
213             else extendr(++nowr);
214         }
215     }
216     return 0;
217 }
View Code

 5.25

先看T1,推了推,只会60暴搜,然后看T2,不太清楚,看T3,好像会20骗分。写T1,写完60分总感觉可以直接dp,但是怎么想也想不出来。然后又乱搞了一会,也没想出来啥别的做法,后来只剩90min了,赶紧去写T2,O(n)的式子推了我好久,花了一个多小时写完了,然后测了组极限数据,6s??后来发现是因为我在结构体里开了个vector,然后sort就炸了。最后没改完,只得了20分,T3暴力都没交。

本来感觉这场考试应该能考得不错的,然后就是炸,不行啊!

T1就是个简单的小dp,为什么我就想不到?包括ctscD1T1,我想了1h+,可能是这阵做的dp太少了吧,必须要思考,尤其是这种没思路的,想想最基本的状态定义还有转移,也许真的不难。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define mod 1000000007
 7 #define N 100500
 8 using namespace std;
 9 int qp(int a,int b){
10     int c=1;
11     for(;b;b>>=1,a=1ll*a*a%mod)
12         if(b&1)c=1ll*c*a%mod;
13     return c;
14 }
15 int fac[N],inv[N];
16 int num[10],now[10],nw[10],wcnt,Ans,n,len;
17 char s[N];
18 void UPD(int &a,int b){a=(a+b>=mod)?(a+b-mod):(a+b);}
19 int C(int n,int m){
20     if(m==n||m==0)return 1;
21     return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
22 }
23 int f[2][1050];
24 void work(){
25     for(int i=1;i<=5;i++){
26         for(int j=0;j<=9;j++)now[j]=num[j];
27         now[i]--;now[10-i]--;
28         int ii=0;memset(f[ii],0,sizeof f[ii]);
29         for(int j=max(0,0-now[9]);j<=wcnt;j++)
30             for(int k=max(0,now[9]+j-now[0]);j+k<=wcnt;k++)
31                 UPD(f[ii][j+k],1ll*C(wcnt,j)*C(wcnt-j,k)%mod);
32         for(int j=1;j<=4;j++){
33             ii^=1;memset(f[ii],0,sizeof f[ii]);
34             for(int k1=max(0,max(0,now[9-j])-now[j]),k2=now[j]+k1-now[9-j];k1+k2<=wcnt;k1++,k2++){
35                 for(int l=0;l+k1+k2<=wcnt;l++)
36                     UPD(f[ii][l+k1+k2],1ll*f[ii^1][l]*C(wcnt-l,k1)%mod*C(wcnt-l-k1,k2)%mod);
37             }
38         }
39         UPD(Ans,f[ii][wcnt]);
40     }
41 }
42 int main(){
43     scanf("%s",s+1);
44     len=strlen(s+1);n=len>>1;
45     for(int i=1;i<=len;i++){
46         if(s[i]=='?')wcnt++;
47         else num[s[i]-'0']++;
48     }
49     fac[0]=1;
50     for(int i=1;i<=wcnt;i++)fac[i]=1ll*fac[i-1]*i%mod;
51     inv[wcnt]=qp(fac[wcnt],mod-2);
52     for(int i=wcnt;i>=1;i--)inv[i-1]=1ll*inv[i]*i%mod;
53     work();
54     printf("%d\n",Ans);
55     return 0;
56 }
View Code

T2,我犯了好几个小错误,在这说一下吧,首先是在结构体里开vector,虽然只有一个数,但是常数一下打了若干倍,其次就是在函数中定义变量没有初始化,再有就是inf开的不够大,反正全是小毛病,细心,再细心。

  1 #pragma GCC optimize ("O3")
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <cmath>
  7 #include <vector>
  8 #define N 100500
  9 #define eps 1e-12
 10 #define inf 0x7fffffffffffffff
 11 #define pb push_back
 12 using namespace std;
 13 int n;
 14 double w[N],sw[N],d[N],sd[N],SUM[N],DIS[N],Ans[N],l[N],r[N],down,up;
 15 int tot,top,be,pp[N];
 16 vector <int> V[N];
 17 struct point{
 18     double x,y;
 19     int id;
 20     point(){x=y=0;}
 21     point(double a,double b){x=a;y=b;}
 22     point operator - (point a){return point(x-a.x,y-a.y);}
 23     double operator * (point a){return x*a.y-y*a.x;}
 24 }p[N],q[N];
 25 double getdis(point a){
 26     return sqrt(a.x*a.x+a.y*a.y);
 27 }
 28 bool cmp(point a,point b){
 29     double now=(a-p[1])*(b-p[1]);
 30     if(now==0)return getdis(a-p[1])<getdis(b-p[1]);
 31     return now>0;
 32 }
 33 int getf(double a){
 34     if(a<-eps)return -1;
 35     if(a>eps)return 1;
 36     return 0;
 37 }
 38 int vis[N],cnt;
 39 namespace work1{
 40     void Main(){
 41         sw[n]=sw[n-1]+down;
 42         double x1=0,x2=0,sum1=0,sum2=0;
 43         x1=d[1];sum1=w[n]*x1;
 44         SUM[1]=d[n]*sum1;
 45         for(int i=n-1;i>=2;i--){
 46             x1+=d[i+1];
 47             sum1+=w[i]*x1;
 48             SUM[1]+=d[i]*sum1;
 49         }
 50         for(int i=3;i<=n;i++){
 51             x2+=d[i];
 52             sum2+=x2*w[i];
 53         }
 54         x2+=d[1];sum2+=x2*w[1];
 55         for(int i=2;i<=n;i++){
 56             SUM[i]=SUM[i-1]-d[i]*sum1+d[i]*sum2;
 57             sum1+=d[i]*sw[n];sum1-=sd[n]*w[i];
 58             sum2+=sd[n]*w[i];sum2-=d[i+1]*sw[n];
 59         }
 60         double ans=SUM[1];
 61         for(int i=2;i<=n;i++)
 62             ans=min(ans,SUM[i]);
 63         for(int i=1;i<=n;i++)
 64             if(getf(ans-SUM[i])==0)cnt++,vis[i]=1;
 65         for(int i=1;i<=n;i++){
 66             if(vis[i])printf("%0.3f\n",1.0/1.0/(1.0*cnt));
 67             else puts("0.000");
 68         }
 69     }
 70 }
 71 int main(){
 72     scanf("%d%lf%lf",&n,&down,&up);
 73     for(int i=1;i<n;i++){
 74         scanf("%lf",&w[i]);
 75         sw[i]=sw[i-1]+w[i];
 76     }
 77     sw[n]=sw[n-1];
 78     for(int i=1;i<=n;i++){
 79         scanf("%lf",&d[i]);
 80         sd[i]=sd[i-1]+d[i];
 81     }
 82     if(down==up){
 83         work1::Main();
 84         return 0;
 85     }
 86     for(int i=1;i<n;i++)
 87         DIS[i]=(sd[n]-sd[i])*(sd[i]);
 88     double x1=0,x2=0,sum1=0,sum2=0;
 89     x1=d[1];sum1=w[n]*x1;
 90     SUM[1]=d[n]*sum1;
 91     for(int i=n-1;i>=2;i--){
 92         x1+=d[i+1];
 93         sum1+=w[i]*x1;
 94         SUM[1]+=d[i]*sum1;
 95     }
 96     for(int i=3;i<=n;i++){
 97         x2+=d[i];
 98         sum2+=x2*w[i];
 99     }
100     x2+=d[1];sum2+=x2*w[1];
101     for(int i=2;i<=n;i++){
102         SUM[i]=SUM[i-1]-d[i]*sum1+d[i]*sum2;
103         sum1+=d[i]*sw[n];sum1-=sd[n]*w[i];
104         sum2+=sd[n]*w[i];sum2-=d[i+1]*sw[n];
105     }
106     for(int i=1;i<=n;i++){
107         p[i]=point(DIS[i],SUM[i]);
108         p[i].id=i;
109     }
110     swap(p[1],p[n]);
111     sort(p+2,p+n+1,cmp);
112     tot=0;
113     for(int i=1,j=1;i<=n;i=j){
114         p[++tot]=p[i];
115         for(;j<=n&&getf(p[i].x-p[j].x)==0&&getf(p[i].y-p[j].y)==0;j++)
116             V[tot].pb(p[j].id);
117     }
118     q[1]=p[1];top=1;pp[1]=1;
119     for(int i=2;i<=tot;i++){
120         while(top>1&&(p[i]-q[top])*(q[top]-q[top-1])>=0)top--;
121         q[++top]=p[i];
122         pp[top]=i;
123     }
124     tot=top;
125     for(int i=1;i<=tot;i++)p[i]=q[i];
126     while(tot>1&&(p[tot].y>p[tot-1].y||p[tot].x<p[tot-1].x))tot--;
127     l[1]=inf;
128     for(int i=1;i<tot;i++){
129         r[i]=(p[i].y-p[i+1].y)/(p[i+1].x-p[i].x);
130         l[i+1]=r[i];
131     }
132     r[tot]=0;
133     for(int i=1;i<=tot;i++)
134         if(r[i]<up){be=i;break;}
135     for(int i=be;i<=tot;i++){
136         if(l[i]<down)break;
137         double now=(min(up,l[i])-max(down,r[i]))/(up-down)/(1.0*V[pp[i]].size());
138         for(int j=0;j<V[pp[i]].size();j++){
139             Ans[V[pp[i]][j]]=now;
140         }
141     }
142     for(int i=1;i<=n;i++)printf("%0.3f\n",Ans[i]);
143     return 0;
144 }
View Code

T3,挺好的一个脑洞题,不想写了,怎么我越来越懒了呢?

  1 #pragma GCC optimize ("O3")
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <cmath>
  7 #include <vector>
  8 #define N 13333
  9 #define LL long long
 10 #define pb push_back
 11 using namespace std;
 12 int n,m,top,tot,e,pos;
 13 struct data{
 14     int u,v;
 15     data(){}
 16     data(int a,int b){u=a;v=b;}
 17 }d[N];
 18 bool cmpd(const data & a,const data & b){return a.u<b.u;}
 19 struct point{
 20     int x,y,id,be;
 21     point(){x=y=0;}
 22     point(int a,int b){x=a;y=b;}
 23     point operator - (const point & a)const{return point(x-a.x,y-a.y);}
 24     LL operator * (const point & a)const{return 1ll*x*a.y-1ll*y*a.x;}
 25 }p[N],q[N];
 26 LL getdis(const point & a){
 27     return sqrt(1ll*a.x*a.x+1ll*a.y*a.y);
 28 }
 29 bool cmp(const point & a,const point & b){
 30     LL now=(a-p[1])*(b-p[1]);
 31     if(now==0)return getdis(a-p[1])<getdis(b-p[1]);
 32     return now>0;
 33 }
 34 bool check(const point & a,const point & b,const point & c,const point & p){
 35     LL x1=(b-a)*(p-a),x2=(c-b)*(p-b),x3=(a-c)*(p-c);
 36     if(x1==0||x2==0||x3==0)return 0;
 37     if(x1>0){if(x2<0||x3<0)return 0;return 1;}
 38     if(x1<0){if(x2>0||x3>0)return 0;return 1;}
 39 }
 40 void graham(){
 41     tot=n+m;
 42     for(int i=2;i<=tot;i++)if(p[i].x<p[1].x||(p[i].x==p[1].x&&p[i].y<p[1].y))
 43         swap(p[1],p[i]);
 44     sort(p+2,p+tot+1,cmp);
 45     q[1]=p[1];top=1;
 46     for(int i=2;i<=tot;i++){
 47         while(top>1&&(p[i]-q[top])*(q[top]-q[top-1])>0)top--;
 48         q[++top]=p[i];
 49     }
 50     int posl=2,posr=top-1;
 51     for(;posl<=top&&q[posl].be==q[posl-1].be;posl++);posl--;
 52     for(;posr>=1&&q[posr].be==q[posr+1].be;posr--);posr++;
 53     if(posl+1<posr){
 54         int c=q[posl+1].be;
 55         for(int i=posl+1;i<posr;i++)
 56             if(q[i].be!=c){puts("GG!");exit(0);}
 57         for(int i=1;i<=posl;i++)q[top+i]=q[i];
 58         for(int i=1;i<=top;i++)q[i]=q[i+posl];
 59         pos=posr-posl;
 60     }
 61     else if(posl+1==posr){
 62         pos=posr;
 63     }
 64 }
 65 int num;
 66 vector<int> V[N];
 67 void work(const point & a,const point & b,const point & c,int now){
 68     int cnt1=0,cnt2=0;
 69     for(int i=0;i<V[now].size();i++){
 70         if(p[V[now][i]].be==a.be)cnt1++;
 71         else cnt2++;
 72     }
 73     if(!cnt1&&!cnt2)return ;
 74     if(!cnt1){
 75         for(int i=0;i<V[now].size();i++)
 76             if(check(a,b,c,p[V[now][i]])&&p[V[now][i]].be==b.be)d[++e]=data(b.id,p[V[now][i]].id);
 77         return ;
 78     }
 79     if(!cnt2){
 80         for(int i=0;i<V[now].size();i++)
 81             if(check(a,b,c,p[V[now][i]])&&p[V[now][i]].be==a.be)d[++e]=data(a.id,p[V[now][i]].id);
 82         return ;
 83     }
 84     for(int i=0;i<V[now].size();i++)
 85         if(check(a,b,c,p[V[now][i]])&&p[V[now][i]].be==a.be){
 86             d[++e]=data(a.id,p[V[now][i]].id);
 87             int nxt=++num;
 88             for(int j=0;j<V[now].size();j++)
 89                 if(check(b,a,p[V[now][i]],p[V[now][j]]))
 90                     V[nxt].pb(V[now][j]);
 91             work(b,a,p[V[now][i]],nxt);
 92             nxt=++num;
 93             for(int j=0;j<V[now].size();j++)
 94                 if(check(c,a,p[V[now][i]],p[V[now][j]]))
 95                     V[nxt].pb(V[now][j]);
 96             work(c,a,p[V[now][i]],nxt);
 97             nxt=++num;
 98             for(int j=0;j<V[now].size();j++)
 99                 if(check(p[V[now][i]],b,c,p[V[now][j]]))
100                     V[nxt].pb(V[now][j]);
101             work(p[V[now][i]],b,c,nxt);
102             return ;
103         }
104 }
105 int main(){
106     scanf("%d%d",&n,&m);
107     if(!n||!m){
108         for(int i=1;i<max(n,m);i++)printf("%d %d\n",i,m);
109         return 0;
110     }
111     for(int i=1;i<=n;i++){
112         scanf("%d%d",&p[i].x,&p[i].y);
113         p[i].id=i;p[i].be=1;
114     }
115     for(int i=1;i<=m;i++){
116         scanf("%d%d",&p[n+i].x,&p[n+i].y);
117         p[n+i].id=n+i;p[n+i].be=2;
118     }
119     graham();
120     if(q[top].be==q[1].be){
121         for(int i=1;i<=n;i++){
122             if(p[i].be!=q[1].be){
123                 for(int j=1;j<top;j++){
124                     d[++e]=data(q[j].id,q[j+1].id);
125                     int now=++num;
126                     for(int k=1;k<=tot;k++)
127                         if(check(p[i],q[j],q[j+1],p[k]))V[now].pb(k);
128                     work(p[i],q[j],q[j+1],now);
129                 }
130                 int now=++num;
131                 for(int k=1;k<=tot;k++)
132                     if(check(p[i],q[1],q[top],p[k]))V[now].pb(k);
133                 work(p[i],q[1],q[top],now);
134                 break;
135             }
136         }
137         sort(d+1,d+e+1,cmpd);
138         for(int i=1;i<n;i++)printf("%d %d\n",d[i].u,d[i].v);
139         for(int i=n;i<n+m-1;i++)printf("%d %d\n",d[i].u-n,d[i].v-n);
140         return 0;
141     }
142     for(int i=1;i<pos-1;i++){
143         d[++e]=data(q[i].id,q[i+1].id);
144         int now=++num;
145         for(int j=1;j<=tot;j++)
146             if(check(q[pos],q[i],q[i+1],p[j]))V[now].pb(j);
147         work(q[pos],q[i],q[i+1],now);
148     }
149     for(int i=pos;i<top;i++){
150         d[++e]=data(q[i].id,q[i+1].id);
151         int now=++num;
152         for(int j=1;j<=tot;j++)
153             if(check(q[1],q[i],q[i+1],p[j]))V[now].pb(j);
154         work(q[1],q[i],q[i+1],now);
155     }
156     sort(d+1,d+e+1,cmpd);
157     for(int i=1;i<n;i++)printf("%d %d\n",d[i].u,d[i].v);
158     for(int i=n;i<n+m-1;i++)printf("%d %d\n",d[i].u-n,d[i].v-n);
159 }
View Code

加油啊!!!!

5.26

先看T1,要O(nqlog),有60分?然后看T2,一点不会,然后看T3,想了一个ac自动机的玄学做法,写出来小样例都过了,自己造的极限数据跑的很快,然后去想T1,发现很水,写了个线段树,然后拍上了。最后去写了T2的暴力,感觉能上200?80+60+25=165 rank6,T1被卡常了,根本不用线段树,直接开个变量就可以,T2的暴力倒是多拿了不少分,T3完全看错题了,竟然有分,挺好。

这次也暴露出了我的不少问题,T1线段树完全是多余的,但是我想到之后没有深入去思考本质,于是就gg了。然后又是T3的读题问题,原来是有一段时间想错误的题意,这次是完全看错题意,以后读题要细心再细心。

T1,我们发现只需处理相邻元素就好,然后每对相邻元素可能需要动的就是最高的不相同位,然后记录一下每一位就好了。

 1 #pragma GCC optimize ("O3")
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cmath>
 7 #define N 1000500
 8 #define B 35
 9 using namespace std;
10 int n,m,a[N],s[N],hi[N],num1[B],num2[B],bit[B],Ans;
11 
12 int read(){
13     int a=0;char ch=getchar();
14     while(ch<'0'||ch>'9')ch=getchar();
15     while(ch>='0'&&ch<='9'){a=a*10+(ch^48);ch=getchar();}
16     return a;
17 }
18 void work(){
19     Ans=0;
20     for(int i=29;~i;i--){
21         if(num1[i]&&num2[i]){puts("-1");return;}
22         if(num1[i])Ans|=bit[i];
23     }
24     printf("%d\n",Ans);
25 }
26 int main(){
27     bit[0]=1;
28     for(int i=1;i<=29;i++)bit[i]=bit[i-1]<<1;
29     n=read();
30     for(int i=1;i<=n;i++)a[i]=read();
31     memset(hi,-1,sizeof hi);
32     for(int i=1;i<n;i++){
33         s[i]=a[i]^a[i+1];
34         for(int j=29;~j;j--)
35             if(s[i]&bit[j]){hi[i]=j;break;}
36         if(hi[i]!=-1){
37             if(a[i]&bit[hi[i]])num1[hi[i]]++;
38             else num2[hi[i]]++;
39         }
40     }
41     work();
42     m=read();
43     for(int i=1,x,y;i<=m;i++){
44         x=read();y=read();
45         if(x>1){
46             if(hi[x-1]!=-1){
47                 if(a[x-1]&(bit[hi[x-1]]))num1[hi[x-1]]--;
48                 else num2[hi[x-1]]--;
49             }
50             s[x-1]=a[x-1]^y;
51             hi[x-1]=-1;
52             for(int j=29;~j;j--)
53                 if(s[x-1]&bit[j]){hi[x-1]=j;break;}
54             if(hi[x-1]!=-1){
55                 if(a[x-1]&bit[hi[x-1]])num1[hi[x-1]]++;
56                 else num2[hi[x-1]]++;
57             }
58         }
59         if(x<n){
60             if(hi[x]!=-1){
61                 if(a[x]&(bit[hi[x]]))num1[hi[x]]--;
62                 else num2[hi[x]]--;
63             }
64             s[x]=y^a[x+1];
65             hi[x]=-1;
66             for(int j=29;~j;j--)
67                 if(s[x]&bit[j]){hi[x]=j;break;}
68             if(hi[x]!=-1){
69                 if(y&(bit[hi[x]]))num1[hi[x]]++;
70                 else num2[hi[x]]++;
71             }
72         }
73         a[x]=y;
74         work();
75     }
76     return 0;
77 }
View Code

T2,我们先把最短路跑出来,然后只保留有用的边,然后对于一段连续的路线来说,可以用斜率优化,然后随便搞搞就行了。

 1 #pragma GCC optimize ("O3")
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cmath>
 7 #include <queue>
 8 #include <vector>
 9 #include <map>
10 #define inf 0x7fffffff
11 #define N 1000500
12 #define LL long long
13 #define pb push_back
14 using namespace std;
15 int n,m,v[N],t[N],s[N];
16 int dis[N],vis[N];
17 int e=1,head[N];
18 LL f[N];
19 struct edge{
20     int u,v,w,id,next;
21 }ed[N];
22 void add(int u,int v,int w,int id){
23     ed[e].u=u;ed[e].v=v;ed[e].w=w;ed[e].id=id;
24     ed[e].next=head[u];head[u]=e++;
25 }
26 queue<int> q;
27 void spfa(){
28     memset(dis,0x3f,sizeof dis);
29     memset(vis,0,sizeof vis);
30     q.push(1);
31     dis[1]=0;vis[1]=1;
32     while(!q.empty()){
33         int x=q.front();q.pop();vis[x]=0;
34         for(int i=head[x];i;i=ed[i].next){
35             int v=ed[i].v;
36             if(dis[x]+ed[i].w<dis[v]){
37                 dis[v]=dis[x]+ed[i].w;
38                 if(!vis[v]){vis[v]=1;q.push(v);}
39             }
40         }
41     }
42 }
43 LL getf(int u,int v){return -2ll*dis[u]*dis[v]+1ll*dis[u]*dis[u]+f[u];}
44 double getcross(int x,int y){return (double)(1ll*dis[x]*dis[x]+f[x]-1ll*dis[y]*dis[y]-f[y])/1.0/(2ll*dis[x]-2ll*dis[y]);}
45 int in[N],tot;
46 vector <int> qu[N];
47 map <int,int> pp[N];
48 int main(){
49     scanf("%d%d",&n,&m);
50     for(int i=1,x,y,cnt,las;i<=m;i++){
51         scanf("%d",&cnt);
52         scanf("%d",&las);
53         for(int j=1;j<=cnt;j++){
54             scanf("%d%d",&y,&x);
55             add(las,x,y,i);las=x;
56         }
57     }
58     spfa();
59     int le=e;
60     e=1;memset(head,0,sizeof head);
61     for(int i=1;i<le;i++)
62         if(dis[ed[i].u]+ed[i].w==dis[ed[i].v]){
63             add(ed[i].u,ed[i].v,ed[i].w,ed[i].id);
64             in[ed[i].v]++;
65         }
66     memset(f,-0x3f,sizeof f);
67     f[1]=0;q.push(1);
68     while(!q.empty()){
69         int x=q.front();q.pop();
70         for(int i=head[x];i;i=ed[i].next){
71             int v=ed[i].v,p=ed[i].id;
72             if(!pp[x].count(p))pp[x][p]=++tot;
73             int now=pp[x][p];
74             pp[v][p]=now;
75             while(qu[now].size()>1&&getcross(qu[now][qu[now].size()-2],qu[now][qu[now].size()-1])<getcross(x,qu[now][qu[now].size()-2]))
76                 qu[now].pop_back();
77             qu[now].pb(x);
78             while(qu[now].size()>1&&getf(qu[now][qu[now].size()-2],v)>getf(qu[now][qu[now].size()-1],v))
79                 qu[now].pop_back();
80             f[v]=max(f[v],1ll*dis[v]*dis[v]+getf(qu[now][qu[now].size()-1],v));
81             in[v]--;
82             if(!in[v])q.push(v);
83         }
84     }
85     printf("%d %lld\n",dis[n],f[n]);
86     return 0;
87 }
View Code

T3,这题调了我好久啊,按根号分类讨论,小的我们暴力在trie树上走,大的我们线段树优化转移,这里一定要注意前后缀的区别。

  1 #pragma GCC optimize ("O3")
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <cmath>
  7 #include <queue>
  8 #define LL long long
  9 #define ull unsigned int
 10 #define N 300500
 11 #define P 333331
 12 using namespace std;
 13 int ch1[N][2],dep1[N],w1[N],tot1,root1;
 14 int ch2[N][2],dep2[N],w2[N],tot2,root2;
 15 int len,n,m,nn,w[155],ln[155],tot;
 16 char s[N],c[N];
 17 LL f[N];
 18 ull pw[N],h[155][N];
 19 ull geth(int x,int l,int r){return h[x][r]-h[x][l-1]*pw[r-l+1];}
 20 void add(int v,char *c){
 21     int l=strlen(c);
 22     int now=root1;
 23     for(int i=0;i<l;i++){
 24         int t=c[i]-'0';
 25         if(!ch1[now][t]){
 26             ch1[now][t]=++tot1;
 27             dep1[tot1]=dep1[now]+1;
 28         }
 29         now=ch1[now][t];
 30         w1[now]=min(w1[now],v);
 31     }
 32     now=root2;
 33     for(int i=l-1;~i;i--){
 34         int t=c[i]-'0';
 35         if(!ch2[now][t]){
 36             ch2[now][t]=++tot2;
 37             dep2[tot2]=dep2[now]+1;
 38         }
 39         now=ch2[now][t];
 40         w2[now]=min(w2[now],v);
 41     }
 42 }
 43 LL minn[N<<2],lazy[N<<2];
 44 void update(int rt,LL v){
 45     if(lazy[rt]==-1||lazy[rt]>v)lazy[rt]=v;
 46     minn[rt]=min(minn[rt],v);
 47 }
 48 void pushdown(int rt){
 49     if(lazy[rt]!=-1){
 50         update(rt<<1,lazy[rt]);
 51         update(rt<<1|1,lazy[rt]);
 52         lazy[rt]=-1;
 53     }
 54 }
 55 void update(int rt,int l,int r,int x,int y,LL z){
 56     if(x<=l&&r<=y){
 57         update(rt,z);
 58         return ;
 59     }
 60     pushdown(rt);
 61     int mid=(l+r)>>1;
 62     if(x<=mid)update(rt<<1,l,mid,x,y,z);
 63     if(y>mid) update(rt<<1|1,mid+1,r,x,y,z);
 64     minn[rt]=min(minn[rt<<1],minn[rt<<1|1]);
 65 }
 66 LL query(int rt,int l,int r,int x,int y){
 67     if(x<=l&&r<=y)return minn[rt];
 68     pushdown(rt);
 69     int mid=(