zoukankan      html  css  js  c++  java
  • The Preliminary Contest for ICPC Asia Nanjing 2019

    A.The beautiful values of the palace

    首先对于每个((x,y)),我们可以(O(1))的查询出这个坐标的值。接下来就将问题转化为了一个(10^6 cdot 10^6)的矩阵,每次查询子矩阵内的点的和。

    考虑将所有的(y)离散化,计(mp_{i,j})表示((1,1)-(i,j))的和,那么对于((x_1,y_1)->(x_2,y_2)),答案即为
    (mp_{x_2,y_2}-mp_{x_1-1,y_2}-mp_{x_2,y1-1}+mp_{x_1-1,y_1-1})

    考虑离线做法:
    把所有的点按照(x)从小到达排序,每加入一个点,利用树状数组插入,每次查询,利用树状数组查询四个前缀和即可。时间复杂度((m+4p) cdot log(m+4p))

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e6+100;
    const int mod = 1e9+7;
    typedef long long ll;
    const int INF = 0x3f3f3f3f;
    const ll llINF = 0x3f3f3f3f3f3f3f3f;
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define fep(i,a,b) for(int i=(a);i>=(b);i--)
    inline bool read(ll &num) {
        char in;bool IsN=false;
        in=getchar();
        if(in==EOF) return false;
        while(in!='-'&&(in<'0'||in>'9')) in=getchar();
        if(in=='-'){ IsN=true;num=0;}
        else num=in-'0';
        while(in=getchar(),in>='0'&&in<='9'){
                num*=10,num+=in-'0';
        } 
        if(IsN) num=-num;
        return true;
    }
    ll T,n,p,m,c[N];
    int lowbit(ll x){
        return (x&(-x));
    }
    void add(ll x,ll v){
        for(;x<N;x+=lowbit(x)){
             c[x]+=v;
             //cout<<x<<' '<<v<<endl;
        }
    }
    ll query(ll x){
        ll ans=0;
        for(;x;x-=lowbit(x)){
            ans+=c[x];
        }
        return ans;
    }
    //BIT
    struct point{
        ll x,y;
        int flag;
    }pp[600000];
    bool cmp(point a,point b){
        if(a.x==b.x){
            if(a.y==b.y){
               return a.flag<b.flag;
            }
            return a.y<b.y;
        }
        return a.x<b.x;
    }
    
    ll dig(ll x){
        ll ans=0;
        while(x){
            ans+=x%10;
            x/=10;
        }
        return ans;
    }
    ll cal(ll x,ll y){//计算(x,y)处的值
        x=x-n/2-1;
        y=y-n/2-1;
        ll t=max(abs(x),abs(y));
        if(x>=y) return n*n-4*t*t-2*t-x-y;
        else return n*n-4*t*t+2*t+x+y;
    }
    map<pair<ll,ll>,ll> mmp;
    ll yy[N],id[N];
    ll x__1[100001],y__1[100001],x__2[100001],y__2[100001];
    int main(){
        read(T);
        while(T--){
            mmp.clear();
            read(n);read(m);read(p);
            memset(c,0,sizeof(c));
            ll x,y,x_1,y_1,x_2,y_2;
            rep(i,1,m){
                read(x);read(y);
                pp[i]={x,y,0};
            }
            rep(i,1,p){
                read(x_1);read(y_1);read(x_2);read(y_2);
                x__1[i]=x_1;y__1[i]=y_1;x__2[i]=x_2;y__2[i]=y_2;
                pp[++m]={x_1-1,y_1-1,1};
                pp[++m]={x_2,y_2,1};
                pp[++m]={x_1-1,y_2,1};
                pp[++m]={x_2,y_1-1,1};
            }
            rep(i,1,m) yy[i]=pp[i].y;
            sort(yy+1,yy+m+1);
            int siz=unique(yy+1,yy+m+1)-yy-1;
            sort(pp+1,pp+m+1,cmp);
            rep(i,1,m){
                id[i]=lower_bound(yy+1,yy+siz+1,pp[i].y)-yy;
            }
            //离散化
            rep(i,1,m){
                if(pp[i].flag==0){
                    add(id[i],dig(cal(pp[i].x,pp[i].y)));
                    //cout<<pp[i].x<<' '<<pp[i].y<<' '<<id[i]<<' '<<dig(cal(pp[i].x,pp[i].y))<<endl;
                }
                else{
                    mmp[{pp[i].x,pp[i].y}]=query(id[i]);
                    //cout<<pp[i].x<<' '<<pp[i].y<<' '<<query(id[i])<<endl;
                }
            }
            rep(i,1,p){
                //cout<<x__2[i]<<' '<<y__2[i]<<endl;
                printf("%lld
    ",mmp[{x__2[i],y__2[i]}]-mmp[{x__1[i]-1,y__2[i]}]-mmp[{x__2[i],y__1[i]-1}]+mmp[{x__1[i]-1,y__1[i]-1}]);
            }
        }
        return 0;
    }
    

    B.super_log

    计算(a^{a^{a^{a...}}} \% m),总共有(b)(a)

    直接递归欧拉降幂即可。
    降幂公式:

    [a^b \% p= egin{cases} a^{b \% phi(p)} \%p & gcd(a,p)=1\ a^b \% p & gcd(a,p) eq1 ,b < phi(p)\ a^{b \% phi(p)+phi(p)} \% p & gcd(a,p) eq 1, phi(p) leq b end{cases} ]

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 2e6+100;
    const int mod = 1e9+7;
    typedef long long ll;
    const int INF = 0x3f3f3f3f;
    const ll llINF = 0x3f3f3f3f3f3f3f3f;
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define fep(i,a,b) for(int i=(a);i>=(b);i--)
    inline bool read(ll &num) {
    	char in;bool IsN=false;
    	in=getchar();
    	if(in==EOF) return false;
    	while(in!='-'&&(in<'0'||in>'9')) in=getchar();
    	if(in=='-'){ IsN=true;num=0;}
    	else num=in-'0';
    	while(in=getchar(),in>='0'&&in<='9'){
    			num*=10,num+=in-'0';
    	} 
    	if(IsN) num=-num;
    	return true;
    }
    ll ph[N];
    void init(){
    	rep(i,1,N-10){
    		ph[i]=i;
    	}
    	rep(i,2,N-10){
    		if(ph[i]==i){
    			for(int j=i;j<=N-10;j+=i){
    				ph[j]=ph[j]/i*(i-1);
    			}
    		}
    	}
    }
    ll qpow(ll a,ll b,ll mod){
    	ll ans=1;
    	while(b){
    		if(b&1) ans=(ans%mod*a%mod)%mod;
    		a=(a%mod*a%mod)%mod;
    		b>>=1;
    	}
    	return ans%mod;
    }
    bool check(ll a,ll b,ll m){
    	if(b==0) return 1>=ph[m];
    	if(b==1) return a>=ph[m];
    	ll ans=1;
    	if(ans>=ph[m]) return 1;
    	rep(i,1,b-1){
    		rep(j,1,a){
    			ans*=a;
    			if(ans>=ph[m]) return 1;
    		}
    	}
    	return 0;
    }
    ll  solve(ll a,ll b,ll m){
    	if(m==1) return 0;
    	if(b==0) return 1%m;
    	if(b==1) return a%m;
    	if(__gcd(a,m)==1){
    		return qpow(a,solve(a,b-1,ph[m]),m);
    	}
    	else{
    		if(check(a,b-1,m)){
    			return qpow(a,solve(a,b-1,ph[m])+ph[m],m);
    		}
    		else return qpow(a,solve(a,b-1,m),m);
    	}
    }
    ll T,a,b,m;
    int main(){
    	//freopen("1.in", "r", stdin);
    	read(T);
    	init();
    	//cout<<ph[1000000]<<endl;
    	while(T--){
    		read(a);read(b);read(m);
    		printf("%lld
    ",solve(a,b,m)%m);
    	}
    	return 0;
    }
    

    D.Robots

    一个有向图,机器人从(u)可以不接着往下走,也可以随便选一个邻接点走下去,所有的情况都是等概率的,一天只能执行一次上面的操作。第(i)天执行任意操作的的花费为(i),计算从(1)(n)的期望花费。

    (day_{u})为从(u)(n)的期望天数,(cost_{u})代表(u)(n)的期望花费。
    那么有:

    [day_{u}=(day_{u}+1) cdot frac{1}{d_{u}+1}+sum{(day_{v}+1)cdot frac{1}{d_{u}+1}} ]

    那么我们就可以得到花费期望的转移:

    [cost_{u}=(cost_{u}+day_{u}+1) cdot frac{1}{d_{u}+1}+ sum{(cost_{v}+day_{v}+1)cdot frac{1}{d_{u}+1}} ]

    移项后DFS转移即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e6+100;
    const int mod = 1e9+7;
    typedef long long ll;
    const int INF = 0x3f3f3f3f;
    const ll llINF = 0x3f3f3f3f3f3f3f3f;
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define fep(i,a,b) for(int i=(a);i>=(b);i--)
    inline bool read(ll &num) {
        char in;bool IsN=false;
        in=getchar();
        if(in==EOF) return false;
        while(in!='-'&&(in<'0'||in>'9')) in=getchar();
        if(in=='-'){ IsN=true;num=0;}
        else num=in-'0';
        while(in=getchar(),in>='0'&&in<='9'){
                num*=10,num+=in-'0';
        } 
        if(IsN) num=-num;
        return true;
    }
    int T,n,m,u,v;
    double day[N],cost[N],d[N];
    bool vis[N];
    vector<int> G[N];
    double dfsa(int u){
        if(day[u]) return day[u];
        if(u==n) return day[u];
        double x=0;
        for(int v:G[u]){
            dfsa(v);
            x+=(day[v]+1)/(d[u]+1);
        }
        x+=1.0/(d[u]+1);
        return day[u]=x*(d[u]+1)/(d[u]);
    }
    double dfsb(int u){
        if(cost[u]) return cost[u];
        if(u==n) return cost[u];
        double y=0;
        for(int v:G[u]){
            dfsb(v);
            y+=(cost[v]+day[v]+1)/(d[u]+1);
        }
        y+=(day[u]+1)/(d[u]+1);
        return cost[u]=(y*(d[u]+1))/(d[u]);
    }
    int main(){
        //freopen("1.in", "r", stdin);
        scanf("%d",&T);
        while(T--){
            scanf("%d %d",&n,&m);
            rep(i,1,n){
                d[i]=0,G[i].clear();
                day[i]=cost[i]=0;
            }
            rep(i,1,m){
                scanf("%d %d",&u,&v);
                G[u].push_back(v);
                d[u]+=1.0;
            }
            dfsa(1);
            printf("%.2lf
    ",dfsb(1));
        }
        return 0;
    }
    
    

    F. Greedy Sequence

    会发现每个点的前驱都是唯一的,我们用主席树求出对于每个点的左右(k)远的区间内最大的小于这个数字的数,然后(O(n))的递推即可。

    #include<bits/stdc++.h>
    
    using namespace std;
    const int maxn = 1e5+100;
    typedef long long ll;
    struct node
    {
    	ll sum,l,r;
    }t[maxn*32];
    int cnt;
    void update(ll l,ll r,ll &x,ll y,ll pos){
    	t[++cnt]=t[y];t[cnt].sum++;x=cnt;//复制节点并且更新
    	if(l==r) return ;
    	int mid=(l+r)>>1;
    	if(mid>=pos) update(l,mid,t[x].l,t[y].l,pos);
    	else update(mid+1,r,t[x].r,t[y].r,pos);
    }
    int query(int a,int b,int x,int l,int r)
    {
    	if(l==r)
    	{
    		if(l==x)
    			return 0;
    		else
    			return l;
    	}
    	int mid=(l+r)>>1;
    	int xx=t[t[b].l].sum-t[t[a].l].sum;
    	int yy=t[t[b].r].sum-t[t[a].r].sum;
    	int res=0;
    	if(yy&&x>mid)
    		res=query(t[a].r,t[b].r,x,mid+1,r);
    	if(xx&&!res)
    		res=query(t[a].l,t[b].l,x,l,mid);
    	return res;
    }
    int a[maxn],pos[maxn],ans[maxn];
    ll roots[maxn];
    int main(){
        //freopen("1.in","r",stdin);
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
        int T;
        cin>>T;
        while(T--){
            cnt=0;
            int n,k;
            cin>>n>>k;
            for(int i=1;i<=n;i++){
                cin>>a[i];pos[a[i]]=i;
            }
            for(int i=1;i<=n;i++) update(1,n,roots[i],roots[i-1],a[i]);
            for(int i=1;i<=n;i++){
                int L=max(pos[i]-k,1);
                int R=min(pos[i]+k,n);
                int now=query(roots[L-1],roots[R],i,1,n);
                if(now==0) ans[i]=1;
                else ans[i]=ans[now]+1;
            }
            for(int i=1;i<=n-1;i++) cout<<ans[i]<<' ';
            cout<<ans[n]<<endl;
        }
        return 0;
    }
    

    H. Holy Grail

    跑6次(SPFA)即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int mod = 1e9+7;
    typedef long long ll;
    const int N = 401;
    const int INF = 0x3f3f3f3f;
    const ll llINF = 0x3f3f3f3f3f3f3f3f;
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define fep(i,a,b) for(int i=(a);i>=(b);i--)
    inline bool read(ll &num) {
        char in;bool IsN=false;
        in=getchar();
        if(in==EOF) return false;
        while(in!='-'&&(in<'0'||in>'9')) in=getchar();
        if(in=='-'){ IsN=true;num=0;}
        else num=in-'0';
        while(in=getchar(),in>='0'&&in<='9'){
                num*=10,num+=in-'0';
        } 
        if(IsN) num=-num;
        return true;
    }
    ll dis[N];
    int s,t,n,m,u,v;
    ll w;
    vector<pair<int,ll> > G[N];
    bool vis[N];
    void SPFA(int s)//若存在负环返回false
    {
        queue<int> q;
        memset(vis,0,sizeof(vis));
        rep(i,0,n) dis[i]=llINF;
        dis[s]=0;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            vis[u]=0;
            for(auto V:G[u]){
                int v=V.first;ll w=V.second;
                if(dis[v]>dis[u]+w){
                    dis[v]=dis[u]+w;
                    if(!vis[v]){
                        q.push(v);
                        vis[v]=1;
                    }
                }
            }
        }
        return ;
    }
    int main(){
       //freopen("1.in", "r", stdin);
        int T;
        scanf("%d",&T);
        while(T--){
            rep(i,0,n) G[i].clear();
            scanf("%d %d",&n,&m);
            rep(i,1,m){
                scanf("%d %d %lld",&u,&v,&w);
                G[u].push_back({v,w});
            }
            rep(i,1,6){
                scanf("%d %d",&s,&t);
                SPFA(t);
                printf("%lld
    ",-dis[s]);
                G[s].push_back({t,-dis[s]});
            }
        }
        return 0;
    }
    
  • 相关阅读:
    从马琳决赛被翻盘想到的
    C语言中的位运算
    瑞星杀毒软件所有监控已禁用!
    回来了,重新开始
    使用 javascript 标记高亮关键词
    我的webgis客户端引擎AIMap
    RPM 命令大全
    终结IE6下背景图片闪烁问题
    linux下挂载硬盘光驱和U盘
    在JavaScript中实现命名空间
  • 原文地址:https://www.cnblogs.com/codancer/p/12232409.html
Copyright © 2011-2022 走看看