T1——jsr(3910)
Description:
给你一个初始数字
A
A
,和目标数字.你需要按照以下操作将
A
A
变为.
数字
x
x
的二进制式(可以有前导)下,将
0
0
,的位置任意排列.再令
x+1
x
+
1
.
求最少次数的操作将
A
A
变为.若无解,输出
−1
−
1
.
A,B≤1018
A
,
B
≤
10
18
Solution:
- 初看此题,感觉是道与dp或bfs的题.
- 但模拟小数据及特殊点的数据,发现了一些规律.
- 因为操作中最后必须 +1 + 1 ,那么 A A 就必须先变为,
- 再回溯一下,就是 A A 要变为二进制下的个数与 (B−1) ( B − 1 ) 的二进制下 1 1 的个数相同.
- 那么就想到分类讨论一下.二进制下,A的1的个数与(B-1)的1的个数的大小.
- 再模拟验证一下就不难解出了.
- 注意:builtinpopcount()只能适用于int,而要在long long 下适用,就在函数名后加’ll’.
Code:
#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize("Ofast")
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
x=0;char c;
while((c=getchar())<48);
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
}
ll a,b;
int main(){
// freopen("jsr.in","r",stdin);
// freopen("jsr.out","w",stdout);
int cas;cin>>cas;
while(cas--){
Rd(a),Rd(b);
if(a==b){puts("0");continue;}
else if(!b && a || b==1 && a>1){puts("-1");continue;}
int cnta=__builtin_popcountll(a),cntb=__builtin_popcountll(b-1);
if(cntb>=cnta)printf("%d\n",cntb-cnta+1);
else puts("2");
}
return 0;
}
T2——mianma(3911)
Description:
在的矩形中,每个格子都有颜色
Ai,j
A
i
,
j
,求颜色种类小于等于
2
2
的最大的联通块大小.
Solution:
- 对于颜色种类为 2 2 的联通块.看似无从下手.
- 实则还是比较常规的操作.
- 处理每个颜色的联通块,再建图.
- 这里,可以用并查集先将同一个颜色的联通块并其起来,在考虑不同颜色的.
- 再考虑不同颜色的时候,我们还是枚举当前颜色的联通块连向的其它的颜色的联通块.
- 然后在用并查集合并,再回溯.
- 但这样枚举的复杂度为.显然是不行的.
- 但是呢,我们发现这些边最多只有 n∗m n ∗ m 条.
- 所以我们先将颜色排序,做到当前的颜色连向的其它的联通块的颜色是堆在一起的.
- 那么我们就将联通块的id(基数)计数排序即可.
- 这样,就可以做到 Θ(nmα(nm)) Θ ( n m α ( n m ) )
Code:
#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize("Ofast")
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
//inline char Sc(){
// static const int LEN=100000;
// static char Buf[LEN],*OP=Buf,*ED=Buf;
// if (OP==ED) ED=(OP=Buf)+fread(Buf,1,LEN,stdin);
// return *OP++;
//}
//template<class T>inline void Rd(T &x){
// static char c;
// for (x=0,c=Sc();c<48;c=Sc());
// for (;c>47;c=Sc()) x=(x<<1)+(x<<3)+(c^48);
//}
template<class T>inline void Rd(T &x){
x=0;char c;
while((c=getchar())<48);
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
}
#define N 1002
int p,cas;
int n,m;
int A[N][N];
const int dx[]={-1,0,1,0};
const int dy[]={0,1,0,-1};
bool check(int x,int y){return x<1 || x>n || y<1 || y>m;}
struct p50{
int id1,id2;
int sum;
bool vis[502][502];
void dfs(int x,int y){
if(A[x][y]!=id1 && A[x][y]!=id2 || vis[x][y])return;
++sum;
vis[x][y]=1;
SREP(i,0,4){
int nx=x+dx[i],ny=y+dy[i];
if(check(nx,ny))continue;
dfs(nx,ny);
}
}
void solve(){
while(cas--){
Rd(n),Rd(m);
int mxc=0;
REP(i,1,n) REP(j,1,m) Rd(A[i][j]),chkmax(mxc,A[i][j]);
int ans=0;
REP(i,1,mxc) REP(j,1,mxc){
id1=i,id2=j;
mcl(vis,0);
REP(x,1,n) REP(y,1,m){
if(vis[x][y])continue;
sum=0;
dfs(x,y);
chkmax(ans,sum);
}
}
printf("%d\n",ans);
}
}
}p1;
struct p20{
int id1,id2;
void solve(){
while(cas--){
Rd(n),Rd(m);
REP(i,1,n) REP(j,1,m) Rd(A[i][j]);
int ans=0;
REP(i,1,m){
id1=A[1][i],id2=0;
REP(j,i,m){
if(A[1][j]!=id1 && !id2)id2=A[1][j];
else if(A[1][j]!=id1 && A[1][j]!=id2){chkmax(ans,j-i);break;}
}
}
printf("%d\n",ans);
}
}
}p2;
struct p10{
#define S 502
int Id[S][S],tot;
int sz[S*S],col[S*S];
vector<int>E[S*S];
map<int,bool>mp[S*S];
bool vis[S*S];
int ans;
void dfs1(int x,int y){
Id[x][y]=tot;
++sz[tot];
SREP(i,0,4){
int nx=x+dx[i],ny=y+dy[i];
if(check(nx,ny))continue;
if(A[nx][ny]!=A[x][y] || Id[x][y])continue;
dfs1(nx,ny);
}
}
void dfs2(int x,int col1,int col2,int sum){
chkmax(ans,sum);
SREP(i,0,E[x].size()){
int y=E[x][i];
if(vis[y])continue;
if(col1==col[y]){
vis[y]=1;
dfs2(y,col1,col2,sum+sz[y]);
vis[y]=0;
}
else if(!col2 || col2==col[y]){
vis[y]=1;
dfs2(y,col1,col[y],sum+sz[y]);
vis[y]=0;
}
}
}
void Clear(){
ans=0;
tot=0;
mcl(Id,0);
mcl(sz,0);
REP(i,1,n*m)E[i].clear(),mp[i].clear();
}
void solve(){
while(cas--){
Rd(n),Rd(m);
Clear();
REP(i,1,n) REP(j,1,m) Rd(A[i][j]);
REP(i,1,n) REP(j,1,m) {
if(Id[i][j])continue;
tot++;
col[tot]=A[i][j];
dfs1(i,j);
}
REP(x,1,n) REP(y,1,m) SREP(d,0,4){
int nx=x+dx[d],ny=y+dy[d];
if(check(nx,ny))continue;
int id1=Id[x][y],id2=Id[nx][ny];
if(id1==id2)continue;
if(mp[id1][id2])continue;
mp[id1][id2]=mp[id2][id1]=1;
E[id1].pb(id2);
E[id2].pb(id1);
}
REP(i,1,tot){
vis[i]=1;
dfs2(i,col[i],0,sz[i]);
vis[i]=0;
}
printf("%d\n",ans);
}
}
}p3;
struct p100{
int col[N*N],sz[N*N],fa[N*N],Id[N*N];
int stk[N*N<<2],top;
int qwq,head[N*N];
struct edge{
int from,to,nxt;
}E[N*N<<2];
void addedge(int x,int y){E[qwq]=(edge){x,y,head[col[x]]};head[col[x]]=qwq++;}
int tmp[N*N];
int ans;
int getid(int x,int y){return (x-1)*m+y;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
bool merge(int a,int b){
a=find(a),b=find(b);
if(a==b)return 0;
sz[a]+=sz[b];
fa[b]=a;
chkmax(ans,sz[a]);
return 1;
}
int cnt[N*N];
void Sort(){
mcl(cnt,0);
REP(i,1,n*m) ++cnt[col[Id[i]]&1023];
REP(i,1,1024) cnt[i]+=cnt[i-1];
DREP(i,n*m,0) tmp[cnt[col[Id[i]]&1023]--]=Id[i];
mcl(cnt,0);
REP(i,1,n*m) ++cnt[col[tmp[i]]>>10];
REP(i,1,1024) cnt[i]+=cnt[i-1];
DREP(i,n*m,0) Id[cnt[col[tmp[i]]>>10]--]=tmp[i];
}
void Clear(){
qwq=0;
mcl(head,-1);
REP(i,1,n*m)fa[i]=Id[i]=i,sz[i]=1;
ans=0;
}
void solve(){
while(cas--){
Rd(n),Rd(m);
Clear();
REP(i,1,n){
REP(j,1,m){
Rd(A[i][j]);
col[getid(i,j)]=A[i][j];
REP(k,0,1){
int lx=i-k,ly=j-(k^1);
if(check(lx,ly))continue;
if(A[lx][ly]==A[i][j]) merge(getid(i,j),getid(lx,ly));
}
}
}
Sort();
REP(i,1,n*m) {
int x=(Id[i]-1)/m+1,y=(Id[i]-1)%m+1;
SREP(k,0,4){
int nx=x+dx[k],ny=y+dy[k];
if(check(nx,ny))continue;
if(A[x][y]<A[nx][ny])addedge(find(getid(nx,ny)),find(Id[i]));
}
}
mcp(tmp,sz);
REP(x,1,n*m) for(int i=head[x],j=i;~i;i=j){
int c=col[E[i].to];
while(~j && c==col[E[j].to]){
if(merge(E[j].to,E[j].from)){
stk[++top]=E[j].to;
stk[++top]=E[j].from;
}
j=E[j].nxt;
}
REP(j,1,top)sz[stk[j]]=tmp[stk[j]],fa[stk[j]]=stk[j];
top=0;
}
printf("%d\n",ans);
}
}
}p4;
int main(){
// freopen("mianma.in","r",stdin);
// freopen("mianma.out","w",stdout);
Rd(p),Rd(cas);
if(p<=10)p1.solve();
else if(p>=13 && p<=16)p2.solve();
else if(p<=12)p3.solve();
else p4.solve();
return 0;
}
T3——rust(3912)
Description:
在一个周长为
h
h
的圆上,有个
XZH
X
Z
H
排列在圆上,为了捕捉
XZH
X
Z
H
,
Isrothy
I
s
r
o
t
h
y
有一个长度为
x
x
的捕捉器,那么捕捉器可以捕捉到在起点为到终点为
s+x−1
s
+
x
−
1
的
XZH
X
Z
H
,但圆上每个点做为起点都有一个概率的权值
Ai
A
i
.求捕捉到的
XZH
X
Z
H
的个数的期望.
由于出题人强行加强了难度.只告诉你
[1,m]
[
1
,
m
]
的
Ai
A
i
和
Ci
C
i
.
只能通过
Ai=∑mjAi−j∗Cj
A
i
=
∑
j
m
A
i
−
j
∗
C
j
计算出
[m,h]
[
m
,
h
]
的
Ai
A
i
.
n≤3000,h≤109,m≤100
n
≤
3000
,
h
≤
10
9
,
m
≤
100
Solution:
- 不难分析,本题的难点就是这个 h h 非常大,所以我们无法去直接计算的.
- 但进行模拟几个后,发现这其实是在求常系数齐次线性递推数列的某一项.
- 这不就是矩阵乘法的经典模型了吗…
- 再回忆一下矩阵乘法. P1×∏ki=1P22k P 1 × ∏ i = 1 k P 2 2 k
- P22k P 2 2 k 是可以在 Θ(m3logh) Θ ( m 3 log h ) 的时间复杂度内预处理出来的.
- 再来看 P1 P 1 矩阵,可以发现, P1 P 1 矩阵实际上只有一列是有元素的.
- 于是,一次矩阵乘法的复杂度就优化成了 Θ(m2) Θ ( m 2 ) .
- 总时间复杂度是 Θ(m3logh+nm2logh) Θ ( m 3 log h + n m 2 log h ) .
Code:
#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize("Ofast")
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
x=0;char c;
while((c=getchar())<48);
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
}
#define N 3002
#define M 32002
#define MM 2000002
#define mod 998244353
int n,m,h,x;
int p[N];
int A[MM],C[N];
void Add(int &x,int y){
x+=y;
if(x>=mod)x-=mod;
else if(x<0)x+=mod;
}
int Pow(int a,int b){
int x=1;
while(b){
if(b&1)x=1ll*x*a%mod;
a=1ll*a*a%mod,b>>=1;
}
return x;
}
struct p36{
int cnt[MM];
void solve(){
REP(i,m+1,h) REP(j,1,m) Add(A[i],1ll*A[i-j]*C[j]%mod);
int sum=0;
REP(i,1,h){
A[i+h]=A[i];
Add(sum,A[i]);
}
REP(i,1,n)++cnt[p[i]],++cnt[p[i]+h];
REP(i,1,h+x+1)Add(cnt[i],cnt[i-1]);
int ans=0;
REP(i,1,h)Add(ans,1ll*A[i]*(cnt[i+x-1]-cnt[i-1])%mod);
printf("%d\n",1ll*ans*Pow(sum,mod-2)%mod);
}
}p1;
struct Matrix{
int a[102][102];
Matrix(){mcl(a,0);}
Matrix operator*(const Matrix &B)const{
Matrix res;
REP(i,1,m+1) REP(j,1,m+1) REP(k,1,m+1) Add(res.a[i][j],1ll*a[i][k]*B.a[k][j]%mod);
return res;
}
}Ans,Res[34],P1,P2;
Matrix Mul(Matrix a,Matrix b){
Matrix res;
REP(j,1,m+1) REP(k,1,m+1) Add(res.a[1][j],1ll*a.a[1][k]*b.a[k][j]%mod);
return res;
}
struct p72{
void Init(){
int tmp=0;
REP(i,1,m){
if(i<m)Add(tmp,A[i]);
P1.a[1][i]=A[m-i+1];
}
P1.a[1][m+1]=tmp;
REP(i,1,m)P2.a[i][1]=C[i];
REP(i,2,m)P2.a[i-1][i]=1;
P2.a[1][m+1]=1;
P2.a[m+1][m+1]=1;
Ans=P1;
Res[0]=P2;
REP(i,1,31)Res[i]=Res[i-1]*Res[i-1];
}
void calc(int k){
int cnt=0;
while(k){
if(k&1)Ans=Mul(Ans,Res[cnt]);
cnt++;
k>>=1;
}
}
void solve(){
Init();
sort(p+1,p+1+n);
int ans=0;
REP(i,1,n){
if(p[i]<=m)Add(ans,A[p[i]]);
else {
calc(p[i]-(p[i-1]<m?m:p[i-1]));
Add(ans,Ans.a[1][1]);
}
}
calc(h-(p[n]<m?m:p[n]));
int sum=(Ans.a[1][1]+Ans.a[1][m+1])%mod;
printf("%d\n",1ll*ans*Pow(sum,mod-2)%mod);
}
}p2;
struct p100{
int tmp[M];
void Init(){
REP(i,1,m){
Add(tmp[i]=tmp[i-1],A[i]);
P1.a[1][i]=A[m-i+1];
}
P1.a[1][m+1]=tmp[m-1];
REP(i,1,m)P2.a[i][1]=C[i];
REP(i,2,m)P2.a[i-1][i]=1;
P2.a[1][m+1]=P2.a[m+1][m+1]=1;
Res[0]=P2;
REP(i,1,31)Res[i]=Res[i-1]*Res[i-1];
}
void calc(int k){
int cnt=0;
while(k){
if(k&1)Ans=Mul(Ans,Res[cnt]);
k>>=1;
cnt++;
}
}
int Get(int x){
if(x<=m)return tmp[x];
Ans=P1;
calc(x-m);
return (Ans.a[1][1]+Ans.a[1][m+1])%mod;
}
int Sum(int l,int r){
return (Get(r)-Get(l-1)+mod)%mod;
}
void solve(){
Init();
int ans=0;
REP(i,1,n){
int L=p[i]-x+1,R=p[i];
if(L>=1)Add(ans,Sum(L,R));
else{
Add(ans,Sum(1,R));
Add(ans,Sum(L+h,h));
}
}
Ans=P1;
calc(h-m);
int sum=(Ans.a[1][1]+Ans.a[1][m+1])%mod;
printf("%d\n",1ll*ans*Pow(sum,mod-2)%mod);
}
}p3;
int main(){
// freopen("rust.in","r",stdin);
// freopen("rust.out","w",stdout);
scanf("%d%d%d%d",&n,&h,&x,&m);
REP(i,1,n)scanf("%d",&p[i]);
REP(i,1,m)scanf("%d",&A[i]);
REP(i,1,m)scanf("%d",&C[i]);
if(h<=1e6)p1.solve();
else if(x==1)p2.solve();
else p3.solve();
return 0;
}
Summary:
- 感觉今天 Isrothy I s r o t h y 的题都是 MediumandHard M e d i u m a n d H a r d 的题…以及 T3 T 3 还魔改成 NTT N T T .
- 但基础分都是比较足的,以及好拿的分也有挺多的…
导致大家分数很紧凑 - 但由于自己的无知,用了builtin_popcount,怒少40…
- 还有就是 T2 T 2 的联通块感觉自己还是比较陌生,没有一点这方面的套路.
- 最后 T3 T 3 的矩阵乘法用的还是不够熟练,有一档前缀和的没推出来,以及套路的预处理 Pow P o w 不知道.
- 综上,感觉这套卷子非常有意义,既能找出不足,还能学习一些新知识.但整体卷子的难度偏难.
还是蒟蒻太菜了... - 评价:较良心出题人.