2019icpc南京網絡賽



 

B. super_log(擴展歐拉函數)

題意:求aa...(b個a)模M的值。

思路:遞歸用歐拉函數求解,我們知道歐拉降冪公式:

 

 如果討論b和φ(p)的關系會很麻煩,網上證明了一種精妙的方法,只需重新Mod,就能把a和p當作互素處理,從而統一處理。

要注意的點是:快速冪中取模也要用重寫的Mod,最終的答案要%M,遞歸終點為b=0,如果終點為b=1時,當b=0會WA。

AC代碼:

#include<cstdio>
#include<algorithm>
#include<bitset>
using namespace std;

typedef long long LL;
const int maxn=1e6+5;
int T;
LL a,b,M,eu[maxn];

void eular(){
    eu[1]=1;
    for(int i=2;i<maxn;++i)
        if(!eu[i])
            for(int j=i;j<maxn;j+=i){
                if(!eu[j]) eu[j]=j;
                eu[j]=eu[j]/i*(i-1);
            }
}

LL Mod(LL x,LL M){
    return x<M?x:x%M+M;
}

LL qpow(LL a,LL b,LL M){
    LL ret=1;
    while(b){
        if(b&1) ret=Mod(ret*a,M);
        a=Mod(a*a,M);
        b>>=1;
    }
    return ret;
}

LL dfs(LL b,LL M){
    if(b==0) return Mod(1,M);
    if(M==1) return Mod(a,M);
    return qpow(a,dfs(b-1,eu[M]),M);
}

int main(){
    eular();
    scanf("%d",&T);
    while(T--){
        scanf("%lld%lld%lld",&a,&b,&M);
        printf("%lld\n",dfs(b,M)%M);
    }
    return 0;
}

 

 


 

 

H. Holy Grail(Floyd求最短路)

題意:給定一個圖,沒有多重邊和自回路,有負權邊,但沒有負權環。n個點,m條有向邊,n<=300,m<=500,現加入6條邊,使得加入的邊權最小,並且不會出現負權環。並且保證一定有解。

思路:

  因為保證一定有解,如果加入的邊為(u,v),那么原圖一定有一條v->u的路徑。所以我們用floyd求出各點之前的最短路即可,那么新加的邊的最小權值就是v到u的最短路的相反數。新加一條邊后重新floyd。

AC代碼:

#include<cstdio>
#include<algorithm>
using namespace std;

typedef long long LL;
const int maxn=305;
const LL inf=0x3f3f3f3f3f3f3f3f;
int T,n,m;
LL dp[maxn][maxn];

void floyd(){
    for(int k=1;k<=n;++k)
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
}

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                dp[i][j]=inf;
        for(int i=1;i<=m;++i){
            int x,y;LL w;
            scanf("%d%d%lld",&x,&y,&w);
            dp[++x][++y]=w;
        }
        for(int i=1;i<=6;++i){
            floyd();
            int x,y;
            scanf("%d%d",&x,&y);
            ++x,++y;
            printf("%lld\n",-1LL*dp[y][x]);
            dp[x][y]=-1LL*dp[y][x];
        }
    }
    return 0;
}

 


 

 

F. Greedy Sequence(暴力)

題意:化簡之后題意就是對於給定排列,求元素i向左向右擴展k個元素后的第一個比i小的元素。

思路:

  最開始以為是單調隊列擴展,后來發現單調隊列沒法做。后來讓隊友試了一發主席樹,T了。然后我想用set試一試,用set加入窗口大小為k的所有元素,每次求出第一個比它小的元素,順序求一次,逆序再求一次。抱着T的心態交了一發,竟然過了QAQ,激動壞了,數據也太水了,暴力都能過。

AC代碼:

#include<cstdio>
#include<algorithm>
#include<set>
#include<cctype>
using namespace std;

inline int read()
{
    int x=0,f=0; char ch=0;
    while(!isdigit(ch)) {f|=ch=='-';ch=getchar();}
    while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return f?-x:x;
}

const int maxn=1e5+5;
int T,n,k,a[maxn],id[maxn],b[maxn],ans[maxn];
set<int> st;

int main(){
    scanf("%d",&T);
    while(T--){
        st.clear();
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i){
            a[i]=read();
            id[a[i]]=i;
            b[i]=0;
        }
        st.insert(a[1]);
        for(int i=2;i<=n;++i){
            st.insert(a[i]);
            if(i-k-1>0) st.erase(a[i-k-1]);
            if(*(st.begin())==a[i]) continue;
            set<int>::iterator it=st.find(a[i]);
            --it;
            b[i]=max(b[i],*it);
        }
        st.clear();
        st.insert(a[n]);
        for(int i=n-1;i>=1;--i){
            st.insert(a[i]);
            if(i+k+1<=n) st.erase(a[i+k+1]);
            if(*(st.begin())==a[i]) continue;
            set<int>::iterator it=st.find(a[i]);
            --it;
            b[i]=max(b[i],*it);
        }    
        for(int i=1;i<=n;++i)
            if(b[id[i]]==0) ans[i]=1;
            else ans[i]=ans[b[id[i]]]+1;
        for(int i=1;i<=n;++i){
            printf("%d",ans[i]);
            if(i!=n) printf(" ");
        }
        printf("\n");
    }
    return 0;
}

 


免責聲明!

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



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