codeforces round DIV2

P1:Mashmokh and Lights 

N个灯,N个开关,现在按顺序按M个开端,按开关i的时候,大于等于i的并且开着的灯都会被关闭,问N个灯分别是被哪一个开关关掉的。直接模拟了..先关的先标记..

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m;
int a[220],b[220];
int main()
{
//    freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    memset(a,0,sizeof a);
    for (int i=1; i<=n; i++)
    {
        scanf("%d",&b[i]);
        for (int j=b[i]; j<=n; j++)
        if (a[j]==0) a[j]=b[i];
    }
    for (int i=1; i<=n; i++)
    cout<<a[i]<<" ";
    cout<<endl;
    return 0;
}

P2: Mashmokh and Tokens

N天,两个参数a,b。每天一个代币数W,W个代币可以换成(W*A/B)向下取整元钱,问每天在换到最多钱的情况下能省下来多少代币。因为牵扯到向下取整,所以只要每次W*A%B数量的都是多余的,而多出来的这部分再除以B就是能省下来的代币数,所以答案就是(W*A%B)/A.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef __int64 ll;
int a,b,n,p,q;
ll aa,bb,m;
ll w[222222];
int main()
{
//    freopen("in.txt","r",stdin);

    scanf("%d%d%d",&n,&a,&b);
    for (int i=1; i<=n; i++)
    {
        aa=a;
        bb=b;
        scanf("%I64d",&m);
        cout<<(m*aa%bb)/aa<<" ";


    }
    cout<<endl;

    return 0;
}

p3: Mashmokh and Numbers

N个数,取K分,每次可以再N个数组成的数列里取前两个数,分数是这两个数的GCD,求构造一个可行序列。

因为要求数列里的数<=1e9,而K最大为1e8,所以必然可以让序列的前两项得到K-(N-2)/2的分数,然后后面的全部用素数补齐。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef __int64 ll;
const int N=10100000;
int prime[1200000], np;
bool vis[N];
ll a[303000],b[303000];
void get_prime()
{
    np = 0;
    memset(vis, 0, sizeof(vis));
    for(int i = 2; i < N; ++i)
    {
        if (!vis[i])
        {
            prime[np++] = i;
            for(int j = i+i; j < N; j +=i) vis[j] = 1;
        }
    }
}
int cnt=0;
int n,k;
ll p,q,r,c;
bool f[10100000];
const int inf=1000000000;
int main()
{
    get_prime();
//    cout<<np<<endl;

    for (int i=0; i+1<np; i+=2)
    {
        a[cnt]=prime[i];
        b[cnt]=prime[i+1];
        cnt++;
        if (cnt>=300000) break;
    }
    while(~scanf("%d%d",&n,&k))
    {
        if (n==1)
        {
            if (k==0) cout<<1<<endl;
            else cout<<"-1"<<endl;
            continue;
        }
        c=k-(n-2)/2;
        if (c<=0)
        {
            cout<<"-1"<<endl;
            continue;
        }
        cout<<c<<" "<<c*2<<" ";
        memset(f,true,sizeof f);
        if (2*c<N) f[c]=f[c*2]=false;
        int cnt=1;
        int i;
        for (i=3; i<=n; i++)
        {
            while(!f[a[cnt]]) cnt++;
            cout<<a[cnt]<<" ";
            cnt++;
        }

        cout<<endl;
    }
    return 0;

}

p4: Mashmokh and ACM

N个数,其中最大数是K,序列A是好序列当且仅当Ai|Ai+1,问这样的好数列有多少个。

DP[i][j]记录当前位置为i,长度为j的数列有多少种。转移方程dp[i][j]+=sum(dp[k][j-1], i|k ),枚举k的倍数类似一个线性的筛法,所以总复杂度略大于2000*2000.

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef __int64 ll;
int n,m,k;
ll dp[2222][2222];
ll sum[2222];
const int mod=1000000007;
int main()
{

    while(~scanf("%d%d",&n,&m))
    {
        memset(dp,0,sizeof dp);
        memset(sum,0,sizeof sum);
        for (int i=1; i<=n; i++)
        dp[i][1]=1;


            for (int j=2; j<=m; j++)
            for (int i=1; i<=n; i++)
             for (int k=i; k<=n; k+=i)
             {
                dp[i][j]+=dp[k][j-1];
                dp[i][j]%=mod;
             }
         ll ans=0;
         for (int i=1; i<=n; i++)
         {

          ans+=dp[i][m];
          if (ans>mod) ans-=mod;
         }
         cout<<ans<<endl;

    }
    return 0;
}

P5: Mashmokh and Reverse Operation  归并+BIT

2^N个数,每次查询一个p,将数列按2^p分组,每组翻转,并且输出翻转后整个序列的逆序对数。

首先用类似归并排序的方法预处理下,第0层是整个序列,第一层是一半,一半,依次向下。

用inv[i]记录一下当前深度为i时逆序对的数量,sum[i]记录深度为i时左半长度*右半长度,两边有多少种比配情况,eq[i]记录一下左半和右半相等的匹配情况,那么在深度为i的区间翻转的时候,新的inv[i]=sum[i]-eq[i]-inv[i],这样就可以实现单层O(1)查询了。查询的时候,从低向高枚举层数,一边更新inv一边统计答案,总复杂度1e6*log(1e6).

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=1300000;
int n,m,p,q;
int a[maxn];
int b[maxn];
ll inv[maxn];
ll sum[maxn];
ll eq[maxn];
struct BIT
{
    ll dt[maxn];
    void init()
    {
        memset(dt,0,sizeof dt);
    }
    int lowbit(int x)
    {
        return x&-x;
    }
    void modify(int x,ll c=1)
    {
        for (int i=x; i<maxn; i+=lowbit(i))
        {
            dt[i]+=c;
        }
    }
    ll query(int x)
    {
        ll res=0;
        for (int i=x; i>0; i-=lowbit(i))
        {
            res+=dt[i];
        }
        return res;
    }
}bit;
void slove(int l,int r,int d)
{
    if (l==r) return;

    int m=(l+r)>>1;
    slove(l,m,d+1);
    slove(m+1,r,d+1);
    ll len=(ll)(m-l+1)*(ll)(r-m);
    sum[d]+=len;
    for (int i=m+1; i<=r; i++) bit.modify(a[i]);
    for (int i=l; i<=m; i++)
    {
        inv[d]+=bit.query(a[i]-1);
        eq[d]+=bit.query(a[i])-bit.query(a[i]-1);
    }
    for (int i=m+1; i<=r; i++) bit.modify(a[i],-1);
}
int main()
{
//    freopen("in.txt","r",stdin);
    while(~scanf("%d",&n))
    {
        int nn=n;
        n=1<<n;

        for (int i=1; i<=n; i++) scanf("%d",&a[i]);
        memcpy(b,a,sizeof a);
        sort(b+1,b+n+1);
        int size=unique(b+1,b+1+n)-(b+1);
        for (int i=1; i<=n; i++)
        a[i]=lower_bound(b+1,b+1+size,a[i])-(b+1)+1;

        bit.init();
        memset(sum,0,sizeof sum);
        memset(inv,0,sizeof inv);
        memset(eq,0,sizeof eq);
        slove(1,n,0);
        scanf("%d",&m);
        ll ans=0;
        for (int i=0; i<nn; i++)
        ans+=inv[i];
        while(m--)
        {
            int k;
            scanf("%d",&k);
            k=nn-k;
            for (int i=k; i<=nn; i++)
            {
                ans-=inv[i];
                inv[i]=sum[i]-eq[i]-inv[i];
                ans+=inv[i];
            }
            cout<<ans<<endl;
        }

    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值