zoukankan      html  css  js  c++  java
  • 2018-2019 ACM-ICPC, NEERC, Southern Subregional Contest, Qualification Stage

    Solved


    Solution


    Problem A. Coffee Break
    • 贪心,对需求时间进行排序。
    • 使用优先队列取出当前所有天的最晚时刻的最小值,如果没有一天是满足条件的,则在重新开一天,否则加入那一天即可。
      代码:
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=2e6+10;
    struct node{
    	ll a;
    	int id;
    }s[maxn];
    bool cmp1(node x,node y)
    {
    	return x.a<y.a;
    }
    ll ans[maxn];
    typedef pair<ll,ll> pre;
    struct cmp{
    	bool operator ()(const pre p1,const pre p2){
    		return p1.second>p2.second; 
    	}
    };
    
    ll num[maxn];
    int main(){
    	priority_queue< pre,vector<pre>,cmp >q;
    	ll n,m,d;
    	cin>>n>>m>>d;
    	for(int i=1;i<=n;i++){
    		scanf("%lld",&s[i].a);
    		s[i].id=i;
    	}
    	sort(s+1,s+n+1,cmp1);
    	q.push(make_pair(1,s[1].a));
    	ans[s[1].id]=1;
    	int day=1;
    	for(int i=2;i<=n;i++){
    		//cout<<q.top().first<<endl;
    		if(q.top().second+d+1>s[i].a){
    			day++;
    			q.push(make_pair(day,s[i].a));
    			ans[s[i].id]=day;
    		}else{
    			int dd=q.top().first;
    			q.pop();
    			ans[s[i].id]=dd;
    			q.push(make_pair(dd,s[i].a));
    		}
    	}
    	 
    	printf("%d
    ",day);
    	for(int i=1;i<=n;i++){
    		printf("%lld%c",ans[i]," 
    "[i==n]);
    	}
    }
    
    
    Problem B. Glider
    • 为了使飞机平滑的时间尽量多,那么每次飞机的起点一定是某个可平滑的线段的 (l) 段,高度一定是最大高度。
    • 然后我们就可以通过枚举飞机的起点,去求出飞机的飞行距离。
    • 由于是取一些平滑线段,想到可以用取尺法。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=2e6+10;
    
    ll l[maxn],r[maxn];
    map<ll,ll>sum;
    int main()
    {
    	int n;
    	ll h;
    	scanf("%d %lld",&n,&h);
    	for(int i=1;i<=n;i++){
    		scanf("%lld %lld",&l[i],&r[i]);
    		l[i]+=1e9;
    		r[i]+=1e9; 
    	}
    	sum[l[1]]=0;
    	sum[r[1]]=0;
    	for(int i=2;i<=n;i++){
    		sum[l[i]]=-(l[i]-r[i-1]);
    		sum[r[i]]=sum[l[i]];
            //cout<<"xx"<<sum[l[i]]<<" "<<sum[r[i]]<<endl;
    	}
    	ll l1=0,r1=0;
    	ll ans=0;
    	ll sumx=h;
    	ll num=0;
    	for(l1=1,r1=1;l1<=n;l1++){
    		if(l1>1){
    			sumx+=(l[l1]-r[l1-1]);
    			//num+=r[r1]-l[r1-1];
    			num=r[r1]-l[l1];
    		}
    		//cout<<"xx"<<sumx<<endl;
    		while(r1<n&&sumx>0){
                r1++;
    			if(sumx+sum[l[r1]]<=0){
                    r1--;
    				//cout<<sumx<<" "<<num<<endl;
    				ans=max(ans,num+sumx);
    				//cout<<l1<<" "<<r1<<" "<<ans<<endl;
    				break;
    			}
    			num=r[r1]-l[l1];
                //cout<<l1<<" "<<num<<endl;
    			sumx+=sum[l[r1]];
    			//cout<<"xx"<<sum[r[r1]]<<endl;
    		}
    		//cout<<"xx"<<num<<endl;
    		//cout<<l1<<" "<<r1<<endl; 
    		if(sumx>0){
                if(n==1){
                    ans=max(ans,r[1]-l[1]+sumx);
                }
    			//cout<<sumx<<" "<<num<<endl;
    			ans=max(ans,num+sumx);
    		    //cout<<l1<<" "<<r1<<" "<<ans<<endl;
    		}
    	}
    	cout<<ans<<endl; 
    }
    
    Problem C. Bacteria
    • 暴力解决或者找规律即可。

    代码:

    ll ok(ll x){
    	ll y=1;
    	while(1){
    		//cout<<y<<endl;
    		if(x>=y){
    			y*=2;
    		}
    		else{
    			break;
    		}
    	}
    	return y/2;
    }
    ll a[200005];
    void run()
    {
    	int n;
    	cin>>n;
    	for(int i=1;i<=n;i++)
    	{
    		cin>>a[i];
    	}
    	sort(a+1,a+1+n);
    	int pp = a[1];
    	for(int i=1;i<=n;i++)
    	{
    		int xx = a[i]/pp;
    		if(a[i]%a[1]!=0)
    		{
    			puts("-1");
    			return;
    		}
    		while(xx%2==0)
    		{
    			xx/=2;
    		}
    		//cout<<xx<<endl;
    		if(xx!=1)
    		{
    			puts("-1");
    			return;
    		}
    		a[i] = a[i]/pp;
    	}
    	ll sum = 0;
    	for(int i=1;i<=n;i++)
    	{
    		sum+=a[i];
    	}
    	ll xx = 1;
    	while(xx<sum)
    	{
    		xx*=2;
    	}
    	ll ans = xx - sum;
    //	cout<<ans<<endl;
    	ll yy=xx/2;
    	ll num=0;
    	while(ans>1){
    		//cout<<ok(ans)<<endl;
    		ans-=ok(ans);
    		//cout<<ans<<endl;
    		num++;
    	}
    //	cout<<num<<endl;
    	if(ans==1) num++;
    	cout<<num<<endl;
     } 
    signed main()
    {
        //std::ios::sync_with_stdio(false);
        run();
     } 
    
    Problem D. Masquerade strikes back
    • 对于某个数,每次找到一组两两不相等就代表这个数有两对可以符合。
    • 那么每次只需要通过暴力寻找可以整除某个数的数。
    • 复杂度 (O(n imes sqrt(10000000)))

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=2e6+10;
    
    struct node{
        int x,y;
    }ans[maxn];
    int num1[10000000+10];
    int num2[10000000+10];
    int c[maxn];
    int n;
    
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%d",&c[i]);
            num1[c[i]]=1;
        }
        int k=1;
        for(int i=1;i<=n;i++){
            if(num2[c[i]]>0){
                ans[i].x=num2[c[i]];
                ans[i].y=c[i]/num2[c[i]];
                if(num2[c[i]]*num2[c[i]]!=c[i]&&num2[c[i]]<c[i]/num2[c[i]]){
                    num2[c[i]]=c[i]/num2[c[i]];
                }else{
                    num2[c[i]]=0;
                }
            }else{
                while(1){
                    if(num1[c[i]]*num1[c[i]]>c[i]){
                        k=0;
                        break;
                    }else{
                        if(c[i]%num1[c[i]]==0){
                            num2[c[i]]=num1[c[i]];
                            num1[c[i]]++;
                            break;
                        }else{
                            num1[c[i]]++;
                        }
                    }
                }
                if(k==0)break;
                i--;
                continue;
            }
        }
        if(k){
            printf("YES
    ");
            for(int i=1;i<=n;i++){
                printf("%d %d
    ",ans[i].x,ans[i].y);
            }
        }else{
            printf("NO
    ");
        }
    }
    
    Problem E. Painting the Fence
    • 首先我们用 (set) 维护某个颜色的位置。
    • 当我们需要操作某个颜色是,那么我们需要涂色的区域就是 (set) 的最大值和最小值,即 (*st.begin()) ~ (*st.rbegin())
    • 我们枚举这个区间,如果发现这个区间内出现了被操作过的区间,那么我们就可以直接跳到这个被操作过区间的末尾即可。否则就把原本这位置上的颜色的 (set) 删除这个位置。
    • 在染色完以后标记已经染过的颜色即可。
    • 每个点最多被访问两次,复杂度 (O(nlog(n)))

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=3e5+10;
    
    set<int>st[maxn];
    int col[maxn];
    int n,m;
    int ans[maxn];
    int vis[maxn];
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%d",&col[i]);
            st[col[i]].insert(i);
        }
        cin>>m;
        for(int i=1;i<=m;i++){
            int temp;
            scanf("%d",&temp);
            if(st[temp].size()<2||vis[temp]){
                vis[temp]=1;
                continue;
            }
            int l=*(st[temp].begin()),r=*(st[temp].rbegin());
            for(int j=l+1;j<r;j++){
                st[col[j]].erase(j);
                if(vis[col[j]]&&st[col[j]].size()>=1){
                    j=*(st[col[j]].rbegin());
                    st[col[j]].erase(j);
                }
            }
            vis[temp]=1;
        }
        for(int i=1;i<=maxn-5;i++){
            if(st[i].size()!=0&&vis[i])
            for(int j=*(st[i].begin());j<=*(st[i].rbegin());j++){
                col[j]=i;
            }
        }
        for(int i=1;i<=n;i++){
            printf("%d%c",col[i]," 
    "[i==n]);
        }
    }
    
    Problem F. Tickets
    • 枚举 (0) ~ (999999) 求出前三位和减去后三位和的绝对值,然后每次记录这些绝对值,然后遍历到哪个数,就可以求出对于那个数的答案。

    代码:

    int sum(int num)
    {
    	int x1=0,x2=0,pos=1;
    	while(num>0){
    		int x=num%10;
    		num/=10;
    		if(pos<=3){
    			x1+=x; 
    		}else{
    			x2+=x;
    		}
    		pos++;
    	}
    	return abs(x2-x1);
    }
    int a[maxn];
    int p[maxn];
    void init()
    {
    	for(int i=0;i<=999999;i++){
    		for(int j=0;j<sum(i);j++){
    			p[i]+=a[j];
    		}
    		a[sum(i)]++;	
    	}
    }
    void run()
    {
    	init();
    	int num;
    	int t = rd();
    	while(t--)
    	{
    		scanf("%d",&num);
    		printf("%d
    ",p[num]); 
    	}
    	
     } 
    signed main()
    {
        //std::ios::sync_with_stdio(false);
        run();
     } 
    
    Problem G. Tree Reconstruction
    • 首先考虑权值最大的点,对于每条边,一定有一个值等于 (n)
    • 考虑构成一条链。
    • 将每条边的值变成前面小、后面大的,后面大值可以保证一定是 (n)
    • 然后将每条边按小权值从大到小排序,从前往后遍历。
    • 如果遇到当前权值被使用了,就去找一个没有被使用的较小的权值,否则就没有答案。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=3e5+10;
    
    struct node{
        int l,r;
    }s[1005];
    bool cmp(node a,node b)
    {
        return a.l<b.l;
    }
    int have[1005];
    vector<int>v;
    int main()
    {
        int n;
        cin>>n;
        int k=1;
        for(int i=1;i<n;i++){
            scanf("%d%d",&s[i].l,&s[i].r);
            if(s[i].l>s[i].r)swap(s[i].l,s[i].r);
            if(max(s[i].l,s[i].r)!=n){
                k=0;
            }
        }
        sort(s+1,s+n,cmp);
        if(k==0){
            printf("NO
    ");
            return 0;
        }
        int maxx;
        for(int i=1;i<n;i++){
            if(have[s[i].l]==0){
                v.push_back(s[i].l);
                have[s[i].l]++;
            }else{
                for(int j=1;j<=n;j++){
                    if(have[j]==0){
                        if(j>s[i].l){
                            k=0;
                            break;
                        }
                        v.push_back(j);
                        have[j]++;
                        break;
                    }
                }
            }
            if(k==0)break;
        }
        v.push_back(n);
        have[n]++;
        for(int i=1;i<=n;i++){
            if(have[i]==0||have[i]>1){
                k=0;
                break;
            }
        }
        if(k==0||v.size()!=n){
            printf("NO
    ");
        }else{
            printf("YES
    ");
            for(int i=0;i<n-1;i++){
                printf("%d %d
    ",v[i],v[i+1]);
            }
        }
    }
    
    Problem H. Theater Square
    • 考虑部分被覆盖的那几行中,前面部分和后面部分奇偶性,以及列数的奇偶性得出答案。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=2e6+10;
    
    int main()
    {
    	int n,m,sum=0;
    	int x1,y1,x2,y2;
    	cin>>n>>m;
    	cin>>x1>>y1>>x2>>y2;
    	int d=(x2-x1+1);
    	if(y1%2==0)sum+=d;
    	if((m-y2)%2==1)sum+=d;
    	if(m%2==1){
    		sum+=(n-d);
    	} 
    	printf("%d
    ",sum/2+(sum%2));
    }
    
    Problem J. Buying a TV Set
    • 先约分,然后取比例最小的得到答案即可。
    • 队友的二分答案也可以。
    void run()
    {
    	ll a,b,x,y;
    	cin>>a>>b>>x>>y;
    	ll ans = __gcd(x,y);
    	ll xx = x/ans;
    	ll yy = y/ans;
    	ll maxx1 = a/xx,maxx2 = b/yy;
    	if(min(maxx1,maxx2) == 0)
    	{
    		puts("0");
    		return;
    	}
    	ll left = 0,right = min(maxx1,maxx2);
    	ll maxx = 0;
    	while(left <= right)
    	{
    		ll mid = (left + right)>>1;
    		if(xx*mid<=a&&yy*mid<=b)
    		{
    			left = mid + 1;
    			maxx = max(maxx,mid);
    		}
    		else
    		{
    			right = mid - 1; 
    		} 
    	}
    	cout<<maxx<<endl;
     } 
    signed main()
    {
        //std::ios::sync_with_stdio(false);
        run();
     } 
    
    Problem K. Medians and Partition
    • 考虑满足条件的子数组一定是大于等于 (m) 的数比小于 (m) 的数至少多一个。
    • 那么我们求出大于等于 (m) 的数为 (a)个,小于 (m) 的数为 (b) 个,那么答案就是 (max(0,a-b))

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int main(){
    	int n,m,k;
    	scanf("%d%d ",&n,&m);
    	int a=0,b=0;
    	while(n--){
    		scanf("%d",&k);
    		if(k>=m) a++;
    		else b++;
    	}
    	printf("%d
    ",max(a-b,0));
    }
    
    Problem L. Ray in the tube
    • 考虑暴力,对每种距离进行枚举,然后求出答案。但这样暴力一定超时。
    • 考虑每种距离一定由 (2^n) ((0<=n<=MAXN))组成 ,那么枚举 (2^n)即可。
    • 时间复杂度 (O(nlog(1e9)))

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=3e5+10;
    
    int x1[maxn],x2[maxn];
    map<int,int>mp;
    int main()
    {
        int n,m,y1,y2;
        mp.clear();
        scanf("%d%d",&n,&y1);
        for(int i=1;i<=n;i++){
            scanf("%d",&x1[i]);
        }
        scanf("%d%d",&m,&y2);
        for(int i=1;i<=m;i++){
            scanf("%d",&x2[i]);
        }
        int ans=2;
        for(int d=2;d<=1e9;d*=2){
            mp.clear();
            for(int i=1;i<=n;i++){
                mp[x1[i]%d]++;
                ans=max(ans,mp[x1[i]%d]);
            }
            for(int i=1;i<=m;i++){
                mp[(x2[i]+d/2)%d]++;
                ans=max(ans,mp[(x2[i]+d/2)%d]);
            }
        }
        printf("%d
    ",ans);
    }
    

    Summary
    **

    • 在前期队友的题上机有错的情况下,再上去一个人一起看。
    • 在卡题时,需要有人去开别的可做的题。
    • 中期,最好由两个人去一起解一道题,整个队伍都需要明白题意,尽量减少一个人去开一道非打卡题的题目,除非很有把握。
    • 后期增强配合。

    2021-03-05 team training

    越自律,越自由
  • 相关阅读:
    rn相关文档
    《浅谈我眼中的express、koa和koa2》好文留存+笔记
    (四)Spring 对DAO 的支持
    (三)Spring 之AOP 详解
    (二)Spring 之IOC 详解
    SVN文件上感叹号、加号、问号等图标的原因
    Windows平台下不同版本SVN对比
    eclipse中启动Genymotion模拟器的错误
    (一)问候Spring4
    (十一)Hibernate 高级配置
  • 原文地址:https://www.cnblogs.com/ha-chuochuo/p/14503037.html
Copyright © 2011-2022 走看看