Codeforces Round #138 (Div. 2)

2 篇文章 0 订阅
1 篇文章 0 订阅

第一次Codeforces.做出三题,但是第二题,有个细节没考虑到。Rating:1500+151=1651,于是下次继续Div2吧。>_<!

 

 

A:

题目给出平行六面体的连接一个顶点的三个面的面积,输出这个12条棱的和。

只要枚举下一条边,求出另外的两条边就行了。

#include<cstdio>
#include<iostream>
#include<cstdlib>

using namespace std;

int a,b,c;

bool work(int a,int b,int c)
{
    int j,k;
    for (int i = 1;i*i<=a;++i)
    if (a % i == 0)
    {
        j = a / i;
        if (b % j == 0)
        {
            k = b / j;
            if (c == i * k )
            {
                cout << (i+j+k)*4 << endl;
                return 1;
            }
        }

    }
    return 0;

}

int main()
{
    cin >> a >> b >> c;
    if (work(a,b,c) || work(a,c,b) || work(b,a,c)
        || work(b,c,a) || work(c,a,b) || work(c,b,a) )
        {
            return 0;
        }
    return 0;
}


B:

给数组a,包含n个元素,人物是找到inclusion segment[l,r].使得,al    al+1 … ar,包含了正好k个不同的数字。Definclusion : if there is no segment [x, y]satisfying the property and less thenm inlength, such that 1 ≤ l ≤ x ≤ y ≤ r ≤ n然后r-l不一定要最小。

直接上代码:

 

#include<iostream>
#include<cstdio>

using namespace std;

int n,k,d,cnt,left = 1;;
int a[200000];
int flag[200000];
int initial = -1;

int main()
{
    cin >> n >> k;
    cnt = 0;
    for (int i = 1;i<=100000;++i) flag[i] == 0;
    for (int i = 0;i<n;++i)
    {
        scanf("%d",&d);
        a[i] = d;
        if (flag[d] == 0)
        {
            ++cnt;

            ++flag[d];
            if (cnt == k)
            {
                int l = 0;
                while (l+1<i && flag[a[l]]>1) { --flag[a[l]];++l; }
                printf("%d %d\n",l+1,i+1);
                return 0;
            }

        }else ++flag[d];
    }
    printf("-1 -1\n");
    return 0;
}

C:

定义括号字符串为包含[] & () 的字符串。然后题目费劲地想表达的是找到一个最大的满足匹配的子串,使得”[”的数目最多,并输出这个子串。

用栈来做,遇到左括号压栈,遇到右括号弹出。然后用个计数器,累加,每当出现不匹配的情况,就清空计数器,很容易顺便求出最大值和这个子串。

但是不能处理这种情况([]([]

为了处理这种情况,我把[]的这个计数器统计到(只有当有右括号匹配(时,[]才会被统计。

实现起来只是添加了一个和栈内元素对应的数组来记录计数。

 

#include<iostream>
#include<cstdio>
#include<string>

using namespace std;

string s;

int stack[200000];
int value[200000];
int n;
int transfer(char c)
{
    if (c == '(') return 2;
    if (c == '[') return 1;
    if (c == ']') return -1;
    if (c == ')') return -2;
}
int top  = 0;
int bj = 0;
int main()
{
    cin >> s;
    n = s.size();
    int now = 0,ans = 0;
    for (int i = 0;i<s.size();++i)
    {
        if (transfer(s[i]) >0 )
        {
            stack[top] = transfer((s[i]));
            value[top] = now;
            now = 0;
            ++top;
        } else{

            if (top == 0 || transfer(s[i]) + stack[top-1] != 0)
            {
                top = 0;
                now = 0;
                continue;
            }
            --top;
                now += value[top];
            if (transfer(s[i]) == -1) ++now;

            if (now > ans )
            {
                ans = now;
                bj = i;
            }


        }
    }
    cout << ans << endl;
    int rs = 0,ls = 0,lc = 0,rc = 0;
    if (ans != 0)
    {
        int tp = bj;
        while (tp>=0)
        {
            if (s[tp] == ']') ++ rs;
            if (s[tp] == '[') ++ ls;
            if (s[tp] == '(') ++ lc;
            if (s[tp] == ')') ++ rc;
            if (ls == ans && rs == ans && lc == rc)
            {
                cout << string(s,tp,bj-tp+1) << endl;
                return 0;
            }
            --tp;

        }
    }
    return 0;
}

D:

得到两个字串ST,考虑一类子串X=sk1sk2…skn.满足k1<k2<…<kn.

判断是否对于所有的I, X=sk1sk2…skn,X=T 并且 Kj=i.

计算出Left[i] i=0..T.size(),表示S中的所有X中能够匹配T[i]的极左。

同理计算出Right[i]表示能够匹配T[i]的极右。然后题目就变成了一些线段能否覆盖所有线段。

可以用类似括号匹配的方法来做

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>


using namespace std;

const int N = 200005;

string S,T;
int occ[256];
int markL[N],markR[N];

int main()
{
    cin >> S >> T;
    int l,r;
    r = 0;
    for (l = 0;l<S.size();++l)
    {
        if (r<T.size() && S[l] == T[r]) markL[l]++, ++r;
    }
    if (r<T.size())
    {
        puts("No");
        return 0;
    }
    r = T.size()-1;
    for ( l = S.size()-1;l>=0;--l)
    {
        if (r>=0 && S[l] == T[r]) markR[l]-- , --r;
    }
//    for (int i = 0;i<S.size();++i) cout << markL[i] << " " << markR[i] << endl;
    for (int i = 0;i<S.size();++i)
    {
        occ[S[i]] += markL[i];

        if (occ[S[i]] == 0)
        {
            puts("No");
            return 0;
        }
          occ[S[i]] += markR[i];

    }
    puts("Yes");
    return 0;

}

 

E:

给出一个数组n元数组a。我们队数组a进行k次操作。操作定义如下。

1、

2、把s赋给a。

输出k次操作后的数组a。

因为(1 ≤ n ≤ 2000,0 ≤ k ≤ 109)所以不能用矩阵乘法(n太大了).

推出公式:

    要推出这个公式也不难,先不要考虑a,然后观察操作后Si的值(这个值有aj的系数组成).


#include<iostream>
#include<cstdio>

using namespace std;

#define LL long long

const LL MOD = 1000000007;
//const LL MOD = 7;

LL myDiv(int x)
{
    LL res = 1;
    LL tmp = x;
    int y = MOD-2;
    while (y>0)
    {
        if (y % 2 == 1)
        {
            res *= tmp;
            res %= MOD;
        }
        y/= 2;
        tmp *= tmp;
        tmp %= MOD;

    }
    return res;
}

LL getC(int n,int k)
{
    LL res = 1;
    for (int i = 1;i<=k;++i)
    {
        res = res * (n-i+1);
        res %=  MOD;
        res = res * myDiv(i);
        res %= MOD;
    }
    return res;
}

int n,k;
LL ar[2005],Ans[2005];
int C[2005];

int main()
{
    cin >> n >> k ;
    for (int i = 0;i<n;++i)
        scanf("%d",&ar[i]);
    if (k==0)
    {
        for (int i = 0;i<n;++i) Ans[i] = ar[i];
    } else {
        for (int i = 0;i<=n;++i)
        {
            C[i] = getC(k-1+i,i);
      //     cout << i << " " << C[i] << endl;
        }

        for (int i = 0;i<n;++i)
        {
            Ans[i] = 0;
            for (int j = 0;j<=i;++j)
            {
                Ans[i] += ar[j] * C[i-j];
//                cout << C[i-j] << endl;
                Ans[i] %= MOD;
            }
        //    printf("\n");
        }
    }
    for (int i = 0;i<n-1;++i)
    {
        printf("%d ",Ans[i]);
    }
    printf("%d\n",Ans[n-1]);
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值