广大附中2019CSP模拟day6

Day6

T1

大意:维护一个长度$10^5$序列,维护以下操作共$5*10^5$次,保证输入的所有数据随机

  1. 修改某个位置的值
  2. 将某个区间内的所有值$val$变为$100000-val$
  3. 给出$a,b,c$,和一个区间,问区间中$a*i+b*val_i+c*i*val_i$的最大值

题解:

  • 对于前两个操作可以用线段树维护区间最大值
  • 对于询问操作,我们考虑当存在一个$j>i且val_j>val_i$,那么$i$就没用了,于是我们查出这个区间$val_i$最大的位置,然后就只用考虑位置比$i$大在地方了,重复这个操作,由于数据随机,很随机,我也不知道为什么复杂度是对的,随机说它是对的就对的
  1 #include<bits/stdc++.h>
  2 #define FOR(i,a,b) for (register ll i=(a);i<=(b);i++)
  3 #define For(i,a,b) for (register ll i=(a);i>=(b);i--)
  4 #define mem(i,j) memset(i,j,sizeof(i))
  5 #define GO(u) for (register ll j=f[u];j!=-1;j=nxt[j])
  6 #define fi first
  7 #define se second
  8 #define pb push_back
  9 #define pii pair<ll,ll>
 10 #define MP make_pair
 11 using namespace std;
 12 typedef long long ll;
 13 const ll N=1e5+5;
 14 ll n,m,x,y[N],a,b,c,tag[N<<2],ans;
 15 pii zh[N<<2],f[N<<2],tmp;
 16 char opt[10];
 17 inline ll read()
 18 {
 19     ll x=0,f=1;
 20     char c=getchar();
 21     while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
 22     while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
 23     return f*x;
 24 }
 25 inline void write(ll x)
 26 {
 27     if (x<0) putchar('-'),x=-x;
 28     if (x>9) write(x/10);
 29     putchar(x%10+'0');
 30     return;
 31 }
 32 inline ll rd()
 33 {
 34     x=(100000005*x+20150609)%998244353;
 35     return x/100;
 36 }
 37 inline ll rd_pos() {return rd()%n+1;}
 38 inline ll rd_val() {return rd()%100001;}
 39 inline void up(ll p)
 40 {
 41     ll ls=p<<1,rs=p<<1|1;
 42     zh[p]=max(zh[ls],zh[rs]);
 43     f[p]=max(f[ls],f[rs]);
 44     return;
 45 }
 46 inline void bd(ll p,ll l,ll r)
 47 {
 48     if (l==r)
 49     {
 50         zh[p]=MP(y[l],l);
 51         f[p]=MP(100000-y[l],l);
 52         return;
 53     }
 54     ll ls=p<<1,rs=p<<1|1,mid=(l+r)>>1;
 55     bd(ls,l,mid);
 56     bd(rs,mid+1,r);
 57     up(p);
 58     return;
 59 }
 60 inline void down(ll p)
 61 {
 62     ll ls=p<<1,rs=p<<1|1;
 63     if (!tag[p]) return;
 64     swap(zh[ls],f[ls]);
 65     swap(zh[rs],f[rs]);
 66     tag[ls]^=1;
 67     tag[rs]^=1;
 68     tag[p]=0;
 69     return;
 70 }
 71 inline void xg(ll p,ll l,ll r,ll L,ll R)
 72 {
 73     if (L<=l&&r<=R)
 74     {
 75         tag[p]^=1;
 76         swap(zh[p],f[p]);
 77         return;
 78     }
 79     ll ls=p<<1,rs=p<<1|1,mid=(l+r)>>1;
 80     down(p);
 81     if (L<=mid) xg(ls,l,mid,L,R);
 82     if (R>mid) xg(rs,mid+1,r,L,R);
 83     up(p);
 84     return;
 85 }
 86 inline void md(ll p,ll l,ll r,ll k,ll v)
 87 {
 88     if (l==r)
 89     {
 90         zh[p]=MP(v,l);
 91         f[p]=MP(100000-v,l);
 92         return;
 93     }
 94     ll ls=p<<1,rs=p<<1|1,mid=(l+r)>>1;
 95     down(p);
 96     if (k<=mid) md(ls,l,mid,k,v);
 97     else md(rs,mid+1,r,k,v);
 98     up(p);
 99     return;
100 }
101 inline pii qr(ll p,ll l,ll r,ll L,ll R)
102 {
103     if (L<=l&&r<=R) return zh[p];
104     ll ls=p<<1,rs=p<<1|1,mid=(l+r)>>1;
105     pii ret=MP(0,0);
106     down(p);
107     if (L<=mid) ret=max(ret,qr(ls,l,mid,L,R));
108     if (R>mid) ret=max(ret,qr(rs,mid+1,r,L,R));
109     up(p);
110     return ret;
111 }
112 inline void solve2()
113 {
114     bd(1,1,n);
115     while (m--)
116     {
117         scanf("%s",opt+1);
118         if (opt[1]=='C') 
119         {
120             int pos=rd_pos();
121             md(1,1,n,pos,rd_val());
122         }
123         else if (opt[1]=='R')
124         {
125             ll l=rd_pos(),r=rd_pos();
126             if (l>r) swap(l,r);
127             xg(1,1,n,l,r);
128         }
129         else
130         {
131             ans=0;
132             a=read(),b=read(),c=read();
133             ll l=rd_pos(),r=rd_pos();
134             if (l>r) swap(l,r);
135             tmp=MP(0,0);
136             while (l<=r)
137             {
138                 tmp=qr(1,1,n,l,r);
139                 l=tmp.se+1;
140                 ans=max(ans,tmp.fi*b+tmp.se*a+tmp.fi*tmp.se*c);
141             }
142             write(ans),putchar('\n');
143         }
144     }
145     return;
146 }
147 int main()
148 {
149     n=read(),m=read(),x=read();
150     FOR(i,1,n) y[i]=rd_val();
151     solve2();
152     return 0;
153 }
View Code

T2

大意:给出一个包含$0,1,2$的大小为$500*500$的矩形,问最多可以取出多少个相邻三个组成的拐角,且1是拐点,2是另外两个位置

题解:

  • 好像这种取出某种特定形状的题目大概都是网络流
  • 对于每个拐角,两个2的位置连边,又考虑到中间的1位置只能被用一次,所以中间再加一个1位置的点并且拆点限流
  • 这个图显然是个二分图,但是哪些2连S,哪些2连T不大清楚,可以黑白直接标号(但是我实现挂了),也可以对行黑白染色,黑色和白色分别连向S和T
  1 #include<bits/stdc++.h>
  2 #define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
  3 #define For(i,a,b) for (register int i=(a);i>=(b);i--)
  4 #define mem(i,j) memset(i,j,sizeof(i))
  5 #define GO(u) for (register int j=f[u];j!=-1;j=nxt[j])
  6 #define fi first
  7 #define se second
  8 #define pb push_back
  9 #define pii pair<int,int>
 10 #define MP make_pair
 11 using namespace std;
 12 typedef long long ll;
 13 const int N=500*500*3+5;
 14 const int M=2e6+5;
 15 const int inf=1e8;
 16 int n,m,a[505][505],num[505][505][3];
 17 int tot=1,f[N],nxt[M],vis[N],dep[N],S,T,pt=0,maxflow=0;
 18 int fx[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
 19 queue <int> q;
 20 struct E
 21 {
 22     int u,v,flow;
 23 }e[M];
 24 inline int read()
 25 {
 26     int x=0,f=1;
 27     char c=getchar();
 28     while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
 29     while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
 30     return f*x;
 31 }
 32 inline void write(int x)
 33 {
 34     if (x<0) putchar('-'),x=-x;
 35     if (x>9) write(x/10);
 36     putchar(x%10+'0');
 37     return;
 38 }
 39 inline void add(int u,int v,int flow)
 40 {
 41     tot++;
 42     nxt[tot]=f[u];
 43     f[u]=tot;
 44     e[tot]=(E){u,v,flow};
 45     return;
 46 }
 47 inline void make_edge(int u,int v,int flow)
 48 {
 49     add(u,v,flow);
 50     add(v,u,0);
 51     return;
 52 }
 53 inline int bfs()
 54 {
 55     while (q.size()) q.pop();
 56     FOR(i,0,T) vis[i]=dep[i]=0;
 57     vis[S]=dep[S]=1;
 58     q.push(S);
 59     while (q.size())
 60     {
 61         int u=q.front();
 62         q.pop();
 63         GO(u)
 64         {
 65             int v=e[j].v;
 66             if (!e[j].flow) continue;
 67             if (dep[v]) continue;
 68             dep[v]=dep[u]+1;
 69             q.push(v);
 70             if (dep[T]) return 1;
 71         }
 72     }
 73     return dep[T];
 74 }
 75 inline int Dinic(int u,int fl)
 76 {
 77     if (u==T||!fl) return fl;
 78     int rest=fl,k;
 79     for (register int j=f[u];j!=-1;j=nxt[j])
 80     {
 81         int v=e[j].v;
 82         if (!e[j].flow) continue;
 83         if (dep[v]!=dep[u]+1) continue;
 84         k=Dinic(v,min(rest,e[j].flow));
 85         if (!k)
 86         {
 87             dep[v]=0;
 88             continue;
 89         }
 90         e[j].flow-=k;
 91         e[j^1].flow+=k;
 92         rest-=k;
 93     }
 94     return fl-rest;
 95 }
 96 int main()
 97 {
 98     mem(f,-1);
 99     n=read(),m=read();
100     FOR(i,1,n) FOR(j,1,m) a[i][j]=read();
101     FOR(i,1,n) FOR(j,1,m) num[i][j][0]=++pt;
102     FOR(i,1,n) FOR(j,1,m) num[i][j][1]=++pt;
103     S=++pt,T=++pt;
104     FOR(i,1,n) FOR(j,1,m)
105     {
106         if (a[i][j]==1) make_edge(num[i][j][0],num[i][j][1],1);
107         else if (a[i][j]==2)
108         {
109             FOR(k,0,3)
110             {
111                 int x=i+fx[k][0],y=j+fx[k][1];
112                 if (x<1||x>n||y<1||y>m) continue;
113                 if (a[x][y]!=1) continue;
114                 if (i&1) make_edge(num[i][j][0],num[x][y][0],1);
115                 else make_edge(num[x][y][1],num[i][j][0],1);
116             }
117             if (i&1) make_edge(S,num[i][j][0],1);
118             else make_edge(num[i][j][0],T,1);
119         }
120     }
121     while (bfs()) 
122     {
123         int tmp;
124         while (tmp=Dinic(S,inf)) maxflow+=tmp;
125     }
126     write(maxflow),putchar('\n');
127     return 0;
128 }
View Code

T3

大意:给出$80$个学生以及他们的得分区间,两端点是整数,每个人的得分等概率地取这个区间中的一个实数,回答一个矩阵,即每个人排每个名次的概率

题解:

  • pb说,显然,要把分数区间离散化,每个人的分数被分成了$O(n)$个区间
  • 我们首先枚举每个人,一个个人处理,再枚举他的一个个得分小区间,逐个处理
  • 设计状态$dp_{i,j,k}$表示处理了这个人和前$i$个人的关系,这前$i$个人中(除了他自己)落在小区间左边的人数为$j$,落在小区间之间的人数为$k$,落在小区间之后的人数为$n-k-j-1$,的概率
  • 转移时算出第$i$个人落在三个部分的概率随便转移即可
  • 如何用$dp$数组求出答案,对于$dp_{i,j,k}$我们显然知道$j$个比我垃圾,$n-j-k-1$个比我强,中间这$k$个人加上我,其实我在这$k$个人中是等概率排名的,于是枚举这个排名即可
  • 时间复杂度$O(n^5)$
 1 #include<bits/stdc++.h>
 2 #define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
 3 #define For(i,a,b) for (register int i=(a);i>=(b);i--)
 4 #define mem(i,j) memset(i,j,sizeof(i))
 5 #define GO(u) for (register int j=f[u];j!=-1;j=nxt[j])
 6 #define fi first
 7 #define se second
 8 #define pb push_back
 9 #define pii pair<int,int>
10 #define MP make_pair
11 using namespace std;
12 typedef long long ll;
13 const int N=201;
14 int n,l[N],r[N],a[N],len=0;
15 double dp[N][N][N],ans[N][N];
16 inline int read()
17 {
18     int x=0,f=1;
19     char c=getchar();
20     while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
21     while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
22     return f*x;
23 }
24 inline void write(int x)
25 {
26     if (x<0) putchar('-'),x=-x;
27     if (x>9) write(x/10);
28     putchar(x%10+'0');
29     return;
30 }
31 inline double query(int gl,int gr,int L,int R)
32 {
33     if (gr<=L||R<=gl) return 0;
34     double ret=(1.0*min(R,gr)-max(L,gl))/(1.0*(R-L));
35     return ret;
36 }
37 int main()
38 {
39     n=read();
40     FOR(i,1,n) l[i]=read(),r[i]=read(),a[++len]=l[i],a[++len]=r[i];
41     sort(a+1,a+len+1);
42     len=unique(a+1,a+len+1)-a-1;
43     FOR(i,1,n) l[i]=lower_bound(a+1,a+len+1,l[i])-a,r[i]=lower_bound(a+1,a+len+1,r[i])-a;
44     FOR(p,1,n)
45     {
46         FOR(q,l[p]+1,r[p])
47         {
48             double sub=1.0*(a[q]-a[q-1])/(1.0*(a[r[p]]-a[l[p]]));
49             dp[0][0][0]=1;
50             FOR(i,1,n)
51             {
52                 if (i==p)
53                 {
54                     For(j,i,0) For(k,i-j,0) dp[i][j][k]=dp[i-1][j][k];
55                     continue;
56                 }
57                 double p1=query(0,a[q-1],a[l[i]],a[r[i]]);
58                 double p2=query(a[q-1],a[q],a[l[i]],a[r[i]]);
59                 double p3=query(a[q],a[len],a[l[i]],a[r[i]]);
60                 For(j,i,0) For(k,i-j,0) dp[i][j][k]=dp[i-1][j][k]*p3+dp[i-1][j-1][k]*p1+dp[i-1][j][k-1]*p2;
61             }
62             FOR(j,0,n) For(k,n-1-j,0) FOR(l,0,k) ans[p][n-l-j]+=sub*dp[n][j][k]/(1.0*(k+1));
63         }
64     }
65     FOR(i,1,n)
66     {
67         FOR(j,1,n) printf("%.7lf ",ans[i][j]);
68         putchar('\n');
69     }
70     return 0;
71 }
View Code

 

posted @ 2019-10-15 13:33  C-S-X  阅读(279)  评论(0编辑  收藏  举报