AtCoder Grand Contest 015

AtCoder Grand Contest 015

A - A+...+B Problem

有一我的有\(n\)個數,最小的是\(A\),最大的是\(B\),其餘數位置,問一共有多少種和的可能狀況。html

顯然可以取到的是一段連續值,那麼求出最小值和最大值就好了。ios

#include<iostream>
using namespace std;
long long n,a,b,l,r;
int main()
{
    cin>>n>>a>>b;
    if(a>b){puts("0");return 0;}
    l=b+(n-1)*a,r=a+(n-1)*b;
    cout<<max(0ll,r-l+1)<<endl;
    return 0;
}

B - Evilator

有一個電梯,有\(n\)層樓,給定了一個字符串\(S\)\(S_i\)告訴你了這個電梯在這一層只能向上走或者是向下走。spa

如今問你任意兩層之間須要坐幾回電梯,求出全部狀況的和。code

顯然答案不是\(1\)就是\(2\),那麼對於每一個位置判斷一下有多少個是\(1\)有多少個是\(2\)就好了。htm

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n;long long ans;
char S[100010];
int main()
{
    scanf("%s",S+1);n=strlen(S+1);
    for(int i=1;i<=n;++i)
        if(S[i]=='U')ans+=(n-i)+2*(i-1);
        else ans+=2*(n-i)+(i-1);
    printf("%lld\n",ans);
    return 0;
}

C - Nuske vs Phantom Thnook

有一個網格圖,一些格子被塗藍了,保證藍色的格子構成了一棵樹。blog

每次詢問問你一個子矩形內藍色格子構成的聯通塊數量。排序

既然是一棵樹,那麼聯通塊個數等於點數減去邊數,而後就很好作了。遞歸

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 2010
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int n,m,Q;
char g[MAX][MAX];
int s[MAX][MAX],sl[MAX][MAX],su[MAX][MAX];
int Calc(int s[][MAX],int x1,int y1,int x2,int y2)
{
    if(x1>x2||y1>y2)return 0;
    return s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];
}
int main()
{
    n=read();m=read();Q=read();
    for(int i=1;i<=n;++i)scanf("%s",g[i]+1);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            s[i][j]=(g[i][j]=='1');
            sl[i][j]=(g[i][j]=='1'&&g[i][j-1]=='1');
            su[i][j]=(g[i][j]=='1'&&g[i-1][j]=='1');
        }
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
            sl[i][j]+=sl[i-1][j]+sl[i][j-1]-sl[i-1][j-1];
            su[i][j]+=su[i-1][j]+su[i][j-1]-su[i-1][j-1];
        }
    while(Q--)
    {
        int x1=read(),y1=read(),x2=read(),y2=read();
        printf("%d\n",Calc(s,x1,y1,x2,y2)-Calc(sl,x1,y1+1,x2,y2)-Calc(su,x1+1,y1,x2,y2));
    }
    return 0;
}

D - A or...or B Problem

\([A,B]\)之間的數構成的非空集合的\(or\)值有多少種。ci

感受頗有想法,然而就是不會作,。。。字符串

首先\(A=B\)不用管了,只考慮\(A=B\) 的狀況,那麼先找到二進制位下\(A,B\)不一樣的第一位,前面的部分能夠直接丟掉,由於對於答案不產生影響。

假設最高位是\(k\),那麼咱們把集合分紅兩個部分,一半是\([A,2^k)\),另外一半是\([2^k,B]\),在第一部分裏面任意選數只能選出\([A,2^k)\)的值,在第二部分中選數,考慮\(B\)的次大二進制爲\(l\),那麼能夠選的範圍在\([2^k,2^k+2^l)\)之間,若是兩個部分同時選的話,那麼能夠獲得的範圍是\([2^k+A,2^{k+1})\)

這三個部分取並就是答案了。

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
ll A,B,ans;
int main()
{
    cin>>A>>B;
    if(A==B){puts("1");return 0;}
    int k=60;
    for(;~k;--k)
    {
        if((A>>k&1)^(B>>k&1))break;
        if(A>>k&1)A^=1ll<<k,B^=1ll<<k;
    }
    int l=k-1;
    while((~l)&&!(B&(1ll<<l)))--l;
    ll L=(!~l)?B:((1ll<<k)+(1ll<<(l+1))-1);
    ll R=(1ll<<k)+A;
    ans=(1ll<<(k+1))-A;
    if(L+1<R)ans-=R-L-1;
    printf("%lld\n",ans);
    return 0;
}

E - Mr.Aoki Incubator

數軸上有\(n\)我的,第\(i\)我的一開始在\(X_i\)位置,用\(v_i\)的初速度往正方向移動。一開始有若干我的被染色,被染色的人若是碰到了未被染色的人,就把會未被染色的人給染色。

問在全部的\(2^n\)種初始的染色方案中,有多少種染色方法在足夠長的時間以後可以讓全部人都被染色。

首先最終的序列必定是惟一的,即全部人都按照速度的順序依次排開,而且全部人相遇的時間也是固定的,那麼惟一須要考慮的就只有染色的狀況。

考慮如今只有一個點被染色,考慮哪些點會被染色。顯然是位置在它左側其速度比它快的,以及位置在它右側而且速度比它慢的點會被追上。

把全部點按照速度從大往小排序,那麼,對於一個點,在速度比它大的點中找到最靠右的那個,記作\(L\)。在速度比它小的點中找到最靠左的那個,記作\(R\) 。那麼\([L,R]\)都會被染色(看起來挺容易證實的)。

因而問題等價於有\(n\)個區間,選出若干個使得他們的並剛好是全集的方案數。

那麼這個東西直接\(dp\)就好了。

把全部區間按照右端點排序,設\(f[i]\)表示考慮了前\(i\)個區間,且\([1,R_i]\)都已經被覆蓋的方案數。

這個東西能夠用前綴和很方便的進行轉移。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MOD 1000000007
#define MAX 200200
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
struct Node{int x,v;}p[MAX];
int S[MAX],top;
bool operator<(Node a,Node b){return a.v<b.v;}
struct Line{int l,r;}a[MAX];
bool operator<(Line a,Line b){if(a.r!=b.r)return a.r<b.r;return a.l<b.l;}
int f[MAX],s[MAX],ans,n;
int main()
{
    n=read();
    for(int i=1;i<=n;++i)p[i].x=read(),p[i].v=read();
    sort(&p[1],&p[n+1]);
    for(int i=1;i<=n;++i)
    {
        if(!top||p[i].x>p[S[top]].x)S[++top]=i;
        int l=1,r=top,ret=i;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(p[S[mid]].x>=p[i].x)r=mid-1,ret=mid;
            else l=mid+1;
        }
        a[i].l=S[ret];
    }
    top=0;
    for(int i=n;i>=1;--i)
    {
        if(!top||p[i].x<p[S[top]].x)S[++top]=i;
        int l=1,r=top,ret=i;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(p[S[mid]].x<=p[i].x)r=mid-1,ret=mid;
            else l=mid+1;
        }
        a[i].r=S[ret];
    }
    sort(&a[1],&a[n+1]);
    for(int i=1,p=1;i<=n;++i)
    {
        while(a[p].r<a[i].l-1)++p;
        f[i]=(s[i-1]-s[p-1]+MOD)%MOD;
        if(a[i].l==1)f[i]=(f[i]+1)%MOD;
        if(a[i].r==n)ans=(ans+f[i])%MOD;
        s[i]=(s[i-1]+f[i])%MOD;
    }
    printf("%d\n",ans);
    return 0;
}

F - Kenus the Ancient Greek

給你\(n,m\),求\(x\in [1,n],y\in[1,m]\)中,讓\(x,y\)作展轉相除的最大遞歸次數是多少。

並求出可以取到最大值的\((x,y)\)的對數。

首先最大值很容易算,不難發現就是斐波那契數列最大的相鄰的兩項,知足都在範圍內。

考慮怎麼統計答案,咱們不妨令\(x\ge y\)。假設最大值是\(k\),遞歸次數是\(g(x,y)\)\(f_i\)爲斐波那契數列第\(i\)項,且\(f_0=f_1=1\)。 那麼\(g(x,y)\)的最大值爲知足\(f_{k+1}\le x,f_{k}\le y\)的最大\(k\)

剩下的部分戳這裏吧

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define ll long long
#define MOD 1000000007
#define pi pair<ll,ll>
#define mp make_pair
inline ll read()
{
    ll x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
ll f[110];
vector<pi> a[110];
int main()
{
    int T=read();
    f[0]=f[1]=1;
    for(int i=2;i<=100;++i)f[i]=f[i-1]+f[i-2];
    a[1].push_back(mp(1,2));a[1].push_back(mp(1,3));a[1].push_back(mp(1,4));
    for(int i=1;i<=100;++i)
        for(int j=0,l=a[i].size();j<l;++j)
        {
            ll x=a[i][j].second,y=a[i][j].first+x;
            while(y<=f[i+3]+f[i])a[i+1].push_back(mp(x,y)),y+=x;
        }
    while(T--)
    {
        ll n=read(),m=read();if(n>m)swap(n,m);
        if(n==1&&m==1){puts("1 1");continue;}
        int p,ans=0;for(int i=1;;++i)if(!(n>=f[i]&&m>=f[i+1])){p=i-1;break;}
        printf("%d ",p);if(p==1){printf("%lld\n",(n%MOD)*(m%MOD)%MOD);continue;}
        for(int j=0,l=a[p-1].size();j<l;++j)
        {
            ll x=a[p-1][j].first,y=a[p-1][j].second;
            if(y<=n)ans=(ans+(m-x)/y)%MOD;
            if(y<=m)ans=(ans+(n-x)/y)%MOD;
        }
        printf("%d\n",ans);
    }
}
相關文章
相關標籤/搜索