HZOJ 20190818 NOIP模拟24题解

T1 字符串:

裸的卡特兰数题,考拉学长讲过的原题,就是bzoj3907网格那题,而且这题更简单,连高精都不用

结论$C_{n+m}^{n}-C_{n+m}^{n+1}$ 考场上10min切掉

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 const int mod=20100403;
 4 const int N=2000006;
 5 using namespace std;
 6 int inv[N],fac[N];
 7 int qpow(int a,int b){
 8     int ans=1;
 9     while(b){
10         if(b&1) ans=ans*a%mod;
11         b>>=1;
12         a=a*a%mod;
13     }
14     return ans%mod;
15 }
16 int C(int n,int m){
17     return fac[n]%mod*inv[n-m]%mod*inv[m]%mod;
18 }
19 signed main(){
20     int n,m;
21     scanf("%lld%lld",&n,&m);
22     fac[0]=1;
23     for(int i=1;i<=n+m;++i) fac[i]=fac[i-1]*i%mod;
24     inv[m+n]=qpow(fac[m+n],mod-2);
25     for(int i=m+n;i>=1;--i) inv[i-1]=inv[i]*i%mod;
26     //inv[0]=1;
27     //for(int i=1;i<=m+n;++i) cout<<i<<" "<<inv[i]<<endl;
28     int ans=(C(n+m,n)%mod-C(m+n,n+1)%mod+mod)%mod;
29     printf("%lld",ans%mod);
30 }
T1

T2 乌鸦喝水:

貌似是这场考试最难的一题了吧,考场上由于忙着调T3没什么时间想,导致只打了个$O(mn^2)$的思博暴力,只拿了25pts,连$O(nm)$的暴力都没想,结果考试后3min就打出了50pts暴力,有点失误啊QAQ。

看到数据范围我们可以猜想这题正解复杂度应该在$O(nlog_2n)$的级别

首先肯定要枚举n,这就意味着我们要去掉m的枚举,我们考虑单独计算每个水桶的贡献,可以先计算出每个水桶最多能够被喝的次数,然后根据每个点被喝的次数sort一下,这样我们从前往后处理就是按照每个水桶被喝光的顺序扫描,我们记录一个res代表每个水桶的贡献,在计算每个点贡献时首先用那个点能够被喝的最多次数减去当前答案ans在除以当前还剩下的桶数,因为这一个水桶被喝了,所有的水桶水位都要相应下降,就相当与把剩下能够喝的次数,均摊到所有剩下的水桶,但是我们注意到他还可能有剩余,所以我们把余数与原序列在前面并且现在没扫到的桶数比较,如果余数大,则证明这桶水还有机会再被喝一次,否则不会在对答案产生贡献,至于如何找在它前面的数的数量用一个树状数组维护即可,然后这题细节还是比较多,细节还是看代码吧。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e5+10;
 4 int a[N],w[N];
 5 struct node{
 6     int maxn,id;
 7 }wat[N];int n,m,x;
 8 int tr[N];
 9 bool cmp(node a,node b){
10     return (a.maxn==b.maxn)?a.id<b.id:a.maxn<b.maxn;
11 }
12 inline int lowbit(int x){return x&(-x);}
13 void add(int x,int val){
14     for(;x<=n;x+=lowbit(x)) tr[x]+=val;
15 }
16 int query(int x){
17     int ans=0;
18     for(;x;x-=lowbit(x)) ans+=tr[x];
19     return ans;
20 }
21 int main(){
22     scanf("%d%d%d",&n,&m,&x);
23     for(int i=1;i<=n;++i) scanf("%d",&w[i]);
24     for(int i=1;i<=n;++i) scanf("%d",&a[i]);
25     for(int i=1;i<=n;++i){
26         wat[i].maxn=(x-w[i])/a[i]+1;
27         wat[i].id=i;
28         add(i,1);
29     }
30     sort(wat+1,wat+n+1,cmp);
31     int ans=0;
32     int cnt=n;
33     for(int i=1;i<=n;++i){
34         add(wat[i].id,-1);
35         if(wat[i].maxn<=0) continue;
36         cnt=(wat[i].maxn-ans)/(n-i+1);
37         if(cnt>=m){ans+=m;continue;}
38         if(query(wat[i].id)<(wat[i].maxn-ans)%(n-i+1)) cnt++;
39         if(cnt>0) ans+=cnt;
40     }
41     printf("%d",ans);
42 }
T2

T3 所驼门王的宝藏:

挺水的一道题,和NOIP模拟15 T2轰炸行动那题很像,只不过这题建图很难搞,数据范围很大$O(n^2)$暴力建图肯定被卡,然后我就在考场上想了半天怎么建图

扫描二维码关注公众号,回复: 7059096 查看本文章

然而思博出题人根本没卡,真开(f××k)心(you)最后没时间了被迫瞎jb打了个暴力建图,然后又调了一年,才过了样例,然后就没时间想T2了,并且T3喜提10分的好成绩再次对思博出题人母亲表达慰问

很简单,就直接tarjan缩点,在DAG上跑拓扑顺便更新答案即可。

正解建图是把同一行的横天门直接缩点,同一列的纵寰门直接所点,自you门暴力建

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N=100005;
  4 struct node{
  5     int x,y,opt;
  6 }t[N];
  7 int n,r,c;
  8 int du[N];
  9 int dx[10]={-1,-1,-1,0,0,1,1,1},dy[10]={-1,0,1,-1,1,-1,0,1};
 10 int first[5000005],nex[5000005],to[5000005],tot;
 11 vector<int> vx[N*10],vy[N*10];
 12 map<pair<int ,int> ,int> mp;
 13 void add(int a,int b){
 14     to[++tot]=b,nex[tot]=first[a],first[a]=tot;
 15 }
 16 int firstc[5000005],nexc[5000005],toc[5000005],totc;
 17 void add_c(int a,int b){
 18     toc[++totc]=b,nexc[totc]=firstc[a],firstc[a]=totc;
 19 }
 20 void init(){
 21     for(int i=1;i<=n;++i){
 22         if(t[i].opt==1){
 23             for(int j=0;j<(int)vx[t[i].x].size();++j){
 24                 if(i==vx[t[i].x][j]) continue;
 25                 add(i,vx[t[i].x][j]);
 26             }
 27         }
 28         else if(t[i].opt==2){
 29             for(int j=0;j<(int)vy[t[i].y].size();++j){
 30                 if(i==vy[t[i].y][j]) continue;
 31                 add(i,vy[t[i].y][j]);
 32             }
 33         }
 34         else{
 35             for(int j=0;j<8;++j){
 36                 int nx=t[i].x+dx[j],ny=t[i].y+dy[j];
 37                 if(nx<=0||ny<=0||nx>r||ny>c) continue;
 38                 if(!mp[make_pair(nx,ny)]) continue;
 39                 add(i,mp[make_pair(nx,ny)]);
 40             }
 41         }
 42     }
 43 }
 44 int dfn[5000005],low[5000005],ins[5000005],top,sta[5000005],res,big[5000005],num,bl[5000005];
 45 void tarjan(int x){
 46     dfn[x]=low[x]=++num;
 47     ins[x]=1,sta[++top]=x;
 48     for(int i=first[x];i;i=nex[i]){
 49         int y=to[i];
 50         if(!dfn[y]){
 51             tarjan(y);
 52             low[x]=min(low[x],low[y]);
 53         }
 54         else if(ins[y]) low[x]=min(low[x],dfn[y]);
 55     }
 56     if(dfn[x]==low[x]){
 57         int y;
 58         res++;
 59         do{
 60             y=sta[top--];
 61             ins[y]=0;
 62             big[res]++;
 63             bl[y]=res;
 64         }while(x!=y);
 65     }
 66 }
 67 queue<int> q;
 68 int ans[5000005];
 69 void topo(){
 70     for(int i=1;i<=res;++i){
 71         ans[i]=big[i];
 72         if(!du[i]){
 73             q.push(i);
 74         }
 75     }
 76     while(q.size()){
 77         int x=q.front();q.pop();
 78         for(int i=firstc[x];i;i=nexc[i]){
 79             int y=toc[i];
 80             ans[y]=max(ans[y],ans[x]+big[y]);
 81             du[y]--;
 82             if(!du[y]) q.push(y);
 83         }
 84     }
 85 }
 86 signed main(){
 87     scanf("%d%d%d",&n,&r,&c);
 88     for(int i=1;i<=n;++i){
 89         scanf("%d%d%d",&t[i].x,&t[i].y,&t[i].opt);
 90         mp[make_pair(t[i].x,t[i].y)]=i;
 91         vx[t[i].x].push_back(i);
 92         vy[t[i].y].push_back(i);
 93     }
 94     init();
 95     for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
 96     for(int i=1;i<=n;++i){
 97         for(int j=first[i];j;j=nex[j]){
 98             int y=to[j];
 99             if(bl[y]==bl[i]) continue;
100             add_c(bl[i],bl[y]);
101             du[bl[y]]++;
102         }
103     }
104     topo();
105     int ansss=0;
106     for(int i=1;i<=res;++i) ansss=max(ansss,ans[i]);
107     printf("%d",ansss);
108 }
T3

猜你喜欢

转载自www.cnblogs.com/leom10/p/11373865.html