AtCoder Regular Contest 197 (Div. 2)

A - Union of Grid Paths

为了方便下标从 \(0\) 开始。

考虑判断一个位置 \((x,y)\) 能否被染黑,其实是限制了前 \(x+y\) 步中有恰好 \(x\) 个是 D。

于是对每条斜线考虑,容易计算出前后的 D 个数范围 \([l1,r1],[l2,r2]\),则合法的 \(x\) 范围为 \([\max(l1,n-1-r2),\min(r1,n-1-l2)]\)

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,r,l) for(int i=(r);i>=(l);i--)
#define repll(i,l,r) for(ll i=(l);i<=(r);i++)
#define perll(i,r,l) for(ll i=(r);i>=(l);i--)
#define pb push_back
#define ins insert
#define clr clear
using namespace std;
namespace ax_by_c{
typedef long long ll;
const int N=4e5+5;
int n,m,s1[N],s2[N];
char s[N];
void slv(){
    scanf("%d %d",&n,&m);
    scanf("%s",s+1);
    rep(i,1,n+m-2){
        s1[i]=s1[i-1],s2[i]=s2[i-1];
        if(s[i]=='D')s1[i]++;
        if(s[i]!='R')s2[i]++;
    }
    ll ans=0;
    rep(i,0,n+m-2){
        int L=max(s1[i],n-1-(s2[n+m-2]-s2[i])),R=min(s2[i],n-1-(s1[n+m-2]-s1[i]));
        if(L<=R)ans+=R-L+1;
    }
    printf("%lld\n",ans);
}
void main(){
	int T=1;
	// int csid=0;scanf("%d",&csid);
    scanf("%d",&T);
    while(T--)slv();
}
}
int main(){
	string __name="";
	if(__name!=""){
		freopen((__name+".in").c_str(),"r",stdin);
		freopen((__name+".out").c_str(),"w",stdout);
	}
	ax_by_c::main();
	return 0;
}

B - Greater Than Average

设平均数为 \(x\),不难发现 \(\le x\) 的数都选了。

排序,若枚举 \(x_0=a_i-eps\),则要在 \(a_i,\dots,a_n\) 中选择尽量多的数使得 \(x\le x_0\)。将所有数都减去 \(x_0\) 后相当于要求和 \(\le 0\),因此肯定是选最小的若干个数。

于是选的数必定是前缀,双指针即可。

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,r,l) for(int i=(r);i>=(l);i--)
#define repll(i,l,r) for(ll i=(l);i<=(r);i++)
#define perll(i,r,l) for(ll i=(r);i>=(l);i--)
#define pb push_back
#define ins insert
#define clr clear
using namespace std;
namespace ax_by_c{
typedef long long ll;
const int N=2e5+5;
int n,a[N];
void slv(){
    scanf("%d",&n);
    rep(i,1,n)scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    int ans=0;
    ll s=0;
    for(int i=1,j=0;i<=n;i++){
        s+=a[i];
        while(j<i&&(ll)a[j+1]*i<=s)j++;
        ans=max(ans,i-j);
    }
    printf("%d\n",ans);
}
void main(){
	int T=1;
	// int csid=0;scanf("%d",&csid);
    scanf("%d",&T);
    while(T--)slv();
}
}
int main(){
	string __name="";
	if(__name!=""){
		freopen((__name+".in").c_str(),"r",stdin);
		freopen((__name+".out").c_str(),"w",stdout);
	}
	ax_by_c::main();
	return 0;
}

C - Removal of Multiples

答案肯定有个上界。注意到质数 \(p\) 只能在 \(a_i=p\) 时被删掉,因此第 \(200000\) 个质数肯定可以作为上界。我使用了 \(3e6\)

直接模拟删除过程注意去重,使用数据结构维护即可,时间复杂度 \(O((V+Q)\log V)\)

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,r,l) for(int i=(r);i>=(l);i--)
#define repll(i,l,r) for(ll i=(l);i<=(r);i++)
#define perll(i,r,l) for(ll i=(r);i>=(l);i--)
#define pb push_back
#define ins insert
#define clr clear
using namespace std;
namespace ax_by_c{
typedef long long ll;
const int V=3e6;
const int N=V+5;
struct BIT{
    int lb(int x){
        return x&(-x);
    }
    int tr[N];
    void add(int i,int x){
        for(;i<=V;i+=lb(i))tr[i]+=x;
    }
    int Q(int i){
        int r=0;
        for(;i;i-=lb(i))r+=tr[i];
        return r;
    }
}tr;
int n;
bool vis[N];
void slv(){
    rep(i,1,V)tr.add(i,1);
    scanf("%d",&n);
    rep(_,1,n){
        int x;
        scanf("%d",&x);
        if(x<=V&&!vis[x])for(int j=x;j<=V;j+=x)if(!vis[j])vis[j]=1,tr.add(j,-1);
        scanf("%d",&x);
        int res=0,cnt=0;
        per(j,21,0)if(res+(1<<j)<=V&&cnt+tr.tr[res+(1<<j)]<x)res+=1<<j,cnt+=tr.tr[res];
        printf("%d\n",res+1);
    }
}
void main(){
	int T=1;
	// int csid=0;scanf("%d",&csid);
    // scanf("%d",&T);
    while(T--)slv();
}
}
int main(){
	string __name="";
	if(__name!=""){
		freopen((__name+".in").c_str(),"r",stdin);
		freopen((__name+".out").c_str(),"w",stdout);
	}
	ax_by_c::main();
	return 0;
}

D - Ancestor Relation

考虑有解怎么做,对于任意一颗树,将根和有多个儿子的节点与儿子之间的边断掉可以得到若干链,容易发现一条链上的节点可以任意排列。

不难发现两个点 \(x,y\) 在一条链上等价于 \(a_x=a_y\),容易找出所有链,算排列数即可。

于是问题变成判无解,因为树本质都是相同的所以可以随便构造一个出来。考虑按照 \(\lvert a_i\rvert\) 排序并把 \(1\) 放最后,然后对每个点找到后面第一个包含它的点作为父亲。此时 \(a\) 相同的点就会构成一条链,链顶则会找到其可能的最深祖先,所以是对的。

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,r,l) for(int i=(r);i>=(l);i--)
#define repll(i,l,r) for(ll i=(l);i<=(r);i++)
#define perll(i,r,l) for(ll i=(r);i>=(l);i--)
#define pb push_back
#define ins insert
#define clr clear
using namespace std;
namespace ax_by_c{
typedef long long ll;
const ll mod=998244353;
const int N=405;
int n,id[N],fa[N];
bitset<N>a[N],g[N];
ll fac[N];
bool cmp(int x,int y){
    if(a[x].count()==a[y].count())return x>y;
    return a[x].count()<a[y].count();
}
struct DSU{
    struct node{
        int fa,sz;
    }a[N];
    void Init(int n){
        rep(i,1,n)a[i]={i,1};
    }
    int find(int x){
        if(a[x].fa==x)return x;
        return a[x].fa=find(a[x].fa);
    }
    bool meg(int x,int y){
        x=find(x),y=find(y);
        if(x==y)return 0;
        if(a[x].sz<a[y].sz)swap(x,y);
        a[y].fa=x;
        a[x].sz+=a[y].sz;
        return 1;
    }
}dsu;
void slv(){
    scanf("%d",&n);
    rep(i,1,n)a[i]=0;
    rep(i,1,n)rep(j,1,n){
        int x;
        scanf("%d",&x);
        a[i][j]=x;
    }
    rep(i,1,n)id[i]=i;
    sort(id+1,id+1+n,cmp);
    if(id[n]!=1){
        puts("0");
        return ;
    }
    rep(i,1,n-1){
        fa[id[i]]=0;
        rep(j,i+1,n)if((a[id[i]]&a[id[j]])==a[id[i]]){
            fa[id[i]]=id[j];
            break;
        }
        if(!fa[id[i]]){
            puts("0");
            return ;
        }
    }
    rep(i,1,n)g[i]=0;
    rep(i,1,n){
        int p=i;
        while(p){
            g[i][p]=g[p][i]=1;
            p=fa[p];
        }
    }
    rep(i,1,n)if(g[i]!=a[i]){
        puts("0");
        return ;
    }
    dsu.Init(n);
    rep(x,2,n)rep(y,2,n)if(a[x]==a[y])dsu.meg(x,y);
    fac[0]=1;
    rep(i,1,n)fac[i]=fac[i-1]*i%mod;
    ll ans=1;
    rep(i,1,n)if(dsu.find(i)==i)ans=ans*fac[dsu.a[i].sz]%mod;
    printf("%lld\n",ans);
}
void main(){
	int T=1;
	// int csid=0;scanf("%d",&csid);
    scanf("%d",&T);
    while(T--)slv();
}
}
int main(){
	string __name="";
	if(__name!=""){
		freopen((__name+".in").c_str(),"r",stdin);
		freopen((__name+".out").c_str(),"w",stdout);
	}
	ax_by_c::main();
	return 0;
}

E - Four Square Tiles

官方题解

考察四个格子的左上方位置,如果有两个在一个 \(k\times k\) 方格内就寄了。

因为 \(n,m\le 3k-1\),所以每行每列至多有两个 \(k\times k\) 方格,如果 \(\min(n,m)<2k\) 就寄了。

然后可以注意到 \((k,k),(k,2k),(2k,k),(2k,2k)\) 在四个方格中,设其左上位置坐标分别为 \((x_1,y_1),(x_2,y_2),(x_3,y_3),(x_4,y_4)\)

考虑相邻两个,可得:

  • \(1\le x_1,x_1+k\le x_3,x_3+k-1\le n\)

  • \(1\le x_2,x_2+k\le x_4,x_4+k-1\le n\)

  • \(1\le y_1,y_1+k\le y_3,y_3+k-1\le m\)

  • \(1\le y_2,y_2+k\le y_4,y_4+k-1\le m\)

这些可以用组合数简单计算,如第一个,可得 \(1\le x_1<x_3-k+1\le n-2k+2\),因此答案为 \(\binom{n-2k+2}{2}\)

考虑容斥掉对角不合法的情况,显然不会同时不合法所以只需计算一个然后乘以二,以 \((x_1,y_1),(x_4,y_4)\) 为例:

  • \(1\le x_1,x_1+k\le x_3,x_3+k-1\le n\)

  • \(1\le x_2,x_2+k\le x_4,x_4+k-1\le n\)

  • \(1\le y_1,y_1+k\le y_3,y_3+k-1\le m\)

  • \(1\le y_2,y_2+k\le y_4,y_4+k-1\le m\)

  • \(x_4<x_1+k,y_4<y_1+k\)

即:

  • \(1\le x_2<x_4-k+1<x_1+1<x_3-k+2\le n-2k+3\)

  • \(1\le y_2<y_4-k+1<y_1+1<y_3-k+2\le m-2k+3\)

同样可以用组合数简单计算,如第一个,答案为 \(\binom{n-2k+3}{4}\)

因此答案为 \(\binom{n-2k+2}{2}^2\binom{m-2k+2}{2}^2-2\binom{n-2k+3}{4}\binom{m-2k+3}{4}\)

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,r,l) for(int i=(r);i>=(l);i--)
#define repll(i,l,r) for(ll i=(l);i<=(r);i++)
#define perll(i,r,l) for(ll i=(r);i>=(l);i--)
#define pb push_back
#define ins insert
#define clr clear
using namespace std;
namespace ax_by_c{
typedef long long ll;
const ll mod=998244353;
ll n,m,k;
ll ksm(ll a,ll b,ll p){
    a=a%p;
    ll r=1;
    while(b){
        if(b&1)r=r*a%p;
        a=a*a%p;
        b>>=1;
    }
    return r%p;
}
ll C(ll n,ll m){
    if(n<m||n<0||m<0)return 0;
    ll res=1;
    repll(i,n-m+1,n)res=res*i%mod;
    repll(i,1,m)res=res*ksm(i,mod-2,mod)%mod;
    return res;
}
ll p2(ll x){
    return x*x%mod;
}
void slv(){
    scanf("%lld %lld %lld",&k,&n,&m);
    if(min(n,m)<k*2){
        puts("0");
        return ;
    }
    printf("%lld\n",(p2(C(n-k*2+2,2)*C(m-k*2+2,2)%mod)-C(n-k*2+3,4)*C(m-k*2+3,4)%mod*2%mod+mod)%mod);
}
void main(){
	int T=1;
	// int csid=0;scanf("%d",&csid);
    scanf("%d",&T);
    while(T--)slv();
}
}
int main(){
	string __name="";
	if(__name!=""){
		freopen((__name+".in").c_str(),"r",stdin);
		freopen((__name+".out").c_str(),"w",stdout);
	}
	ax_by_c::main();
	return 0;
}
posted @ 2025-05-05 10:30  ax_by_c  阅读(31)  评论(0)    收藏  举报