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;
    }
    
  • 相关阅读:
    【郑轻邀请赛 G】密室逃脱
    【郑轻邀请赛 C】DOBRI
    【郑轻邀请赛 F】 Tmk吃汤饭
    【郑轻邀请赛 I】这里是天堂!
    【郑轻邀请赛 B】base64解密
    【郑轻邀请赛 A】tmk射气球
    【郑轻邀请赛 H】 维克兹的进制转换
    解决adb command not found以及sdk环境配置
    adb shell 命令详解,android, adb logcat
    Unexpected exception 'Cannot run program ... error=2, No such file or directory' ... adb'
  • 原文地址:https://www.cnblogs.com/codancer/p/12232409.html
Copyright © 2011-2022 走看看