zoukankan      html  css  js  c++  java
  • 10-8 王小呆的校内互坑赛题解

    money

    可以发现一条边被允许走无数次,再经过分析可以知道,对于一个环上的边,可以一直走走走,直到将环上所有的边所有的钱全部得到。所以我们可以先找环,这个过程用Tarjan实现,找到所有的环之后,将环缩成一个点,这个时候需要将环上所有的边的边权加到缩点之后的点上。(注意,这里的边权指的是通过恢复系数累加直至钱数为零时的总和)。之后就会发现我们得到的是一个无环的有向图,那就在跑一遍带点权的最长路即可。(数据并没有卡SPFA,因为出题人不会卡。。。)所以可以放心的跑最短路,又因为题目并没有给出明确的终点,所以需要O(n)枚举每个点的答案,取最大值。

    说几个需要注意的问题吧,这道题的思路其实很简单,不过出题人认为代码是比较复杂的,在代码实现过程中,我们需要先Tarjan缩点找出所有的环,在这个过程中只需要标记每个点属于哪一个强连通分量即可。接着,需要再去枚举每一个点的出边,判断每条边两端的点是否属于同一个强连通分量。如果不是,就连一条新的边,边权等于原来这条边的边权。(就等同于将所有的强连通分量之间连边)。在做完以上一系列工作之后,再跑一遍带点权的最长路,std用的是SPFA,不过堆优化DijA掉这道题也是没有问题的。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    using namespace std;
    inline int read(){
        int sum=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            sum=(sum<<1)+(sum<<3)+ch-'0';
            ch=getchar();
        }
        return sum*f;
    }
    const int wx=300017;
    int num,Num,n,m,s,x,y,z,tot,top,col,ans;
    double c;
    int head[wx],Head[wx],vis[wx],a[wx],dfn[wx],low[wx],size[wx],belong[wx],st[wx],dis[wx];
    struct e{
        int nxt,to,dis,Dis;
        double c;
    }edge[wx*2];
    void add(int from,int to,int dis,double c){
        edge[++num].nxt=head[from];
        edge[num].to=to;
        edge[num].dis=dis;
        edge[num].Dis=dis;
        edge[num].c=c;
        head[from]=num;
    }
    struct E{
        int nxt,to,dis;
    }Edge[wx*2];
    void Add(int from,int to,int dis){
        Edge[++Num].nxt=Head[from];
        Edge[Num].to=to;
        Edge[Num].dis=dis;
        Head[from]=Num;
    }
    void Tarjan(int u){
        dfn[u]=low[u]=++tot;
        st[++top]=u;
        for(int i=head[u];i;i=edge[i].nxt){
            int v=edge[i].to;
            if(!dfn[v]){
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(!belong[v])low[u]=min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u]){
            belong[u]=++col;
            size[col]++;
            while(st[top]!=u){
                belong[st[top]]=col;
                size[col]++;
                top--;
            }
            top--;
        }
    }
    void XJB(){
        for(int u=1;u<=n;u++){
                for(int i=head[u];i;i=edge[i].nxt){
                    int v=edge[i].to;
                    if(belong[v]==belong[u]){
                        int tmp=edge[i].Dis;
                        while(tmp){
                            tmp=(int)tmp*edge[i].c;
                            edge[i].dis+=tmp;
                        }
                    }
                }
        }
    }
    void WTM(){
        for(int u=1;u<=n;u++){
            for(int i=head[u];i;i=edge[i].nxt){
                int v=edge[i].to;
                if(belong[v]==belong[u]){
                    a[belong[u]]+=edge[i].dis;
                }
            }
        }
        for(int u=1;u<=n;u++){
            for(int i=head[u];i;i=edge[i].nxt){
                int v=edge[i].to;
                if(belong[u]!=belong[v]){
                    Add(belong[u],belong[v],edge[i].dis);
                }
            }
        }
    }
    queue<int > q;
    void SPFA(int s){
        for(int i=1;i<=col;i++)dis[i]=0,vis[i]=0;
        vis[s]=1;q.push(s);dis[s]=a[s];
        while(q.size()){
            int u=q.front();q.pop();
            vis[u]=0;
            for(int i=Head[u];i;i=Edge[i].nxt){
                int v=Edge[i].to;
                if(dis[v]<dis[u]+Edge[i].dis+a[v]){
                    dis[v]=dis[u]+Edge[i].dis+a[v];
                    if(!vis[v]){
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
    }
    void get_ans(){
        for(int i=1;i<=col;i++){
            ans=max(ans,dis[i]);
        }
        printf("%d
    ",ans);
    }
    int main(){
    //	freopen("money004.in","r",stdin);
    //	freopen("money004.out","w",stdout);
        n=read();m=read();
        for(int i=1;i<=m;i++){
            x=read();y=read();z=read();scanf("%lf",&c);
            add(x,y,z,c);
        }
        s=read(); 
        for(int i=1;i<=n;i++){
            if(!dfn[i])Tarjan(i);
        }
        XJB();
        WTM();
        SPFA(belong[s]);
        get_ans();
        return 0;
    } 
    
    

    dream

    发现这是一道数学题。

    具体来说就是求满足$ a^x equiv 1(mod n)$的最小x值加上1

    那么怎么求呢?

    知不知道欧拉定理?其实这就是一道简单的欧拉定理板子题。

    设gcd(a,m)=1,必有正整数x,使得a^x=1(mod m),且设满足等式的最小正整数为x0,必满足x0|phi(m).注意m>1.

    否则如果gcd(a,m)!=1,则方程a^x=1(mod m)没有解。

    欧拉定理:(a^{(φ(n))}equiv 1(mod n))

    证明过程:

    ​ 所有小于等于n并且与n互质的数按大小顺序排布,我们可以设为:(x_1,x_2……x_{φ(n)})。显然,一共有φ(n)个数。

    ​ 接下来我们考虑这么一些数:

    ​ 设(m_1=a*x_1,m_2=a*x_2……m_{φ(n)}=a*x_{φ(n)})

    ​ 可以得出以下几个结论:

    (1.)这些数中的任意两个都不模n同余,因为如果存在(m_{one}equiv m_{two}(mod n)),就会有:(m_{one}-m_{two}=a*(x_{one}-x_{two})=k*n),即n能整除(a*(x_{one}-x_{two}))。但是a和n互质,即a与n的最大公约数为1,然而(x_{one}-x_{two})小于n,因而等式左边不可能被n整除。也就是说:这些数中任意两个都不会模n同余,即φ(n)个数关于n会有φ(n)个余数。

    (2.)这些数关于n的余数都与n互质,因为如果存在:余数与n有公因子r,那么(a*x_i=p*n+q*r=r*(……)),说明a*x_i与n不互质(即存在公约数r不为1),但显然,这是不可能的,那么这些数关于n的余数,全部都在(x_1,x_2……x_{φ(n)})中,因为这些数代表的即是所有小于等于n的与n互质的数。

    ​ 那么,由(1)(2)可知 ,数(m_1,m_2……m_{φ(n)})必须相应地对应地关于n同余于(x_1,x_2……x_{φ(n)})

    ​ 所以得出:(m_1*m_2*m_3*……*m_{φ(n)} equiv x_1*x_2*x_3……x_{φ(n)}(mod n))

    ​ 换一种表达方式可以是:(a^{[φ(n)]}*(x_1*x_2*……*x_{φ(n)})equiv (x_1*x_2*……*x_{φ(n)}))

    ​ 为了更加方便,我们设K为((x_1*x_2*……*x_{φ(n)})),就又可以表示为:(K*(a^{φ(n)}-1)equiv0(mod n))

    ​ 这些都是成立的。

    ​ 所以可得(K*(a^{φ(n)}-1))被n整除,但是K中的因子(x_1,x_2……x_{φ(n)})都与n互质,那么K也与n互质,所以((a^{φ(n)}-1))必须能被n整除,即又可得((a^{φ(n)}-1)equiv0(mod n))成立,即得(a^{φ(n)}equiv1(mod n)),得证。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int wx=1000017;
    int isprime[wx],prime[wx],phi[wx];
    int a,n,tot,t;
    int gcd(int a,int b){
    	return !b?a:gcd(b,a%b);
    }
    int euler_phi(int n){
    	int m = floor(sqrt(n+0.5));
    	int ans = n;
    	for(int i = 2; i <= m; i++)
    	if(n%i == 0){
    	    ans = ans / i * (i-1);        
    		while(n%i == 0){
    		n /= i; }   
    		}    
    	if(n > 1) ans = ans / n *(n-1);    
    	return ans;
    }
    int ksm(int a,int b,int mod){
    	int re=1;
    	while(b){
    		if(b&1)re=re*a%mod;
    		a=a*a%mod;
    		b>>=1;
    	}
    	return re;
    }
    int Fastgcd(int a, int b){
        if (a == 0) return b;
    	if (b == 0) return a;
    	if (!(a & 1) && !(b & 1))      
    	return Fastgcd(a>>1, b>>1)<<1;    
    	else if (!(b & 1))    
    	return Fastgcd(a, b>>1);    
    	else if (!(a & 1)) return Fastgcd(a>>1, b);    
    	else return Fastgcd(abs(a - b), min(a, b));
    }
    signed main(){
    //	freopen("dream.in","r",stdin);
    //	freopen("dream.out","w",stdout);
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d%d",&a,&n);
    		if(Fastgcd(a,n)!=1){
    			printf("w_x_c_q is living in a dream
    ");
    		}
    		else{
    			int tmp=euler_phi(n);
    			int ans=9999999999999LL;
    			for(int i=1;i*i<=tmp;i++){
    				if(tmp%i)continue;
    				if(ksm(a,i,n)==1)ans=min(ans,i);
    				if(ksm(a,tmp/i,n)==1)ans=min(ans,tmp/i);
    			}
    			printf("%d
    ",ans);
    		}
    	}
    	return 0;
    }
    

    hope

    二维偏序简单题。

    将A排序,把A+B作为B。

    保证A有序,将B放到树状数组,每次查询就行了。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    const int wx=200177;
    int sum[wx];
    int n,ans;
    struct node{
    	int a,b;
    	friend bool operator < (const node& a,const node & b){
    		return a.a<b.a;
    	}
    }t[wx];
    void add(int pos,long long k){
    	for(int i=pos;i<=n*2;i+=(i&-i)){
    		sum[i]+=k;
    	}
    }
    int query(int x){
    	long long re=0;
    	for(int i=x;i>=1;i-=(i&-i)){
    		re+=sum[i];
    	}
    	return re;
    }
    int main(){
    	freopen("hope001.in","r",stdin);
    	freopen("hope001.out","w",stdout);
    	n=read();
    	for(int i=1,x;i<=n;i++){
    		t[i].a=read();x=read();
    		t[i].b=t[i].a+x;
    	}
    	sort(t+1,t+1+n);
    	for(int i=1;i<=n;i++){
    		ans+=(query(t[i].b-1)-query(t[i].a-1)); 
    		add(t[i].b,1);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Nginx 部署多个 web 项目(虚拟主机)
    Nginx 配置文件
    Linux 安装 nginx
    Linux 安装 tomcat
    Linux 安装 Mysql 5.7.23
    Linux 安装 jdk8
    Linux 安装 lrzsz,使用 rz、sz 上传下载文件
    springMVC 拦截器
    spring 事务
    基于Aspectj 注解实现 spring AOP
  • 原文地址:https://www.cnblogs.com/wangxiaodai/p/9756307.html
Copyright © 2011-2022 走看看