【题目】
原题地址
A.Dice Rolling
只需要输出一种合法方案,且一定有解。显然输出 ⌊ n 2 ⌋ \lfloor \frac n 2 \rfloor ⌊2n⌋即可。
#include<bits/stdc++.h>
using namespace std;
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
#endif
int T=read();
while(T--)
{
int n=read();
printf("%d\n",n/2);
}
return 0;
}
B.Letters Rearranging
不能构造出非回文串当且仅当所有字符一样,否则将字符排序输出即可。
#include<bits/stdc++.h>
using namespace std;
int n,cnt[30];
char s[10000];
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
#endif
int T=read();
while(T--)
{
scanf("%s",s);n=strlen(s);int flag=0;
memset(cnt,0,sizeof(cnt));
for(int i=0;i<n;++i)
{
int c=s[i]-'a';
if(!cnt[c]) ++flag;
++cnt[c];
}
if(flag==1) puts("-1");
else
{
sort(s,s+n);printf("%s\n",s);
}
}
return 0;
}
C.Mishka and the Last Exam
只需要贪心构造 a a a数组即可,具体来说我们使前半部分的 a i a_i ai尽量小,且判断对应后半部分的 a a a是否满足单调性即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
ll n,a[N],b[N];
ll read()
{
ll ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=(ll)ret*10+(c^48),c=getchar();
return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
#endif
n=read()/2;
for(int i=1;i<=n;++i) b[i]=read();
a[n*2+1]=(ll)1e18;
for(int i=1;i<=n;++i)
{
ll t=b[i]-a[i-1];
if(t>a[2*n-i+2]) t=a[2*n-i+2];
a[2*n-i+1]=t;a[i]=b[i]-t;
}
for(int i=1;i<=2*n;++i) printf("%lld ",a[i]);
return 0;
}
D.Beautiful Graph
两端点和为奇数,则奇偶性不同。对整幅图黑白染色后将每一块方案乘起来即可。一块的方案计算显然。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+10,mod=998244353;
int n,m,tot,flag,cnt,ans;
int head[N],col[N],ct[N][2];
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
struct Tway{int v,nex;}e[N<<1];
void add(int u,int v)
{
e[++tot]=(Tway){v,head[u]};head[u]=tot;
e[++tot]=(Tway){u,head[v]};head[v]=tot;
}
void clear()
{
tot=0;flag=1;cnt=0;ans=0;
for(int i=0;i<=n+1;++i)
head[i]=ct[i][0]=ct[i][1]=0,col[i]=-1;
}
void dfs(int bl,int x,int fa,int dp)
{
col[x]=dp;++ct[bl][dp];
if(!flag) return;
for(int i=head[x];i;i=e[i].nex)
{
int v=e[i].v;
if(v==fa) continue;
if(~col[v])
{
if(col[v]==col[x]){flag=0;return;}
continue;
}
dfs(bl,v,x,dp^1);
}
}
ll qpow(int x,int y)
{
ll res=1;
for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) res=(ll)res*x%mod;
return res%mod;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("D.in","r",stdin);
freopen("D.out","w",stdout);
#endif
int T=read();
while(T--)
{
n=read();m=read();clear();
for(int i=1;i<=m;++i) add(read(),read());
for(int i=1;i<=n;++i)
{
if(!~col[i]) ++cnt,dfs(cnt,i,0,0);
}
if(!flag){puts("0");continue;}
ll ans=1;
for(int i=1;i<=cnt;++i)
{
///printf("%d %d\n",ct[i][0],ct[i][1]);
ll res=0;
(res+=(ll)qpow(2,ct[i][0])+qpow(2,ct[i][1]))%=mod;
ans=ans*res%mod;
}
ans%=mod;cout<<ans<<endl;
}
return 0;
}
E.Intersection of Permutations
由于两个数组都是一个排列,我们将两个数组进行映射后使得问题可以转化为二维数点问题。具体来说,由于只有 b b b数组会变动,我们记录 a a a中每个数出现的位置,令 p o s [ a [ i ] ] = i pos[a[i]]=i pos[a[i]]=i,那么 ( i , p o s [ b [ i ] ] ) (i,pos[b[i]]) (i,pos[b[i]])即为二维平面上一个点,查询相当于询问 横 坐 标 [ l 2 , r 2 ] 横坐标[l_2,r_2] 横坐标[l2,r2],纵坐标 [ l 1 , r 1 ] [l_1,r_1] [l1,r1]的矩阵中有多少个点。具体意义显然,我们可以用树套树来解决这个问题。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m;
int a[N],b[N],pos[N],rt[N];
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
struct Segment
{
int sz,w[N<<7],ls[N<<7],rs[N<<7];
queue<int>q;
void update(int &x,int l,int r,int p,int v)
{
if(!x){if(!q.empty()) x=q.front(),q.pop(); else x=++sz;} w[x]+=v;
if(l==r) return;
int mid=(l+r)>>1;
if(p<=mid) update(ls[x],l,mid,p,v);
else update(rs[x],mid+1,r,p,v);
if(!w[x]) q.push(x),x=0;
}
int query(int x,int l,int r,int L,int R)
{
if(!x) return 0;
if(L<=l && r<=R) return w[x];
int mid=(l+r)>>1,res=0;
if(L<=mid) res+=query(ls[x],l,mid,L,R);
if(R>mid) res+=query(rs[x],mid+1,r,L,R);
return res;
}
}t;
struct BIT
{
#define lowbit(x) (x&(-x))
void update(int x,int p,int v){for(;x<N;x+=lowbit(x))t.update(rt[x],1,n,p,v);}
int query(int x,int l,int r)
{
int res=0;
for(;x;x-=lowbit(x))res+=t.query(rt[x],1,n,l,r);
return res;
}
}bit;
int main()
{
#ifndef ONLINE_JUDGE
freopen("E.in","r",stdin);
freopen("E.out","w",stdout);
#endif
n=read();m=read();
for(int i=1;i<=n;++i) a[i]=read(),pos[a[i]]=i;
for(int i=1;i<=n;++i) b[i]=read();
for(int i=1;i<=n;++i) bit.update(i,pos[b[i]],1);
while(m--)
{
int opt=read();
if(opt&1)
{
int l1=read(),r1=read(),l2=read(),r2=read();
printf("%d\n",bit.query(r2,l1,r1)-bit.query(l2-1,l1,r1));
}
else
{
int x=read(),y=read();
bit.update(x,pos[b[x]],-1);bit.update(y,pos[b[y]],-1);
bit.update(x,pos[b[y]],1);bit.update(y,pos[b[x]],1);
swap(b[x],b[y]);
}
}
return 0;
}
F.Vasya and Array
F:考虑这样一个状态: f i , j f_{i,j} fi,j表示前 i i i个数,已经有 j j j段连续数字的方案数。我们考虑对于每个状态从哪些状态贡献过来,显然我们可以知道从第 i i i个位置往前是否能将连续的一段全部换成某个数字,因此我们只需要用一个前缀和来维护这个 DP \text{DP} DP即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353,N=1e5+10,M=105;
int n,K,m,ans;
int a[N],s[N][M],f[N][M],g[N][M];
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("F.in","r",stdin);
freopen("F.out","w",stdout);
#endif
n=read();K=read();m=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=K;++i) s[1][i]=1;
for(int i=2;i<=n+1;++i) for(int j=1;j<=K;++j)
if(!~a[i-1] || a[i-1]==j) s[i][j]=s[i-1][j]; else s[i][j]=i;
f[1][0]=g[1][0]=1;
for(int i=2;i<=n+1;++i)
{
for(int j=1;j<=K;++j)
{
int las=max(s[i][j]-1,i-m);
f[i][j]=((ll)(g[i-1][0]-g[las][0]-(g[i-1][j]-g[las][j]))%mod+mod)%mod;
g[i][j]=(g[i-1][j]+f[i][j])%mod;
g[i][0]=(g[i][0]+f[i][j])%mod;
}
g[i][0]=(g[i-1][0]+g[i][0])%mod;
}
for(int i=1;i<=K;++i) (ans+=f[n+1][i])%=mod;
printf("%d\n",ans);
return 0;
}
G.Multidimensional Queries
考虑曼哈顿距离的计算方式,则两点之间大小坐标大小关系在去掉绝对值之后有 2 k 2^k 2k种方式,我们枚举这个关系,用线段树维护最大值即可。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,k,K,Q,a[N][6];
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
struct Segment
{
#define ls (x<<1)
#define rs (x<<1|1)
int w[N<<2][32];
void update(int x,int l,int r,int p)
{
if(l==r)
{
for(int i=0;i<1<<k-1;++i)
{
int t=0;
for(int j=0;j<k;++j) t+=a[p][j]*((i&(1<<j))?-1:1);
w[x][i]=t;w[x][K^i]=-t;
}
return;
}
int mid=(l+r)>>1;
if(p<=mid) update(ls,l,mid,p);
else update(rs,mid+1,r,p);
for(int i=0;i<=K;++i) w[x][i]=max(w[ls][i],w[rs][i]);
}
int query(int x,int l,int r,int L,int R,int mask)
{
if(L<=l && r<=R) return w[x][mask];
int mid=(l+r)>>1,res=-1e9;
if(L<=mid) res=max(res,query(ls,l,mid,L,R,mask));
if(R>mid) res=max(res,query(rs,mid+1,r,L,R,mask));
return res;
}
}tr;
int main()
{
#ifndef ONLINE_JUDGE
freopen("G.in","r",stdin);
freopen("G.out","w",stdout);
#endif
n=read();k=read();K=(1<<k)-1;
for(int i=1;i<=n;++i)
{
for(int j=0;j<k;++j) a[i][j]=read();
tr.update(1,1,n,i);
}
Q=read();
while(Q--)
{
int op=read();
if(op&1)
{
int x=read();
for(int i=0;i<k;++i) a[x][i]=read();
tr.update(1,1,n,x);
}
else
{
int l=read(),r=read(),ans=0;
for(int i=0;i<1<<k-1;++i) ans=max(ans,tr.query(1,1,n,l,r,i)+tr.query(1,1,n,l,r,K^i));
printf("%d\n",ans);
}
}
return 0;
}
【总结】
巨蒻无比。