23号~26号的3场cf

23号~26号的10场cf

 第一场:#272 div1

A题:

推下公式然后统计,注意a/b=c,a=c*b+(a%b),比如7/3=2,7=2*3+7%3。

没什么好讲的,A题就是个水题。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a,b) for(int i=a;i>=b;i--)

using namespace std;

const int maxn=1000100;
const int INF=(1<<29);
typedef long long ll;
const ll MOD=1000000007;

ll a,b;

int main()
{
    cin>>a>>b;
    ll ans=0;
    for(int k=1;k<=a;k++){
        ll tmp=(((k*b+1)%MOD)*(((b-1)*b/2)%MOD))%MOD;
        ans=(ans%MOD+tmp%MOD)%MOD;
    }
    cout<<ans<<endl;
    return 0;
}
View Code

B题:

找规律。。但是前提得知道,gcd(a,b)=c ----》 gcd(a/c,b/c)=1。

四个数的gcd为k可以让这些数除以k,这样变成k=1的情况,问题转化成找四个互质的数。K>1的时候让结果乘以K就行了。

然后就是找规律了。。。首先不能出现两个偶数,然后发现偶数出现在第二个比较好。。

1 2 3 5

7 8 9 11

13 14 15 17

19 20 21 23

.......

然后规律就很明显了。。

(6*i-5),(6*i-4),(6*i-3),(6*i-1)

首先还是要想到转换为互质简化问题,接着从前几项开始找规律,稍稍观察就能找到了。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a,b) for(int i=a;i>=b;i--)

using namespace std;

const int maxn=1000100;
const int INF=(1<<29);

int n,k;

int main()
{
    while(cin>>n>>k){
        cout<<(6*n-1)*k<<endl;
        for(int i=1;i<=n;i++){
            printf("%d %d %d %d\n",(6*i-5)*k,(6*i-4)*k,(6*i-3)*k,(6*i-1)*k);
        }
    }
    return 0;
}
View Code

C题是dp题,也涉及到字符串,必须补啊。。明天早上起来再补,补完C题后直接开第二场。

 C题:

感觉和上次dp专题赛的数字那题有些类似,都是前i个找j个的形式,然后进行转移,前一状态是i-1,但不一定j-1,可以是j-k。

当然dp的前提还是范围比较小。

这个可以单独写个题解:http://www.cnblogs.com/--560/p/4754253.html

第一场,爆零了。

 

 第二场:#274 div1

A题:水题,贪心,排个序就行了。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int INF=(1<<29);
const int maxn=1000100;

struct Node
{
    ll a,b;
    friend bool operator<(Node A,Node B)
    {
        if(A.a<B.a) return 1;
        if(A.a==B.a) return A.b<B.b;
        return 0;
    }
};
int n;
Node p[maxn];

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>n){
        for(int i=1;i<=n;i++){
            scanf("%I64d%I64d",&p[i].a,&p[i].b);
        }
        sort(p+1,p+n+1);
        ll tmp=1;
        for(int i=1;i<=n;i++){
            if(p[i].b>=tmp) tmp=p[i].b;
            else tmp=p[i].a;
        }
        cout<<tmp<<endl;
    }
    return 0;
}
View Code

B题:水题。用几个map或set随便弄一下就行了。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int INF=(1<<29);
const int maxn=1000100;

ll n,l,x,y;
ll a[maxn];
map<ll,int> X,Y,A;

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>n>>l>>x>>y){
        X.clear(),Y.clear(),A.clear();
        for(int i=1;i<=n;i++) scanf("%I64d",&a[i]),A[a[i]]++;
        bool flagX=0,flagY=0;
        set<ll> sX,sY;
        for(int i=1;i<=n;i++){
            if(A[a[i]+x]||A[a[i]-x]) flagX=1;
            if(A[a[i]+y]||A[a[i]-y]) flagY=1;
        }
        if(flagX&&flagY) puts("0");
        else{
            for(int i=1;i<=n;i++){
                if(a[i]+x<=l) sX.insert(a[i]+x);
                if(a[i]-x>=0) sX.insert(a[i]-x);
                if(a[i]+y<=l) sY.insert(a[i]+y);
                if(a[i]-y>=0) sY.insert(a[i]-y);
            }
            if(flagY){
                cout<<1<<endl;
                cout<<*(sX.begin())<<endl;
            }
            else if(flagX){
                cout<<1<<endl;
                cout<<*(sY.begin())<<endl;
            }
            else{
                bool tag=0;
                int ans;
                for(set<ll>::iterator it=sX.begin();it!=sX.end();it++){
                    if(sY.find(*it)!=sY.end()){
                        tag=1;ans=*it;
                        break;
                    }
                }
                if(tag){
                    cout<<1<<endl;
                    cout<<ans<<endl;
                }
                else{
                    cout<<2<<endl;
                    cout<<*(sX.begin())<<" "<<*(sY.begin())<<endl;
                }
            }
        }
    }
    return 0;
}
View Code

C题:

比赛的最后时刻想到了dp,不过没有写下去,其实就是dp!

关键还是找转态转移。

dp+前缀和优化。

这个可以单独写个题解:

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int INF=(1<<29);
const int maxn=5010;

const ll p=1000000007;
ll n,a,b,k;
ll dp[maxn][maxn];
ll sum[maxn];

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>n>>a>>b>>k){
        MS0(dp);
        for(int i=1;i<=n;i++) dp[1][i]=(abs(a-i)<abs(a-b))&&(i!=a);
        sum[0]=0;
        for(int i=1;i<=n;i++) sum[i]=(sum[i-1]+dp[1][i])%p;
        for(int i=2;i<=k;i++){
            for(int j=1;j<=n;j++){
                if(j<b){
                    dp[i][j]=(dp[i][j]+(sum[(b+j-1)/2]-sum[0]-(sum[j]-sum[j-1])+3*p)%p)%p;
                }
                else if(j>b){
                    dp[i][j]=(dp[i][j]+(sum[n]-sum[(b+j)/2]-(sum[j]-sum[j-1])+3*p)%p)%p;
                }
            }
            for(int j=1;j<=n;j++){
                sum[j]=(sum[j-1]+dp[i][j]%p)%p;
            }
        }
        ll ans=0;
        for(int i=1;i<=n;i++){
            ans=(ans%p+dp[k][i]%p)%p;
        }
        cout<<ans<<endl;
    }
    return 0;
}
View Code

 这场轻松过了AB,要是打那次的div2,过CD上紫?

 下一场?能过dp?
 
 
第三场:#275 div1
A题:水题,20min过。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);

ll n,k;

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>n>>k){
        int a=1;
        for(int i=1;i<=n-k;i++){
            printf("%d ",a++);
        }
        int c=n,d=a;
        for(int i=1;i<=k;i++){
            if(i&1) printf("%d ",c--);
            else printf("%d ",d++);
        }
        puts("");
    }
    return 0;
}
View Code

B题:线段树。居然没有看出是线段树。。主要是位运算的问题,位运算和一般的增减还是不一样的。

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

const int maxn=1000100;

typedef long long ll;
int N,Q;
ll val[maxn<<2];
struct Query
{
    int l,r;
    ll ask;
};Query q[maxn];

void push_up(int rt)
{
    val[rt]=val[rt<<1]&val[rt<<1|1];
}

void push_down(int rt)
{
    val[rt<<1]|=val[rt];
    val[rt<<1|1]|=val[rt];
}

void update(int L,int R,ll c,int l,int r,int rt)
{
    if(L<=l&&r<=R){
        val[rt]|=c;
        return;
    }
    push_down(rt);
    int m=(l+r)>>1;
    if(L<=m) update(L,R,c,lson);
    if(R>m) update(L,R,c,rson);
    push_up(rt);
}

ll query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R) return val[rt];
    push_down(rt);
    int m=(l+r)>>1;
    ll res=(1LL<<60)-1;
    if(L<=m) res&=query(L,R,lson);
    if(R>m) res&=query(L,R,rson);
    push_up(rt);
    return res;
}

void get(int l,int r,int rt)
{
    if(l==r){
        printf("%I64d ",val[rt]);
        return;
    }
    push_down(rt);
    int m=(l+r)>>1;
    get(lson);
    get(rson);
    push_up(rt);
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(cin>>N>>Q){
        memset(val,0,sizeof(val));
        for(int i=1;i<=Q;i++){
            scanf("%d%d%I64d",&q[i].l,&q[i].r,&q[i].ask);
            update(q[i].l,q[i].r,q[i].ask,1,N,1);
        }
        bool flag=1;
        for(int i=1;i<=Q;i++){
            if(query(q[i].l,q[i].r,1,N,1)!=q[i].ask){
                flag=0;break;
            }
        }
        if(flag){
            puts("YES");
            get(1,N,1);
            puts("");
        }
        else puts("NO");
    }
    return 0;
}
View Code

明天再补。

C题:概率+dp,略涉及字符串。补补补!

 

div2 B题:水题二分,画个集合的韦恩图容斥一下就好了。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);

ll c1,c2,x,y;

bool check(ll n)
{
    ll px=n/x;
    ll py=n/y;
    ll pxy=n/(x*y);
    return n-px>=c1&&n-py>=c2&&n-pxy>=c1+c2;
}

ll bin(ll l,ll r)
{
    while(l<r){
        ll m=(l+r)>>1;
        if(check(m)) r=m;
        else l=m+1;
    }
    return r;
}

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>c1>>c2>>x>>y){
        ll n=bin(1,1LL<<60);
        cout<<n<<endl;
    }
    return 0;
}
View Code

虽然20分钟过了A,不过线段树居然没过,没过的原因还是位运算的细节没想清楚,觉得处理起来比较麻烦,就没往线段树方面想了,还是经验问题。C题比较难,过的人有点少,但既然是dp,又涉及字符串,还是得补,增加经验。

不过要是做了那一场的div2,40min3题?可能也会紫?如果做出线段树呢?

明天补完BC,有时间再开一场,没时间就准备下午的组队赛了。

 

感觉该补线段树了

====================

做了一些线段树离线的题,补了Orz_panda的A题(线段树离线)和I题(状压dp),回来刷cf了。

第四场:

A题:水题。求[l,r]中二进制表示出现的1的个数最多的数,如果多种答案,输出最小的。

本来以为是数位dp,想了一下原来是个水题,比赛的时候用字符串模拟,51min才过,其实直接用数字二进制弄更简单些。

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

const int maxn=120;

int n;
ll l,r;
int numL[maxn],numR[maxn];
int nL,nR;

int main()
{
   // freopen("in.txt","r",stdin);
    cin>>n;
    while(n--){
        scanf("%I64d%I64d",&l,&r);
        int tmp[maxn];
        ll tl=l,tr=r;
        nL=nR=0;
        while(tl){
            tmp[nL++]=tl%2;
            tl>>=1;
        }
        for(int i=0;i<nL;i++) numL[i]=tmp[nL-1-i];
        //cout<<tr<<endl;
        while(tr){
            tmp[nR++]=tr%2;
            tr>>=1;
        }
        for(int i=0;i<nR;i++) numR[i]=tmp[nR-i-1];
       // cout<<nL<<" "<<nR<<endl;
        bool flag=1;
        for(int i=0;i<nR;i++){
            if(!numR[i]){
                flag=0;break;
            }
        }
        //cout<<flag<<endl;
        //for(int i=0;i<nR;i++) cout<<numR[i]<<" ";cout<<endl;
        if(flag){
            printf("%I64d\n",r);
            continue;
        }
        //cout<<nL<<" "<<nR<<endl;
        if(nL<nR){
            //cout<<nL<<" "<<((1LL<<nL)-1)<<endl;
            printf("%I64d\n",(1LL<<(nR-1))-1);
            continue;
        }
        int ans[maxn];
        memset(ans,0,sizeof(ans));
        bool tag=0;
        for(int i=0;i<nR;i++){
            if(tag){
                ans[i]=1;continue;
            }
            if(numL[i]!=numR[i]){
                tag=1;
                bool tag2=0;
                for(int j=i+1;j<nR;j++){
                    if(numR[j]==0){
                        tag2=1;break;
                    }
                }
                if(tag2) ans[i]=0;
                else ans[i]=1;
                continue;
            }
            ans[i]=numL[i];
        }
        ll Ans=0;
       // cout<<"f"<<endl;
        for(int i=0;i<nR;i++){
            if(ans[i]) Ans+=(1LL<<(nR-i-1));
        }
        printf("%I64d\n",Ans);
    }
    return 0;
}
View Code

B题:这题其实也不难。。

给一个序列,找一对(ai,aj)使得ai>aj,且ai%aj最大。

先排序,然后遍历a[j]*k,k=2,3,....,查找第一个比a[j]*k小的,取余数更新答案。

复杂度 :  a[j]*k <= Max,因此这部分复杂度类似素数筛(n/1+n/2+n/3+...+n/1=logn),后面二分查找也是logn,总复杂度(n*logn*logn).

#include<bits/stdc++.h>

using namespace std;

const int maxn=1000100;
const int INF=(1<<29);

int n;
int a[maxn];

int bin(int l,int r,int x,int mod)
{
    while(l<=r){
        int m=(l+r)>>1;
       // cout<<l<<" "<<r<<" "<<m<<" "<<a[m]<<endl;
        if((m==n&&a[m]<x)||(a[m]<x&&a[m+1]>=x)) return a[m]%mod;
        if(a[m]>=x) r=m-1;
        else l=m+1;
    }
    return 0;
}

int main()
{
    while(cin>>n){
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        n=unique(a+1,a+n+1)-(a+1);
        int Max=a[n];
        int ans=0;
        for(int i=1;i<=n;i++){
            for(int j=2;a[i]*(j-1)<=Max;j++){
               // cout<<i+1<<" "<<n<<" "<<a[i]*j<<" "<<a[i]<<endl;
                ans=max(bin(i+1,n,a[i]*j,a[i]),ans);
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}
View Code

 

 第五场:(#273 div 2)

A题:略。

B题:略。

C题:

给定a个红球,b个白球,c个蓝球,求每次选择确定的三个装饰桌子,不能选完全相同的三个,最多能装饰多少桌子。

不妨设a>=b>=c,当a<=(b+c)*2时,直接除以3。

#include<bits/stdc++.h>

using namespace std;

const int maxn=1000100;
const int INF=(1<<29);
typedef long long ll;

ll r,b,g;

void solve()
{
    ll a[3]={r,b,g};
    sort(a,a+3);
    r=a[2];b=a[1];g=a[0];
    if(r>(b+g)*2) r=(b+g)*2;
    cout<<(r+b+g)/3<<endl;
}

int main()
{
    while(cin>>r>>b>>g){
        solve();
    }
    return 0;
}
View Code

D题:

 dp题。http://codeforces.com/contest/478/problem/D

#include<bits/stdc++.h>

using namespace std;

const int maxn=200100;
const int INF=(1<<29);
typedef long long ll;
const ll MOD=1000000007;

ll dp[2][maxn];
int r,g;

int main()
{
    while(~scanf("%d%d",&r,&g)){
        memset(dp,0,sizeof(dp));
        dp[1][0]=r?1:0;
        dp[1][1]=g?1:0;
        ll H=0;
        for(int x=1;;x++){
            if((r+g)-x*(x+1)/2>=0) H=x;
            else break;
        }
        ll sum=1;
        for(int i=2;i<=H;i++){
            sum+=i;
            for(int j=0;j<=g&&j<=sum;j++){
                dp[i%2][j]=0;
                if(sum-j<=r){
                    dp[i%2][j]=(dp[i%2][j]+dp[(i+1)%2][j])%MOD;
                    if(j>=i) dp[i%2][j]=(dp[i%2][j]+dp[(i+1)%2][j-i])%MOD;
                }
            }
        }
        ll ans=0;
        for(int i=0;i<=g;i++) ans=(ans+dp[H%2][i])%MOD;
        cout<<ans<<endl;
    }
    return 0;
}
View Code

E题:数位dp,待补。。

 

 

 

posted @ 2015-08-23 20:44  __560  阅读(232)  评论(0编辑  收藏  举报