Educational Codeforces Round 89 (Rated for Div. 2)重點:D. Two Divisors

鏈接

雖然因爲菜造成了這麼慢的寫完,但至少策略上沒有什麼問題,既然卡題那就做下一題,再卡就再換,雖然最後的時間都不夠做這道D題了
在這裏插入圖片描述

A、Shovels and Swords

題意簡單不表

菜是原罪,比賽的時候嘗試了各種手段,各種方法
首先要求出x+y的最大值
可以列出等式
x + 2y <= a;
2
x + y <= b;
由此可知3x+3y <= (a+b)
因此x+y <= (a+b)/3
到了這步我就不會了,感覺不是充要條件,當然事後題解是和a,b再取個最小值,但我當時真懵了,感覺搞不出充要證明

就換方法

於是乎我就通過推樣例發現,本題的難點在於貪心一方是不一定能夠得到最後答案的,那麼如果能夠將兩個值變爲相等的話,那麼就有固定套路,如果不能變爲相等,直接取最小,如果可以,就判斷一下%3的情況,於是過了。

int n ;
int a,b;
int main(){
    int _;
    for(scanf("%d" , &_) ; _ ; _ --){
        scanf("%d %d", &a , &b);
        if(a > b )swap(a,b);
        int x = b - a;
        int y = min(x ,min(a,b/2));
        b -= 2*y, a -= y;
        if(b == a){
            int q ;
            if(a % 3 >= 2)q = 1;
            else q = 0;
            printf("%d\n",a / 3 * 2 + y + q);
        }
        else{
            printf("%d\n" , y);
        }
    }
    return 0;
}
int main(){
    int _;
    for(scanf("%d" ,&_); _ ;_ --){
        int a,b;
        scanf("%d %d" ,&a, &b);
        int mini = min((a + b) / 3 , min(a,b));
        cout << mini <<endl;
    }
    return 0;
}

B. Shuffle

題意:給你一個n,m,x。x代表初始位置,有n個數,m個區間,如果x在區間裏,你可以將x替換成區間內的任意一個值,問你最後可能的最大範圍是多少
思路:大致就是x在某個區間裏,就將x擴大爲這個區間,然後利用這個區間再更新

int main(){
    int _;
    for(scanf("%d" , &_) ; _ ; _ --){
        int n , m , x , l ,r;
        scanf("%d %d %d" ,&n , &x, &m);
        int maxx = -1 , mini = 0x3f3f3f3f , flag = 0;
        for(int i = 1; i <= m ; i ++){
            scanf("%d %d",&l , &r);
            if(flag){
                if((l >= mini && l <= maxx)||(r >=mini && l <= maxx)){
                    maxx = max(r, maxx);
                    mini = min(l, mini);
                }
            }
            if(l <= x && r >= x){
                maxx = max(r, maxx);
                mini = min(l, mini);
                flag = 1;
            }
        }
        if(!flag)puts("1");
        else{
            cout << maxx - mini + 1 << "\n";
        }
    }
}

C. Palindromic Paths

題意:你從1,1點到n,m點的所有路徑必須是迴文路徑
思路:類似於一個bfs的思想,第一步和最後一步的數字必須相同,第二步和倒數第二步…以此類推,再將裏面的值肯定是取數量最大的值,改變數量最小的值。

int a[33][33];
int dx[2] = {1,0},
    dy[2] = {0,1};
 
int v[100][3];
int main(){
    int _;
    for(scanf("%d" , &_) ; _ ; _ --){
        int n , m;
        memset(v,0,sizeof v);
        scanf("%d %d" ,&n ,&m );
        for(int i = 1; i <= n ; i++){
            for(int j = 1; j <= m ; j ++){
                scanf("%d",&a[i][j]);
                v[abs(i-1) + abs(j-1)][a[i][j]] ++;
            }
        }
        int ans = 0;
        for(int i = 0 ,j = n+m-2 ; i < j ; i ++ , j --){
//            int maxx = max(v[i][0]+v[j][0],v[i][1] + v[j][1]);
            ans += min(v[i][0]+v[j][0],v[i][1] + v[j][1]);
        }
        printf("%d\n",ans);
    }
}

D. Two Divisors

來到重點題,題意好像還是很輕鬆明白的
重要的是這題的思路證明。
首先對於這一題的求解,想要尋找問題的突破口,於是就必須看給出的條件,他d1,d2的限制是在每一個a[i]的所有因子裏,再加上 他的每一個a[i] 是在1e7裏的,我們很容易想到一個n*sqrt(A)的做法,將每一個數的因子找出來,然後找兩個符合的,我們這時候會發現n是5e5而sqrt(A)大約在5e3左右綜合複雜度大約在1e9左右,是不能跑過cf的樣例的。到了這裏我們會繼續看,其實對於d1+d2想要和a[i]取到一個gcd爲1,我們可以這樣,感性認知一下,對於每一個數分解成一個數乘以另一個數,這倆個數相加一定會符合gcd爲1
下面給出證明

  • 假設A分解成p1c1 p2c2 p3c3
    將他分成
    x = p1c1p2c2…pkck ,
    y = pk+1ck+1pk+2ck+2
    因爲xy = n
    那麼
    gcd(x+y,n) = gcd(x+y,xy) = gcd(x+y,x)*gcd(x+y,y) = gcd(x,y)*gcd(y,x) = 1
    命題得證

    (這個格式用法好迷啊=-=不會用)
    那麼現在我們只需要維護1e7以內所有數的最小公因數,並且只要爲兩個就可以輸出,否則就是-1,兩種方法(實際上還有很多種隨你用,線性篩蠻快的)

在這裏插入圖片描述

int n;
int a[N];
int v[10000007];
int main(){
    for(int i = 2 ; i <= M ; i ++){
        if(v[i] == 0){
            v[i] = i;
            for(int j = i + i ; j <= M ; j +=i){
                v[j] = i;
            }
        }
    }
    while(~scanf("%d" , &n)){
        for(int i = 1; i <= n ; i ++){
            scanf("%d" , &a[i]);
        }
        VI G[2];
        for(int i = 1; i <= n ; i ++){
            int res = a[i] , lin = v[res];
            while(res % lin == 0 )res /= lin;
            if(res > 1){
                G[0].pb(res);
                G[1].pb(a[i]/res);
                continue;
            }
            G[0].pb(-1);
            G[1].pb(-1);
        }
        for(auto x : G[0])printf("%d ",x);puts("");
        for(auto x : G[1])printf("%d ",x);puts("");
    }
    return 0;
}
int n;
int a[N];
int v[10000007],prime[10000007];
int main(){
    int m = 0;
    for(int i = 2 ; i <= M ; i ++){
        if(v[i] == 0){
            v[i] = i;
            prime[++m] = i;
        }
        for(int j = 1 ; j <= m ;j ++){
            if(prime[j]>v[i]||prime[j]>M/i)break;
            v[i*prime[j]] = prime[j];
        }
    }
//    for(int i = 1; i <= 100; i ++)cout << prime[i] <<" ";puts("");
    while(~scanf("%d" , &n)){
        for(int i = 1; i <= n ; i ++){
            scanf("%d" , &a[i]);
        }
        VI G[2];
        for(int i = 1; i <= n ; i ++){
            int res = a[i] , lin = v[res];
            while(res % lin == 0 )res /= lin;
            if(res > 1){
                G[0].pb(res);
                G[1].pb(a[i]/res);
                continue;
            }
            G[0].pb(-1);
            G[1].pb(-1);
        }
        for(auto x : G[0])printf("%d ",x);puts("");
        for(auto x : G[1])printf("%d ",x);puts("");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章