AtCoder Regular Contest 102

C Triangular Relationship
如果k是奇数,只有a%k=b%k=c%k=0,才能满足条件

如果k是偶数,除上述以外,还有a%k=b%k=c%k=k/2能满足条件

因为题目考虑(a,b,c)和(c,b,a)这样的是不同对,所以分别计算以上两种可能中a的取值

b,c的取值集合和a一样,答案就是a取值方案的三次方

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
int main()
{
    scanf("%lld%lld",&n,&k);
    if(k&1)
    {
        n/=k;
        printf("%lld\n",n*n*n);
    }
    else
    {
        ll s=n/k;
        n=n/k+(n%k>=k/2);
        printf("%lld\n",n*n*n+s*s*s);
    }
}

D All Your Paths are Different Lengths
考虑找到一个x使得(2^x)-1<=l-1,然后x个点,x-1条路径。

第x-1和第x个点连一条权值为0的路径和一条权值为1的边

第x-2和第x-1个点连一条权值为0的路径和一条权值为2的边

第x-3和第x-2个点连一条权值为0的路径和一条权值为4的边

依次类推。

这样就有2^x条路径,并且每条路径有不同的取值,值域为0~(1<<x)-1

而对于剩下的值l-1-((2^x)-1)种取值,我们先给1一条权值为(1<<x),然后再后面找到一个点

这个点跑到n的值域为0~s,满足(1<<x)+s<=l-1,我们把1的这条边连到这个点上

又剩下l-1-(1<<x)-s条路径,依次类推。

#include<bits/stdc++.h>
using namespace std;
int l,n,m;
struct node
{
    int x,y,z;
    node(int x=0,int y=0,int z=0):x(x),y(y),z(z){}
};
vector<node>e;
int main()
{
    scanf("%d",&l);
    if(l<=30)
    {
        printf("%d %d\n",2,l);
        for(int i=0;i<l;i++)
            printf("%d %d %d\n",1,2,i);
        return 0;
    }
    int n=log2(l)+1;
    int sum=0;
    for(int i=1,j=log2(l)-1;i<n;i++,j--)
        e.push_back(node(i,i+1,0)),e.push_back(node(i,i+1,1<<j)),sum+=1<<j;
    while(sum<l-1)
    {
        int s=l-1-sum;
        int res=0;
        for(int i=n-1,j=0;i>=2;i--,j++)
        {
            res+=1<<j;
            if(res+1>s)
            {
                res-=1<<j;
                e.push_back(node(1,i+1,sum+1));
                sum+=res+1;
                break;
            }
            else if(res+1==s||i==2)
            {
                e.push_back(node(1,i,sum+1));
                sum+=res+1;
                break;
            }
        }
    }
    printf("%d %d\n",n,e.size());
    for(int i=0;i<e.size();i++)
        printf("%d %d %d\n",e[i].x,e[i].y,e[i].z);
}

E Stop. Otherwise…
考虑对于t=2,t=3…t=2k分别计算答案

对于两个筛子,值分别为x,y,满足x+y=t的筛子的对数是可以算出来的

假设共有up对,我们考虑分别计算存在i对不同筛子的方案数(0<=i<=up)

那么当i=0,就是我们要求的答案,考虑枚举i,进行容斥

那么当有了i对,还有n-2*i个筛子的值可以是任意的,但是由于筛子之间没有顺序

所以答案不是k的n-2*i次方,考虑值为1-k的筛子的出现次数

我们在n-2*i个小球加入k-1个小球,从中选出k-1个小球作为隔板,就是总方案数。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4005,mod=998244353;
int k,n,c[N][N];
ll C(int n,int m)
{
    if(m==0||n==m) return 1;
    if(m==1) return n;
    if(c[n][m]) return c[n][m];
    return c[n][m]=(C(n-1,m-1)+C(n-1,m))%mod;
}
ll solve(int x)
{
    ll ans=0;
    int up=0;
    for(int i=1;i<=x/2;i++)
        if(i<=k&&x-i<=k)
        up++;
    for(int j=0,f=1;j<=up&&n-2*j>=0;j++,f*=-1)
        ans=(ans+f*C(up,j)%mod*C(n-2*j+k-1,k-1))%mod;
    return (ans+mod)%mod;
}
int main()
{
    scanf("%d%d",&k,&n);
    for(int i=2;i<=2*k;i++)
        printf("%lld\n",solve(i));
}

F Revenge of BBuBBBlesort!
首先考虑反着做,给定一个长度为n的排列a:1,2…n-1,n

每次可以选择一个i,满足ai-1<ai<ai+1,然后交换ai-1和ai+1,是否存在一种方案使得操作后排列等于p

首先考虑奇偶性,每次选择ai-1,ai,ai+1,只会交换ai-1和ai+1,i-1和i+1的位置的奇偶性相同

所以怎么操作不会改变排列的奇偶性

然后,考虑对ai进行了一次操作,那么接下来就不可以对ai-1和ai+1进行操作了

因为ai-1>ai,ai>ai+1,不满足条件。如果要让ai-1缩小,就要对ai-2进行操作

同理,对ai-2进行操作后,也不能对ai-1进行操作了。(对ai+1的证明类似)

因此可以得出结论对ai进行操作后ai就会固定不动。

设ai-1=A,ai+1=B,当ai-1和ai+1交换位置后,a-1=B,ai+1=A,B只可能永远<=i-1这个位置

并且不会有比B大的值在B的左方,没有比A小的值在A的右方

考虑一个ai!=i的位置,那么一定是ai与其前面的某个元素交换了,或者与其后面某个元素交换了

如果ai与其前面某个元素交换了,那么是将一个比自己小的换到后面了

此时ai后面的元素是的最小值比自己小,其前面的最大值也比自己小

如果ai与其后面某个元素交换,其前面的最大值比自己大,后面的最小值也比自己大

当上述条件互斥,那么肯定是不合法的

在考虑ai=i,ai+1=i+1,那么显然没有对ai进行过操作

即,位置i-1前面的元素不会跨越到位置i+1后面,因此满足i前面的元素都比它小ai小,i+1后面的元素都比ai+1大

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,a[N],pre[N],bk[N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    pre[1]=a[1];
    bk[n]=a[n];
    for(int i=2;i<=n;i++) pre[i]=max(pre[i-1],a[i]);
    for(int i=n-1;i>=1;i--) bk[i]=min(bk[i+1],a[i]);
    bool flag=true;
    for(int i=1;i<=n;i++)
        if((a[i]&1)^(i&1)) flag=false;
    for(int i=2;i<n;i++)
        if(a[i]!=i&&a[i-1]!=i-1&&a[i+1]!=i+1) flag=false;
    for(int i=1;i<n;i++)
        if(a[i]==i&&a[i+1]==i+1&&pre[i]!=i) flag=false;
    for(int i=2;i<n;i++)
        if(a[i]!=i&&pre[i-1]>a[i]&&bk[i+1]<a[i]) flag=false;
    printf(flag?"Yes\n":"No\n");
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值