AGC002

以后养成一个好习惯,每天做一套agc。

[AGC002A] Range Product

入门。

int a,b;
int main(){
    scanf("%d%d",&a,&b);
    if(a>b)swap(a,b);
    if(a<=0&&b>=0)puts("Zero");
    else if(a>0||((min(0,b)-a)&1))puts("Positive");
    else puts("Negative");
    return 0;
}

[AGC002B] Box and Ball

普及-。

int n,m,a[100010],cnt[100010];
bool v[100010];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)cnt[i]=1;
    v[1]=true;
    for(int i=1;i<=m;i++){
        int x,y;scanf("%d%d",&x,&y);
        cnt[x]--;cnt[y]++;v[y]|=v[x];
        if(cnt[x]==0)v[x]=false;
    }
    int ans=0;
    for(int i=1;i<=n;i++)ans+=v[i];
    printf("%d\n",ans);
    return 0;
}

[AGC002C] Knot Puzzle

真正普及-。

int n,pos=1,l,a[100010];
int main(){
    scanf("%d%d",&n,&l);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=2;i<=n;i++){
        if(a[i]+a[i-1]>a[pos]+a[pos-1])pos=i;
    }
    if(a[pos]+a[pos-1]>=l){
        puts("Possible");
        for(int i=2;i<pos;i++)printf("%d\n",i-1);
        for(int i=n;i>=pos;i--)printf("%d\n",i-1);
    }
    else puts("Impossible");
    return 0;
}

[AGC002D] Stamp Rally

大概两种写法。

首先看这个最大编号最小直接二分,然后可以写Kruskal重构树,也可以整体二分+可持久化并查集。我写的后者。然后并查集加了个路径压缩调了半天。

struct node{
    int u,v;
}edge[100010];
int n,m,Q,ans[100010],fa[100010],siz[100010];
int find(int x){
    return fa[x]==x?fa[x]:find(fa[x]);
}
struct ques{
    int x,y,z,id;
}q[100010],q1[100010],q2[100010];
pair<int,int> stk[100010];
int top;
void merge(int x,int y){
    x=find(x);y=find(y);
    if(x==y)return;
    if(siz[x]<siz[y])swap(x,y);
    fa[y]=x;siz[x]+=siz[y];
    stk[++top]=make_pair(x,y);
}
void solve(int L,int R,int l,int r){
    if(l==r){
        for(register int i=L;i<=R;i++)ans[q[i].id]=l;
        int x=find(edge[l].u),y=find(edge[l].v);
        if(x==y)return;
        if(siz[x]<siz[y])swap(x,y);
        fa[y]=x;siz[x]+=siz[y];
        return;
    }
    int mid=(l+r)>>1,cnt1=0,cnt2=0;
    for(register int i=l;i<=mid;i++)merge(edge[i].u,edge[i].v);
    for(register int i=L;i<=R;i++){
        int x=find(q[i].x),y=find(q[i].y);
        if(x==y){
            if(siz[x]>=q[i].z)q1[++cnt1]=q[i];
            else q2[++cnt2]=q[i];
        }
        else{
            if(siz[x]+siz[y]>=q[i].z)q1[++cnt1]=q[i];
            else q2[++cnt2]=q[i];
        }
    }
    for(register int i=1;i<=cnt1;i++)q[i+L-1]=q1[i];
    for(register int i=1;i<=cnt2;i++)q[i+cnt1+L-1]=q2[i];
    while(top){
        fa[stk[top].second]=stk[top].second;
        siz[stk[top].first]-=siz[stk[top].second];
        top--;
    }
    solve(L,L+cnt1-1,l,mid);
    solve(L+cnt1,R,mid+1,r);
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(register int i=1;i<=n;i++)fa[i]=i,siz[i]=1;
    for(register int i=1;i<=m;i++)cin>>edge[i].u>>edge[i].v;
    cin>>Q;
    for(register int i=1;i<=Q;i++){
        cin>>q[i].x>>q[i].y>>q[i].z;q[i].id=i;
    }
    solve(1,Q,1,m);
    for(register int i=1;i<=Q;i++)cout<<ans[i]<<'\n';
    return 0;
}

[AGC002E] Candy Piles

很妙妙的题。很想不到的转化。

首先看这个条件很蛋疼,我们考虑转换一下。

\(a\) 从大到小排序,然后整成一个二维坐标系的形式(从下到上)。然后随手造组样例举例子:

4
2 7 4 3

排序后变成7 4 3 2。然后转化成二维坐标系:

00
000
0000
0000000

然后我们就可以很方便地表示两种操作。我们从左下角开始,如果去掉最大就是向上移动一格,全都去掉一个就是向右移动一格。终止条件是边界,显然是必败情况。所以我们可以把这个东西染个色(√为必胜,×为必败):

××
×√×
√×√×
×√×√×××

然后发现这玩意在内部是×交错的。规律就找出来了。具体怎么求可以找到以左下角为中心的最大的正方形,左下角和右上角的状态显然一样。然后看正方形右上角上方和右方有多少个点。如果全是奇数那么先手必胜,反之先手必败。

int n,a[100010];
bool cmp(int a,int b){
    return a>b;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++){
        if(a[i+1]<i+1){
            int j=0;
            while(a[j+i+1]==i)j++;
            if(((a[i]-i)&1)||(j&1))puts("First");
            else puts("Second");
            return 0;
        }
    }
}

[AGC002F] Leftmost Ball

小清新组合数 dp。

首先显然是个 \(n^2\) dp。那么设 \(dp_{i,j}\) 为放了 \(i\) 个白球, \(j\) 种颜色的球的方案数。转移考虑放白球和放颜色球。

然后我们假设有 \(n\times k\) 个空位放球,每次考虑最左边的合法空位能放什么。

  • 放白球:只放在最左边的空位,方案显然 \(dp_{i-1,j}\)
  • 放颜色球:从剩下的 \(n-j+1\) 种颜色里选一个,然后这有颜色的 \(k-1\) 个球里,第一个球的位置是定死在最左边的空位的,然后剩下的可以随便放。剩下 \(n\times k-i-1-(j-1)\times(k-1)\) 个空位,放 \(k-2\) 个球,就是个组合数。
const int mod=1000000007;
int n,k,dp[2010][2010],jc[4000010],inv[4000010];
int qpow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)ans=1ll*ans*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return ans;
}
int C(int n,int m){
    if(n<m)return 0;
    return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
    scanf("%d%d",&n,&k);jc[0]=inv[0]=1;
    if(k==1){
        puts("1");return 0;
    }
    for(int i=1;i<=n*k;i++)jc[i]=1ll*jc[i-1]*i%mod;
    inv[n*k]=qpow(jc[n*k],mod-2);
    for(int i=n*k-1;i>=1;i--)inv[i]=1ll*inv[i+1]*(i+1)%mod;
    for(int i=0;i<=n;i++)dp[i][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            dp[i][j]=(dp[i][j]+dp[i-1][j]+1ll*(n-j+1)*dp[i][j-1]%mod*C(n*k-i-1-(j-1)*(k-1),k-2)%mod)%mod;
        }
    }
    printf("%d\n",dp[n][n]);
    return 0;
}

完了。

posted @ 2022-11-11 19:53  gtm1514  阅读(43)  评论(2编辑  收藏  举报