Codeforces Round #731 (Div. 3) +382

题目链接

https://codeforces.com/contest/1547

A 题意

三个二维点,不经过三号点一二号点最短路

A 思路

除非连成线且三号在正中,否则就是横纵坐标求差的绝对值和,如果连线,答案加2

A 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=200505;
	const int inf=0x3f3f3f3f;
	int n,m,k;
    int a[maxn];
    int ans;
	signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
        cin>>tn;
        while(tn--){
            int x1,y1,x2,y2,x3,y3;
            cin>>x1>>y1>>x2>>y2>>x3>>y3;
            int t=abs(x1-x2)+abs(y1-y2);
            if(x1==x2&&x1==x3&&y3!=max(max(y1,y2),y3)&&y3!=min(min(y1,y2),y3))  t+=2;
            if(y1==y2&&y1==y3&&x3!=max(max(x1,x2),x3)&&x3!=min(min(x1,x2),x3))  t+=2;
            cout<<t<<endl;
        }
	} 
						
B 题意

a-z顺序生成一个串,每次只能在之前基础上插头插尾,给你一堆串,问你是否是按这个办法生成的

B 思路

假定长为x,那么1-x的字母都必须出现一次。
之后定位a,向左向右各扫一遍,都为递增即正确。

B 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=205;
	const int inf=0x3f3f3f3f;
	int n,m,k;
    int a[maxn];
    int ans;
    int cnt[maxn];
    void solve(){
        string s;
        cin>>s;
        memset(cnt,0,sizeof cnt);
        for(auto i:s)
            cnt[i-'a']++;
        int index;
        for(int i=0;i<s.size();i++){
            if(cnt[i]!=1){
                cout<<"NO"<<endl;
                return;
            }
        }
        for(int i=0;i<s.size();i++){
            if(s[i]=='a'){
                index=i;break;
            }
        }
        for(int i=index;i;i--){
            if(s[i]<s[i-1]) continue;
            else{
                cout<<"NO"<<endl;
                return ;
            }
        }
        for(int i=index;i<s.size()-1;i++){
            if(s[i]<s[i+1]) continue;
            else{
                cout<<"NO"<<endl;
                return ;
            }
        }
        cout<<"YES"<<endl;
    }   
	signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
        cin>>tn;
        while(tn--){
            solve();
        }
	} 
						
C 题意

两个序列,要求你合并他们(不改变两个序列原顺序)。有一个初值k,要求新的序列中,每次遇0,k++,否则要求k大于等于遇到的数。输出这个合并序列或者说不存在

C 思路

双指针贪心,有0就放,全为数字就放较小的。

C 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=205;
	const int inf=0x3f3f3f3f;
	int n,m,k;
    int a[maxn];
    int b[maxn];
    int ans;
    int cnt[maxn];
    void solve(){
        cin>>k>>n>>m;
        for(int i=1;i<=n;i++)   cin>>a[i];
        for(int i=1;i<=m;i++)   cin>>b[i];
        int p1=1,p2=1;
        vector<int>v;
        while(p1<=n&&p2<=m){
            if(p1<=n&&a[p1]==0){
                v.push_back(0);
                p1++;
                continue;
            }
            if(p2<=m&&b[p2]==0){
                v.push_back(0);
                p2++;
                continue;
            }
            if(a[p1]<b[p2]){
                v.push_back(a[p1]);
                p1++;
                continue;
            }
            else{
                v.push_back(b[p2]);
                p2++;
                continue;
            }
        }
        while(p1<=n){
            v.push_back(a[p1]);
            p1++;
        }
        while(p2<=m){
            v.push_back(b[p2]);
            p2++;
        }
        for(auto i:v){
            if(i==0){
                k++;
                continue;
            }
            if(i>k){
                cout<<-1<<endl;
                return;
            }
        }
        for(auto i:v)   cout<<i<<' ';cout<<endl;
    }   
	signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
        cin>>tn;
        while(tn--){
            solve();
        }
	} 
						
D 题意

若一个序列满足所有 a[i]&a[i+1]=a[i],&为二进制或,成为growing数列,给你一个数列,且一个字典序最小的数列b,b[i]^a[i]数列growing。

D 思路

字典序最小,那么显然越晚处理越好,所有从左向右扫,扫到不满足的就处理a[i+1],对于处理,就是把a[i]有1,a[i+1]没有1的位置异或1,我们需要额外操作来顺道让后面的i+2等等满足吗?不需要,字典序最小,那样的话一定答案更劣。所以就是相当于一个二进制模拟了,熟悉二进制操作就行。

D 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=200505;
	const int inf=0x3f3f3f3f;
	int n,m,k;
    int a[maxn];
    int ans[maxn];
    void deal(int &a,int &b,int index){
        int now=1;
        while(now<=a){
            if((now&a)&&!(now&b)){
                b^=now;
                ans[index]^=now;
            }
            now<<=1;
        }
    }
	signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
        cin>>tn;
        while(tn--){
            cin>>n;
            memset(ans,0,sizeof ans);
            for(int i=1;i<=n;i++)
                cin>>a[i];
            for(int i=1;i<n;i++){
                if((a[i]&a[i+1])!=a[i]){
                    deal(a[i],a[i+1],i+1);
                }
            }
            for(int i=1;i<=n;i++)
                cout<<ans[i]<<' ';
            cout<<endl;
        }
	} 
						
E 题意

一维数组有空调,第i个空调会将他的格子位置设成温度t[i],远离一个格子是t[i]+1,以此类推。每个格子的实际温度是所有空调在这个地方的温度取最小值,输出每个格子的实际温度

E 思路

两个数组初值全为inf。从左到右从右到左分别扫一遍,扫的过程中如果没空调就是上个格子温度+1,否则就是和新空调取个min。两边扫完每个格子取个min即可。

E 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=300005;
	const int inf=0x3f3f3f3f;
	int n,m,k;
    int a[maxn],t[maxn];
    int le[maxn],rt[maxn];
    vector<int>ans;
	signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
        cin>>tn;
        while(tn--){
            cin>>n>>k;
            for(int i=0;i<=n+5;i++)
                le[i]=rt[i]=inf;
            ans.clear();
            for(int i=1;i<=n;i++)   a[i]=0;
            for(int i=1;i<=k;i++){
                int t;
                cin>>t;
                a[t]=i;
            }
            for(int i=1;i<=k;i++)   cin>>t[i];
            int dis=0;
            for(int i=1;i<=n;i++){
                if(!a[i]){
                    le[i]=le[i-1]+1;
                }
                else{
                    if(t[a[i]]<le[i-1]+1){
                        le[i]=t[a[i]];
                    }
                    else
                        le[i]=le[i-1]+1;
                }
            }
            for(int i=n;i;i--){
                if(!a[i]){
                    rt[i]=rt[i+1]+1;
                }
                else{
                    if(t[a[i]]<rt[i+1]+1){
                        rt[i]=t[a[i]];
                    }
                    else
                        rt[i]=rt[i+1]+1;
                }
            }
            for(int i=1;i<=n;i++)
                cout<<min(le[i],rt[i])<<' ';
            cout<<endl;
        }
	} 
						
F 题意

数组进行操作,每次操作将a[i]变成a[i]与a[i+1]的gcd。如果是a[n]就是和a[1]取。问多少次后全相同

F 思路

容易发现

  • 答案有单调性,且范围为0-n
  • 操作了i次,相当于原数组i个相邻数取gcd.

二分答案,每次枚举位置判断区间gcd,区间gcd可以用ST表求。
复杂度 O ( n ∗ l o g 2 n ) O(n*log^2n) Onlog2n

F 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=200505;
	const int inf=0x3f3f3f3f;
	int n,m,k;
    int a[maxn];
    int ans;
    unordered_map<int,bool>mp;
    int ST[maxn][20];//ST ij means the max number form i to i+pow 2 j  
	//20 is log 2 maxn,maxn 1000000 ok
	
	
	void preST(int len){
		for(int i=1;i<=len;i++)
			ST[i][0]=a[i];
		int t=log(len)/log(2)+1;
		for(int j=1;j<t;j++)
			for(int i=1;i<=len-(1<<j)+1;i++)
				ST[i][j]=__gcd(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
	}
	
	int query(int l,int r){
		int k=log(r-l+1)/log(2);//pow 2 k is lower than l-r+1 
		return __gcd(ST[l][k],ST[r-(1<<k)+1][k]);
	}
    bool check(int k){
        mp.clear();
        int cnt=0;
        for(int i=1;i<=n;i++){
            int t;
            if(i+k-1<=n)
                t=query(i,i+k-1);
            else
                t=__gcd(query(i,n),query(1,k-n+i-1));
            if(!mp[t]){
                mp[t]=1;
                cnt++;
            }
            if(cnt>1)   return 0;
        }
        return cnt;
    }
	signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
        cin>>tn;
        while(tn--){
            cin>>n;
            for(int i=1;i<=n;i++)
                cin>>a[i];
            preST(n);
            int l=0,r=n,mid;
            while(l<r){
                mid=(l+r)/2;
                if(check(mid)){
                    r=mid;
                }
                else{
                    l=mid+1;
                }
            }
            if(r)r--;
            cout<<r<<endl;
        }
	} 
								
G 题意

有自环有向图,输出1号点对每个点的可达情况,其中

  • 0 不可达
  • 1 唯一可达
  • 2 多种方案可达
  • -1 无穷方案可达
G 思路

SCC缩点,拓扑排序+dp,不可达就是拓扑序在1之前,也就是scc编号在1之后。唯一可达就是传递方案最后dp值为1,多种可达就是传递方案dp为>1数字。无穷可达就是1到它的传递路径上途径某个size大于1的SCC块或者某个自环点,这个情况把dp设成inf,传递时直接相等不要加和。细节很多。

官方题解有别的做法,等待更新。

G 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=1000005;
    const int maxe=1000005;
	const int inf=0x3f3f3f3f;
    int n,m;
    int dfn[maxn],low[maxn],dfncnt;
    int in_stack[maxn];
    int scc[maxn],sc;
    int sz[maxn];
    vector<int>p[maxn];
	int cnt;
	int head[maxe];
    int ans[maxn];
	struct Edge{
		int next;
		int to;
        int form;
		int dis; 
	} edge[maxe]; 
	bool it[maxn],it_scc[maxn];
    int in[maxn];
    vector<int>e[maxn];
    int sc_1;
	void init(){
		memset(head,-1,sizeof(ll)*(n+15));
        memset(ans,0,sizeof(ll)*(n+15));
        memset(sz,0,sizeof(ll)*(n+15));
        memset(it,0,sizeof(ll)*(n+15));
        memset(it_scc,0,sizeof(ll)*(n+15));
        memset(in,0,sizeof(ll)*(n+15));
        memset(dfn,0,sizeof(ll)*(n+15));
        cnt=0;sc=0;dfncnt=0;
        for(int i=0;i<n+15;i++)e[i].clear();
	}
	void add(int u,int v,int w){
		edge[cnt].dis=w;
		edge[cnt].to=v;
        edge[cnt].form=u;
		edge[cnt].next=head[u];
		head[u]=cnt++;
	}

    stack<int>sa;
    void tarjan(int u) {
        low[u] = dfn[u] = ++dfncnt;
        sa.push(u);  in_stack[u] = 1;
        for (int i = head[u]; ~i; i = edge[i].next) {
            int v = edge[i].to;
            if (!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            } 
            else if (in_stack[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if (dfn[u] == low[u]) {
            ++sc;
            while (1) {
                int now=sa.top();
                sa.pop();
                if(now==1)sc_1=sc;
                if(it[now])it_scc[sc]=1;
                scc[now] = sc;
                sz[sc]++;
                p[sc].push_back(now);
                in_stack[now] = 0;
                if(now==u){
                    break;
                }
            }
        }
    }
    signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
        cin>>tn;
        while(tn--){
            cin>>n>>m;
            init();
            while(m--){
                int u,v;
                cin>>u>>v;
                if(u==v)
                    it[u]=1;
                else
                    add(u,v,0);
            }
            for(int i=1;i<=n;i++){
                if(!dfn[i]) tarjan(i);
            }
            for(int i=0;i<cnt;i++){
                if(scc[edge[i].to]!=scc[edge[i].form]){
                    e[scc[edge[i].form]].push_back(scc[edge[i].to]);
                    in[scc[edge[i].to]]++;
                }
                
            }
            ans[sc_1]=1;
            for(int i=1;i<=sc;i++)
                if((sz[i]>1||it_scc[i]))  ans[i]=-inf;

            
            for(int i=sc;i>sc_1;i--)
                ans[i]=0;
            for(int i=sc_1;i>=1;i--){
                
                for(auto y:e[i]){
                    if(ans[i]<0)
                        ans[y]=-inf;
                    else if(ans[i]==0){
                        ans[y]=0;
                    }
                    else{
                        if(ans[y]<2)
                            ans[y]+=ans[i];
                    }
                }
            }
            for(int i=1;i<=n;i++)
                if(!ans[scc[i]])    cout<<0<<' ';
                else if(ans[scc[i]]==1) cout<<1<<' ';
                else if(ans[scc[i]]>1)  cout<<2<<' ';
                else                    cout<<-1<<' ';
            cout<<endl;
        }
	} 
						
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值