codeforces contest 315

http://codeforces.com/contest/315

AB水题就不说了

//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

C 314A Sereja and Contest

题意:定义一种变换。初始给出数组a[],每次对它进行变换,并且把d[i]<m并且i最小的数删掉(删掉之后后面的数往前移)。不能删除就停止。输出所有被删除数的初始下标。

题解:把di这个式子拆开,发现可以分成两部分bi,ci,b[i]可以由b[i-1]得到,c[i]可以O(1)获取。所以对a[]遍历一遍,求出d[i]就行。复杂度O(n)。还有一个注意事项见代码。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define de(x) cout << #x << "=" << x << endl
const int N=200005;
ll a[N],b[N];
int main() {
    int n,k;
    while(~scanf("%d%d",&n,&k)) {
        for(int i=1;i<=n;++i) scanf("%I64d",&a[i]);
        int ans=0;
        b[1]=0ll;
        for(int i=2;i<=n;++i) {
            //因为a[i-1]有可能已经被删掉了,所以式子不能这样化
            //b[i]=b[i-1]+a[i-1]*(ll)(i-2-ans);
            b[i]=b[i-1]+a[i]*(ll)(i-1-ans);
            if(b[i]-(ll)(i-1-ans)*(ll)(n-i+1)*a[i]<k) {
                printf("%d\n",i);
                ++ans;
                b[i]=b[i-1];
            }
        }
    }
    return 0;
}

//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

D 314B Sereja and Periods

题意:定义有循环节的字符串的表示方法[str,n],比如[ab,2]=abab。首先给你两个用这种表示方法表示的字符串w,q,字符串[q.p]可以从w中获得,求最大的p。(ac可以从abc中获得)

题解:暴力方法肯定是扫一遍w串,如果w[i]==q[j],j就往后移。对于题目给出的有循环的字符串,我们可以对暴力方法进行优化。具体见代码。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define de(x) cout << #x << "=" << x << endl
const int N=105;
char s1[N],s2[N];
int cnt[N],nex[N];
//从i出发经过了cnt[i]次结尾
//下一次要从nex[i]处开始
int main() {
    int n,m;
    while(~scanf("%d%d%s%s",&n,&m,s1,s2)) {
        int len1=strlen(s1);
        int len2=strlen(s2);
        memset(cnt,0,sizeof(cnt));
        memset(nex,0,sizeof(nex));
        for(int i=0;i<len2;++i) {
            int x=i;
            for(int j=0;j<len1;++j) {
                if(s1[j]==s2[x]) {
                    ++x;
                    if(x>=len2) {
                        x=0;
                        ++cnt[i];
                    }
                }
            }
            nex[i]=x;
        }
        int ans=0,x=0;
        for(int i=1;i<=n;++i) {
            ans+=cnt[x];
            x=nex[x];
        }
        printf("%d\n",ans/m);
    }
    return 0;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
E  314C  Sereja and Subsequences
题意:找出给定数组中的所有非降子序列,求它们的乘积和。
题解:对于a[i],以它结尾的ans[i]只与之前的以[1~a[i]]结尾的乘积和有关。那么我们就可以用树状数组维护。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define de(x) cout << #x << "=" << x << endl
const int mod=1000000007;
const int N=1000020;
ll c[N],a[N/10],m;
int n;
void add(int k,ll val) {//arr[k]+=val;
    while(k<=m) {
        c[k]=(c[k]+val)%mod;
        k+=k&-k;
    }
}
ll read(int k) {//1~k的区间和
    ll ans=0;
    while(k) {
        ans=(ans+c[k])%mod;
        k-=k&-k;
    }
    return ans;
}
int main() {
    while(~scanf("%d",&n)) {
        m=0;
        for(int i=1;i<=n;++i) {
            scanf("%I64d",&a[i]);
            m=max(m,a[i]);
        }
        memset(c,0,sizeof(c));
        ll ans=0;
        for(int i=1;i<=n;++i) {
            ll t1=read(a[i]);
            ll t2=(t1+1)%mod*a[i]%mod;
            ll t3=t1-read(a[i]-1);//以a[i]结尾的
            add(a[i],t2-t3);
        }
        printf("%I64d\n",read(m));
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值