义乌集训7.13 contest 6题解
2021.7.13 Contest 题解
T1:
Description:
胖教授和瘦教授在下中国象棋。胖教授有 \(n_1\) 个车,瘦教授有 \(n_2\) 个车。车都在整点坐标上。一个车被另一个车攻击需要满足:
- 这两个车来自于不同的教授;
- 它们的 \(x\) 坐标相同或者 \(y\) 坐标相同;
- 在它们之间没有其他车;
请帮助两位教授算算哪些车是被攻击的。
Input:
第一行两个整数 \(n_1,n_2\)。
接下来 \(n_1\) 行,每行两个整数 \((x,y)\) 表示胖教授的车的坐标。
接下来 \(n_2\) 行,每行两个整数 \((x,y)\) 表示瘦教授的车的坐标。
数据保证车的位置两两不同。
Output:
第一行输出一个长度为 \(n_1\) 的字符串,第 \(i\) 位为 \(1\) 表示胖教授的第 \(i\) 个车被攻击了,否则第 \(i\) 位为 \(0\)。
第二行输出一个长度为 \(n_2\) 的字符串,第 \(i\) 位为 \(1\) 表示瘦教授的第 \(i\) 个车被攻击了,否则第 \(i\) 位为 \(0\)。
Sample1 Input:
3 2
0 0
0 1
1 0
0 -1
-1 0
Sample1 Output:
100
11
Hint:
\(1\leq n_1,n_2\leq200000,−10^9≤x,y≤10^9\)
题目分析:
随便乱搞都能过,这里我采用了离散化的方法。当然,\(set\) 也能搞。
代码如下(马蜂很丑,不喜勿喷)——
#include<bits/stdc++.h>
#define N 200005
#define LL long long
using namespace std;
int n,m,S,tot,rk1[N],rk2[N],X1[N],Y1[N],X2[N],Y2[N];bool b[N<<2],vis1[N],vis2[N];vector<int> g;
inline bool cmp1(int x,int y){if(X1[x]^X1[y]) return X1[x]<X1[y];return Y1[x]<Y1[y];}
inline bool cmp2(int x,int y){if(X2[x]^X2[y]) return X2[x]<X2[y];return Y2[x]<Y2[y];}
inline void solve(){
memset(b,0,sizeof(b)),sort(rk1+1,rk1+n+1,cmp1),sort(rk2+1,rk2+m+1,cmp2);int now=1;for(register int i=1;i<=n;i++)
{int X=X1[rk1[i]];while(now<=m&&X2[rk2[now]]<X) b[Y2[rk2[now]]]=1,now++;if(b[Y1[rk1[i]]]) vis1[rk1[i]]=1;b[Y1[rk1[i]]]=0;}
memset(b,0,sizeof(b)),now=1;for(register int i=1;i<=m;i++)
{int X=X2[rk2[i]];while(now<=n&&X1[rk1[now]]<X) b[Y1[rk1[now]]]=1,now++;if(b[Y2[rk2[i]]]) vis2[rk2[i]]=1;b[Y2[rk2[i]]]=0;}
}
inline int read(){int ret=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}while(isdigit(ch)) ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();return ret*f;}
int main(){
// freopen("eat.in","r",stdin);freopen("eat.out","w",stdout);
n=read(),m=read();for(register int i=1;i<=n;i++) rk1[i]=i,X1[i]=read(),Y1[i]=read(),g.push_back(X1[i]),g.push_back(Y1[i]);
for(register int i=1;i<=m;i++) rk2[i]=i,X2[i]=read(),Y2[i]=read(),g.push_back(X2[i]),g.push_back(Y2[i]);sort(g.begin(),g.end()),g.erase(unique(g.begin(),g.end()),g.end());S=g.size();
for(register int i=1;i<=n;i++) X1[i]=lower_bound(g.begin(),g.end(),X1[i])-g.begin()+1,Y1[i]=lower_bound(g.begin(),g.end(),Y1[i])-g.begin()+1;
for(register int i=1;i<=m;i++) X2[i]=lower_bound(g.begin(),g.end(),X2[i])-g.begin()+1,Y2[i]=lower_bound(g.begin(),g.end(),Y2[i])-g.begin()+1;
solve();for(register int i=1;i<=n;i++) X1[i]=S+1-X1[i];for(register int i=1;i<=m;i++) X2[i]=S+1-X2[i];
solve();for(register int i=1;i<=n;i++) swap(X1[i],Y1[i]);for(register int i=1;i<=m;i++) swap(X2[i],Y2[i]);
solve();for(register int i=1;i<=n;i++) X1[i]=S+1-X1[i];for(register int i=1;i<=m;i++) X2[i]=S+1-X2[i];solve();
for(register int i=1;i<=n;i++) if(vis1[i]) putchar('1');else putchar('0');putchar('\n');
for(register int i=1;i<=m;i++) if(vis2[i]) putchar('1');else putchar('0');return 0;
}
T2:
Description:
给定串 \(s\) ,问其中有多少 \(namomo\) 子序列。 定义一个子序列 \(t\) 是 \(namomo\) 子序列,当且仅当
- \(t_3=t_5\);
- \(t_4=t_6\);
- \(t_1,t_2,t_3,t_4\) 两两不同。
Input:
一行一个字符串 \(s\)。
\(s\) 仅包含小写字母 \((a-z)\)、大写字母 \((A-Z)\)、数字 \((0-9)\)。
Output:
输出一行一个整数表示答案——\(namomo\) 子序列的数目。请输出答案 mod \(998244353\)。
Sample1 Input:
wohaha
Sample1 Output:
1
Sample2 Input:
momomo
Sample2 Output:
0
Sample3 Input:
gshfd1jkhaRaadfglkjerVcvuy0gf
Sample3 Output:
73
Sample4 Input:
retiredMiFaFa0v0
Sample4 Output:
33
Hint:
\(6\leq∣s∣\leq 10^6\)
题目分析:
我们把 \(namomo\) 序列分为两段 \(t_1,t_2\) 和 \(t_3,t_4,t_5,t_6\)
显然,如果我们确定了 \(t_3,t_4,t_5,t_6\) 那么合法的 \(t_1,t_2\) 的组数可以用前缀和之类的 trick 直接算出。
我们不妨枚举 \(t_3\) ,我们可以得到合法的 \(t_5\) 的位置,我们再枚举 \(t_4\) ,我们可以得到合法的 \(t_6\) 的位置,于是这道题用 \(O(26n)\) 就能通过。
代码如下(马蜂很丑,不喜勿喷)——
#include<bits/stdc++.h>
#define N 1000005
#define LL long long
using namespace std;
const int p=998244353;
int n,tmp,tt,pre[N][65],a[N],mp[1000],Lst[N],lst[65]/*,nxt[N],fir[65]*/,ans,sum1[65],sum2[65];LL S[N];char s[N];inline int get(int x,int y,int z){return (S[x]-1ll*(x-y-z)*(y+z)-1ll*y*z)%p;}
inline int read(){int ret=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}while(isdigit(ch)) ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();return ret*f;}
int main(){
// freopen("string.in","r",stdin);freopen("string.out","w",stdout);
scanf("%s",s+1);for(register int i='a';i<='z';i++) mp[i]=i-'a';for(register int i='A';i<='Z';i++) mp[i]=i-'A'+26;for(register int i='0';i<='9';i++) mp[i]=i-'0'+52;
n=strlen(s+1);for(register int i=1;i<=n;i++){a[i]=mp[s[i]];for(register int j=0;j^62;j++) pre[i][j]=pre[i-1][j];pre[i][a[i]]++;/*if(!lst[a[i]]) fir[a[i]]=i;*/Lst[i]=lst[a[i]]/*,nxt[lst[a[i]]]=i*/,lst[a[i]]=i;}
for(register int i=1;i<=n;i++) S[i]=S[i-1]+1ll*(i-pre[i][mp[s[i]]]);for(register int x=0;x^62;x++) for(register int j=1,i=a[j];j<=n;j++,i=a[j]) if(i^x){
tt=pre[j-1][x];if(!Lst[j]) sum1[i]=get(j-1,tt,pre[j-1][i]),sum2[i]=1ll*sum1[i]*tt%p;
else ans=((LL)ans+1ll*(pre[n][x]-tt)*(1ll*tt*sum1[i]%p-sum2[i]+p))%p,tmp=get(j-1,tt,pre[j-1][i]),sum1[i]+=tmp,(sum1[i]>=p)&&(sum1[i]-=p),sum2[i]=((LL)sum2[i]+1ll*tmp*tt)%p;
}
cout<<ans<<'\n';return 0;
}
T3:
Description:
给定一棵大小为 \(n\) 的有根树。每个节点有个非负权值,对于每个节点 \(x\),我们找到包含 \(x\) 的节点的平均值最大的连通块,定义 \(f(x)\) 为这个平均值。请求出 \(min({f(i)│i∈{1,2,…,n} })\)。
Input:
输入第一行一个正整数 \(n\)。 接下来一行 \(n\) 个整数 \(a_1 , a_2 ,…, a_n\) ,\(a_i\) 表示第 \(i\) 个点的权值。 接下来一行 \(n-1\) 个整数 \(p_1 , p_2 ,… , p_{n-1} (1\leq p_i\leq i)\),\(p_i\) 表示第 \(i+1\) 个点的父节点编号。
Output:
输出一行一个数表示答案。绝对误差或相对误差在 \({10}^{-6}\) 内即为正确。
Sample1 Input:
5
0 1 0 1 0
1 1 2 2
Sample1 Output:
0.5
Hint:
对于全部数据,\(2 \leq n \leq 10^5,0\leq a_i \leq 10^8.\)
题目分析:
分数规划+换根DP的套路题。考虑二分答案,将每个数的权值减去这个数,然后跑换根DP求出经过每个点的最大连通块,若每个连通块的权值都大于等于 \(0\),则 \(L=mid\);反之,\(R=mid\)。由于数据过水,\(eps\) 调到 \(70\) 都能过!!!当然,正经人 \(eps\) 调到 \(10^{-7}\)即可。
代码如下(马蜂很丑,不喜勿喷)——
#include<bits/stdc++.h>
#define N 100005
#define LL long long
#define inf 100000000
#define DB double
#define eps 70
using namespace std;
int n,tot,fa[N],fir[N],nxt[N],son[N];DB a[N],b[N],f[N],g[N],L=inf,R=0;bool flg;
inline void dfs(int x){f[x]=b[x];for(register int i=fir[x];i;i=nxt[i]) dfs(son[i]),f[x]+=max(f[son[i]],0.0);}
inline void dfs2(int x){if(g[x]<0.0) flg=1;for(register int i=fir[x];i;i=nxt[i]) g[son[i]]=max(0.0,g[x]-max(f[son[i]],0.0))+f[son[i]],dfs2(son[i]);}
inline bool check(DB x){flg=0;for(register int i=1;i<=n;i++) b[i]=a[i]-x;dfs(1),g[1]=f[1],dfs2(1);return flg;} inline void add(int x,int y){son[++tot]=y,nxt[tot]=fir[x],fir[x]=tot;}
inline int read(){int ret=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}while(isdigit(ch)) ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();return ret*f;}
int main(){
n=read();for(register int i=1;i<=n;i++) a[i]=read(),L=min(L,a[i]),R=max(R,a[i]);for(register int i=2,x;i<=n;i++) x=read(),add(x,i);
while(R-L>eps){DB mid=(L+R)/2.0;if(check(mid)) R=mid;else L=mid;}printf("%0.9lf\n",R);return 0;
}
T4:
Description:
给定序列 \(a_1,a_2,…,a_n\) 和 \(m\) 组询问。
对于每组询问,给定区间 \([l,r] (1\le l\le r\le n)\),请问有多少子区间 \([i,j]\) 满足 \(l\le i\le j\le r\) 并且子序列 \(a_i,…,a_j\) 中不同的整数的数目是奇数。
Input:
第一行一个整数 \(n\)。
接下来一行 \(n\) 个整数 \(a_1,a_2,…,a_n\)。
接下来一行一个整数 \(m\)。
接下来 \(m\) 行每行两个整数 \(l,r\)。
Output:
对于每组询问,输出一行一个整数表示答案。
Sample1 Input:
5
1 2 3 2 1
5
1 5
2 4
1 3
2 5
4 4
Sample1 Output:
10
3
4
6
1
Sample2 Input:
5
2 3 5 1 5
5
2 3
1 1
1 3
2 5
2 4
Sample2 Output:
2
1
4
6
4
Sample3 Input:
10
2 8 5 1 10 5 9 9 3 5
10
6 8
1 2
3 5
5 7
1 7
3 9
4 9
1 4
3 7
2 5
Sample3 Output:
4
2
4
4
16
16
12
6
9
6
Hint:
对于 \(20\%\) 的数据,满足 \(n,m\le 100\)。
对于 \(100\%\) 的数据,满足 \(1\le n,m\le 5\times 10^5\),\(1\le a_i\le n\),\(1 \le l \le r \le n\)。
题目分析:
这道题有多种维护的方法,当然都是离线后用线段树搞的(其实在线做也可以
我们不妨让询问按照 \(r\) 从小到大排序,我们只需统计每加入一个 \(i\) 后答案的变化。我们记下每一个 \(i\),\(a_i\) 上一次出现的位置 \(pre_i\),则加入 \(i\) 之后,区间 \([pre_i+1,i]\) 不同整数数目的奇偶性会发生改变,在线段树上打标记即可。
具体实现起来需要维护的标记数目比较多,我写得相对比较繁琐,就不详细展开说了,详情见代码。
代码如下(马蜂很丑,不喜勿喷)——
#include<bits/stdc++.h>
#define N 500005
#define LL long long
using namespace std;
int n,m,bl,L,R,a[N],lst[N],pre[N],nxt[N],T[N<<2],sum1[N<<2],sum2[N<<2],tag1[N<<2],tag2[N<<2];LL res,ans[N],S1[N<<2],S2[N<<2];
inline void swap(int &x,int &y){x^=y,y^=x,x^=y;} struct node{int l,r,id;}p[N];inline bool cmp(const node x,const node y){return x.r<y.r;}
inline void PU(int x){S1[x]=S1[x<<1]+S1[x<<1|1],S2[x]=S2[x<<1]+S2[x<<1|1],sum1[x]=sum1[x<<1]+sum1[x<<1|1],sum2[x]=sum2[x<<1]+sum2[x<<1|1];} inline void PD(int x){
if(!T[x<<1]) tag2[x<<1]+=tag2[x],tag1[x<<1]+=tag1[x];else tag1[x<<1]+=tag2[x],tag2[x<<1]+=tag1[x];if(!T[x<<1|1]) tag1[x<<1|1]+=tag1[x],tag2[x<<1|1]+=tag2[x];else tag1[x<<1|1]+=tag2[x],tag2[x<<1|1]+=tag1[x];
S1[x<<1]+=1ll*sum1[x<<1]*tag1[x]+1ll*sum2[x<<1]*tag2[x],S2[x<<1]+=1ll*sum1[x<<1]*tag2[x]+1ll*sum2[x<<1]*tag1[x],S1[x<<1|1]+=1ll*sum1[x<<1|1]*tag1[x]+1ll*sum2[x<<1|1]*tag2[x],S2[x<<1|1]+=1ll*sum1[x<<1|1]*tag2[x]+1ll*sum2[x<<1|1]*tag1[x];
if(T[x]) T[x<<1]^=T[x],T[x<<1|1]^=T[x],swap(sum1[x<<1],sum2[x<<1]),swap(sum1[x<<1|1],sum2[x<<1|1]);T[x]=tag1[x]=tag2[x]=0;
}
inline void U(int x,int l,int r,int ll,int rr){if(ll>rr) return;if(l>=ll&&r<=rr){swap(sum1[x],sum2[x]),S1[x]+=sum1[x],S2[x]+=sum2[x];if(!T[x]) tag2[x]++;else tag1[x]++;T[x]^=1;return;}PD(x);int mid=l+r>>1;if(mid>=ll) U(x<<1,l,mid,ll,rr);if(mid<rr) U(x<<1|1,mid+1,r,ll,rr);PU(x);}
inline void M(int x,int l,int r,int ll,int rr){if(ll>rr) return;if(l>=ll&&r<=rr){S1[x]+=sum1[x],S2[x]+=sum2[x];if(!T[x]) tag1[x]++;else tag2[x]++;return;}PD(x);int mid=l+r>>1;if(mid>=ll) M(x<<1,l,mid,ll,rr);if(mid<rr) M(x<<1|1,mid+1,r,ll,rr);PU(x);}
inline void B(int x,int l,int r){if(l==r){S1[x]=1,sum1[x]=1;return;}int mid=l+r>>1;B(x<<1,l,mid),B(x<<1|1,mid+1,r);PU(x);}
inline LL Q(int x,int l,int r,int ll,int rr){if(l>=ll&&r<=rr) return S1[x];PD(x);int mid=l+r>>1;LL sum=0;if(mid>=ll) sum=Q(x<<1,l,mid,ll,rr);if(mid<rr) sum+=Q(x<<1|1,mid+1,r,ll,rr);return sum;}
struct FastIO{
static const int S=1048576;
char buf[S],*L,*R;int stk[20],Top;~FastIO(){clear();}
inline char nc(){return L==R&&(R=(L=buf)+fread(buf,1,S,stdin),L==R)?EOF:*L++;}inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
inline void pc(char ch){Top==S&&(clear(),0);buf[Top++]=ch;}inline void endl(){pc('\n');}
FastIO& operator >> (char&ch){while(ch=nc(),ch==' '||ch=='\n');return *this;}
template<typename T>FastIO& operator >> (T&ret){
ret=0;int f=1;char ch=nc();while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=nc();}
while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=nc();}ret*=f;return *this;
}
FastIO& operator >> (char* s){int Len=0;char ch=nc();while(ch!='\n'){*(s+Len)=ch;Len++;ch=nc();}}
template<typename T>FastIO& operator << (T x){
if(x<0){pc('-');x=-x;}do{stk[++stk[0]]=x%10;x/=10;}while(x);
while(stk[0]) pc('0'+stk[stk[0]--]);return *this;
}
FastIO& operator << (char ch){pc(ch);return *this;}
FastIO& operator << (string str){int Len=str.size()-1;for(stk[0]=0;Len>=0;Len--) stk[++stk[0]]=str[Len];while(stk[0]) pc(stk[stk[0]--]);return *this;}
}fin,fout;
int main(){
fin>>n;for(register int i=1;i<=n;i++) fin>>a[i],pre[i]=lst[a[i]],lst[a[i]]=i;fin>>m;for(register int i=1;i<=m;i++) fin>>p[i].l>>p[i].r,p[i].id=i;sort(p+1,p+m+1,cmp);B(1,1,n);int now=1;
for(register int i=1;i<=m;i++){while(now<=p[i].r) M(1,1,n,1,pre[now]),U(1,1,n,pre[now]+1,now-1),now++;ans[p[i].id]=Q(1,1,n,p[i].l,p[i].r);}for(register int i=1;i<=m;i++) fout<<ans[i]<<'\n';return 0;
}