Codeforces Round #749 (Div. 1 + Div. 2, based on Technocup 2022 Elimination Round 1) 賽后總結


一、整體流程

做了A和B。

大膽猜想,直接寫碼……

二、具體題目

A. Windblume Ode

(1)讀題

①場上:從樣例解釋中發現,輸出時的順序無關緊要,換句話講,輸出1 2 3 ... 8 9與輸出6 9 1 2 3 ... 8都算正確。

題目要求集合大小盡量大,但不需要總值最大。同時,需要判斷合數或者素數。

那么,如果保證是合數的話,就可以直接輸出;如果是素數的話,可以想辦法減為合數。

②改進:可以大膽猜想算法。一般對於最簡單的一道題,都有着非常容易寫出的代碼,即不考察算法和碼力,轉而考慮數學猜想和證明能力。對於此題,大膽猜想可隨意刪除一個數字,如果保證刪除此數后新的和為合數,就貪心的輸出答案。

③證明:在和本身為合數的情況下,直接輸出答案。如果本身不是合數,那么和一定是質數,也一定是奇數。既然和是奇數,那么只要再減去一個奇數就可以變成偶數了,既然是偶數,那么也必然是合數。考慮到和為奇數,那么一定有起碼一個奇數,即充分性。

(2)做題

由於int sum=0;定義在了函數外,wa了兩次。

素數篩

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
bool isGood[300000];//�Ƿ�Ϊ���� 

void init(){
    for(int i=2;i<=20000;i++){
        for(int j=2;j<=20000;j++){
            if(i*j>20000)continue;
            else isGood[i*j]=1;
        }
    }
} 

int a[200];
int main()
{
    //cout<<Miller_Rabin(3)<<endl;
    init();
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        int sum=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        //printf("isGood[%d]=%d\n",sum,isGood[sum]);
        if(isGood[sum]){//�����Ǻ��� 
            printf("%d\n",n);
            for(int i=1;i<=n;i++){
                printf("%d ",i);
            } 
            printf("\n");
        }else{//�����Ǻ��� 
            //ȥ��һ������ʹ��ȥ�����sumΪ������Ȼ������� 
            int removeIndex=0;
            for(int i=1;i<=n;i++){
                if(isGood[sum-a[i]]){
                    removeIndex=i;
                    //printf("removeIndex:%d\n",removeIndex);
                    break;
                }
            }
            printf("%d\n",n-1);
            for(int i=1;i<=n;i++){
                if(i!=removeIndex){
                    printf("%d ",i);
                }
            }
            printf("\n");
        }
    }
    return 0;
}
View Code

Miller-Rabin

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int prime[10]={2,3,5,7,11,13,17,19,23,29};
int Quick_Multiply(int a,int b,int c)  
{
    long long ans=0,res=a;
    while(b)
    {
        if(b&1)
          ans=(ans+res)%c;
        res=(res+res)%c;
        b>>=1;
    }
    return (int)ans;
}
int Quick_Power(int a,int b,int c)   
{
    int ans=1,res=a;
    while(b)
    {
        if(b&1)
          ans=Quick_Multiply(ans,res,c);
        res=Quick_Multiply(res,res,c);
        b>>=1;
    }
    return ans;
}
bool Miller_Rabin(int x)  
{
    int i,j,k;
    int s=0,t=x-1;
    if(x==2)  return true; 
    if(x<2||!(x&1))  return false;  
    while(!(t&1))
    {
        s++;
        t>>=1;
    }
    for(i=0;i<10&&prime[i]<x;++i)     
    {
        int a=prime[i];
        int b=Quick_Power(a,t,x);  
        for(j=1;j<=s;++j)   
        {
            k=Quick_Multiply(b,b,x); 
            if(k==1&&b!=1&&b!=x-1)   
              return false;
            b=k;
        }
        if(b!=1)  return false;  
    }
    return true; 
}
 
 
int a[200];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int sum=0;
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        if(!Miller_Rabin(sum)){//?????????? 
            printf("%d\n",n);
            for(int i=1;i<=n;i++){
                printf("%d ",i);
            } 
            printf("\n");
        }else{
            //???????????????????sum??????????????? 
            int removeIndex=0;
            for(int i=1;i<=n;i++){
                if(!Miller_Rabin(sum-a[i])){
                    removeIndex=i;
                    //printf("removeIndex:%d\n",removeIndex);
                    break;
                }
            }
            printf("%d\n",n-1);
            for(int i=1;i<=n;i++){
                if(i!=removeIndex){
                    printf("%d ",i);
                }
            }
            printf("\n");
        }
    }
    return 0;
}
View Code

B. Omkar and Heavenly Tree

 

 

(1)讀題

①場上:題意要求兩點之間的簡單路徑中不能有違法點,考慮重新建圖。注意到兩點之間如果有任何限制,那么連接這兩個點,就可以直接忽略掉這些限制。但是如果直接連接輸出答案的話,可能出現環或者其他構造答案,因此要換一種連點越過限制的方法。

②改進:div2的B題一般不會太難,難度主要在思維上。重新審視要求,發現對於樹的類型和形狀沒有確切的規定,輸出答案十分自由。那么聯想到"菊花圖"

③證明:菊花圖有着一個特性:任意兩點之間的中間點必然有且只有中心點和兩點上面的點。聯合a,b,c均獨特的特性,得到正解為構造一顆深度為2的菊花圖.

(2)做題

#include<cstdio>
#include<iostream>
using namespace std;
bool baned[200000];
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        scanf("%d%d",&n,&m); 
        for(int i=1;i<=n;i++)baned[i]=0;
        for(int i=1;i<=m;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            baned[b]=1;
        }
        for(int i=1;i<=n;i++){
            if(!baned[i]){//
                for(int j=1;j<=n;j++){
                    if(j!=i)
                    printf("%d %d\n",i,j);
                }
                break; 
            }
        }
    }
    return 0;
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM