1. 程式人生 > >解題報告:Codeforces Round #421 (Div. 2) A-E

解題報告:Codeforces Round #421 (Div. 2) A-E

A、題目連結

題意:一本c頁的書要讀,你的初始讀書速度為v0,每天速度增加a,速度上限為v1,每天讀書後若書沒有讀完則忘記l頁,詢問多少天讀完。

思路:

類似於蝸牛上樹,資料小直接模擬,資料大推個公式。

程式碼:

#include<bits/stdc++.h>

using namespace std;

int c,v0,v1,a,l;
int main()
{
    while(scanf("%d%d%d%d%d",&c,&v0,&v1,&a,&l)==5){
        int ans = 0;
        while(c>=0){
            ans++;
            c-=v0;
            v0 = min(v0+a,v1);
            if(c<=0)break;
            c+=l;
        }printf("%d\n",ans);
    }return 0;
}

B、題目連結

題意

在正n多邊形內選三個點組成一個角,求最靠近t的這個角的大小三個點號碼

思路:

正n多邊形內最大角為內角(n-2)*180/n,設角中心的點號碼為1,那麼最大角為213,每次想外移動一個單位,角度減小180/n,記錄最靠近的答案就好,複雜度O(n)。

程式碼:

#include<bits/stdc++.h>

using namespace std;

int n;
double a;
int main()
{
    while(scanf("%d%lf",&n,&a)==2){
        double mx = 1.0*(n-2)*180.0/n;
        double tmp = mx;
        int ans = n;
        double t = 180.0/n;
        for(int i=n-1;i>2;i--){
            tmp-=t;
            if(fabs(tmp-a)<fabs(mx-a)){
                ans = i;
                mx = tmp;
            }
        }
        printf("2 1 %d\n",ans);
    }return 0;
}

C、題目連結

這個題有點問題,出題人的程式碼被hack了,詳見 點選開啟連結

題意:

兩個人進行字元串游戲,初始串為空串,兩個人輪流往後加字母,第一個人的操作是選擇串裡的後a個字母,然後往後面加a個字典序最小的與 選擇的這個a個字母不重複的 不重複字母串,第二個可以任意加長度為b的字母串,給定l,r,問你作為第二個玩家進行遊戲時組成的字串[ l , r ]區間出現的字母種類數。

講一下原來的思路:

第二個人只需要把串最後面的元素重複b次,然後就可以發現生成串是一個長度為2(a+b)的迴圈串,將區間對映到對應的迴圈串進行統計即可。

D、題目連結

題意:

給定一個長度為n的全排列,定義 deviation

為每個位上的數減去下標的絕對值之和,你可以進行把最右邊的數放在最左的操作,問你可以通過這個操作得到的最小的deviation和得到這個deviation進行的操作個數。

思路:

先計算得出初始串的deviation 值,並統計 數字和下標相等的個數numa ,數字比下標小的個數numb , 數字比下標大的個數numc,big[x]陣列記錄數字比下標大x的個數。每次操作,不考慮最後一位的變化,原本小的貢獻會變得大,等於的貢獻會變大,大的貢獻會變小,利用numa,numb,numc,還有分類討論最後位數與下標的大小的情況可以O(1)的更新deviation,統計最小值即可。

程式碼:

#include<bits/stdc++.h>

using namespace std;

int n;
int A[1000005];
int big[1000005];
int main()
{
    int a=0,b=0,c=0;
    long long ans = 0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&A[i]);
        ans += abs(A[i]-i);
        if(A[i]>i){
            c++;
            big[A[i]-i]++;
        }else if(A[i]==i){
            a++;
            big[0]++;
        }else {
            b++;
        }
    }//printf("ans-->%d\n",ans);
    int pos = n , id = 0;
    int ans_pos = 0 ;
    long long tmp = ans;
    while(--pos){
        id++;
        tmp += b+a;
        tmp -= c;
        b = b+a;
        c = c-big[id];
        a = big[id];
        if(A[pos+1]==n){
            tmp += n-2;
            int t = id + n-1;
            if(t<=n)big[t]++;
            b--;
            c++;
        }else if(A[pos+1]==1){
            b--;
            a++;
            tmp -= n;
        }else {
            b--;
            c++;
            int t = id+A[pos+1]-1;
            if(t<=n)big[t]++;
            tmp += -abs(A[pos+1]-n-1)+(A[pos+1]-1);
        }
        //printf("%d %d a->%d b->%d c->%d\n",id,tmp,a,b,c);

        if(tmp<=ans){
            ans = tmp;
            ans_pos = id;
        }
    }printf("%I64d %d\n",ans,ans_pos);


    return 0;
}


E、題目連結

題意:

有三個裝置,裝置A放在(m,0)處,裝置B放在(0,n)處,裝置C不明。

第一步把裝置A直線移動到原點,第二步把裝置B直線移動到原點,當三個裝置都位於整數點上且他們之間的三角形面積為s時會發出一次訊號,問移動過程中有多少個位置可能會發出訊號。

m,n,s都是以3個整數ma*mb*mc=m的形式給出,1000組資料一個檔案。

思路:

考慮第一步操作的過程,設A(k,0),B(0,n),C(x,y),則利用叉積求得三角形面積為k*(y-n)+x*n,只需要判斷這個式子能否等於2s,很明顯該式子有整數解只需要滿足gcd(k,n)|2s,那麼我們只需要求滿足gcd(k,n)|2s的k個數即可,設n和2s的唯一分解式為n=PI(pi^ni) , 2s = PI(pi^si) ,我們知道當相同pi時,若ni>si,則pi^(si+1)不能整除k,利用這點加上容斥可以求得第一步裡可能的位置個數。

考慮第二步操作的過程,設A(0,0),B(0,k),C(x,y),則三角形面積為k*x,那麼只有求得滿足 k|2s 的k的個數即可,dfs一下即可。

程式碼:

#include<bits/stdc++.h>


#define pii pair<long long,int>
#define fi first
#define se second
using namespace std;


vector<pii>V;
map<int,int>M[4];
long long n , m , s , ans;


void oper(int x,int k){
    for(int i=2,ed=sqrt(x+0.5);i<=ed&&x>1;i++){
        while(x%i==0){
            x/=i;
            M[k][i]++;
        }
    }if(x>1)M[k][x]++;
}

void dfs1(int pos,int need,int k,long long val,const long long& x){
    if(!need||val>x){
        ans += k * x/val;
        return ;
    }for(int i=pos;i<V.size();i++){
        if(val*V[i].fi/V[i].fi==val)
            dfs1(i+1,need-1,k,val*V[i].fi,x);
    }
}


void dfs2(int pos , long long val ,const long long& mx){
    if(val<=mx){
        ans++;
    }else {
        return ;
    }
    for(int i=pos;i<V.size();i++){
        long long t = val;
        for(int j=1;j<=V[i].se;j++){
            t *= V[i].fi;
            dfs2(i+1,t,mx);
        }
    }
}

long long qpow(long long x,int y){
    long long res = 1;
    while(y){
        if(y&1)res *= x;
        y>>=1;
        x *= x;
    }return res;
}

int main(){

    int T;
    scanf("%d",&T);
    while(T--){
        V.clear();
        for(int i=0;i<3;i++)M[i].clear();
        n = 1 , m = 1 , s = 2;
        M[2][2]++;
        for(int i=0,x;i<3;i++){
            scanf("%d",&x);
            n *= x;
            oper(x,0);
        }for(int i=1,x;i<=3;i++){
            scanf("%d",&x);
            m *= x;
            oper(x,1);
        }for(int i=1,x;i<=3;i++){
            scanf("%d",&x);
            s *= x;
            oper(x,2);
        }

        M[3].clear();
        V.clear();
        for(auto it = M[0].begin();it!=M[0].end();it++){
            if( it->se > M[2][it->fi]){
                V.emplace_back(pii(qpow(it->fi,M[2][it->fi]+1),0));
            }
        }ans = m;
        for(int i=1;i<=V.size();i++){
            dfs1(0,i,(i&1)?-1:1,1,m);
        }//printf("ans-->%I64d\n",ans);
        V.clear();
        for(auto it=M[2].begin();it!=M[2].end();it++){
            if(it->se){
                V.emplace_back(*it);
            }
        }dfs2(0,1,n);

        printf("%I64d\n",ans);
    }return 0;
}