• CF1287 div2题解


    前言

    昨夜打CF div2,思涨分之事。然脑未上线,BC题皆挂,仅A两道。
    特写此篇,以记此耻。

    所有题题面:https://codeforces.com/contest/1287/problems

    A. Angry Students

    题面:https://codeforces.com/contest/1287/problem/A
    题解:直接扫一遍,记录(A)后面最长的一段(P)即可。
    时间复杂度:(O(n))
    代码:略

    B. Hyperset

    题面:https://codeforces.com/contest/1287/problem/B
    题解:
    可以发现对于任意一对卡,能和它们组成一组的卡片是唯一的。
    暴力枚举所有卡对,在map里存储信息,直接查找即可。
    时间复杂度:O((n^2)klogn)
    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define re register int
    #define F(x,y,z) for(re x=y;x<=z;x++)
    #define FOR(x,y,z) for(re x=y;x>=z;x--)
    typedef long long ll;
    #define I inline void
    #define IN inline int
    #define C(x,y) memset(x,y,sizeof(x))
    #define STS system("pause")
    template<class D>I read(D &res){
    	res=0;register D g=1;register char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')g=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch)){
    		res=(res<<3)+(res<<1)+(ch^48);
    		ch=getchar();
    	}
    	res*=g;
    }
    map<string,int>mp;
    string s;
    char c[2020][110],t[110];
    int n,m;
    ll ans;
    I Match(int x,int y){
    	F(i,1,m){
    		if(c[x][i]==c[y][i])t[i]=c[x][i];
    		else {
    			if(c[x][i]=='S'&&c[y][i]=='E')t[i]='T';
    			else if(c[x][i]=='S'&&c[y][i]=='T')t[i]='E';
    			else if(c[x][i]=='E'&&c[y][i]=='S')t[i]='T';
    			else if(c[x][i]=='E'&&c[y][i]=='T')t[i]='S';
    			else if(c[x][i]=='T'&&c[y][i]=='S')t[i]='E';
    			else t[i]='S';
    		}
    	}
    	s.clear();s.append(t+1);
    }
    int main(){
    	//cin>>t+1;s.append(t+1);
    	//F(i,0,s.size()-1)cout<<s[i];
    	//return 0;
    	read(n);read(m);
    	F(i,1,n)cin>>c[i]+1;
    	F(i,1,n-1){
    		F(j,i+1,n){
    			Match(i,j);
    			if(!mp.count(s))continue;
    			ans+=mp[s];
    		}
    		s.clear();s.append(c[i]+1);mp.insert(make_pair(s,1));
    	}
    	cout<<ans;
    	return 0;
    }
    

    C. Garland

    题面:https://codeforces.com/contest/1287/problem/C
    题解:考虑DP。
    (f[i][j][k][0/1])表示考虑了前(i)位,已经在0的地方放了(j)个偶数
    (k)个奇数的最小代价。转移方程分当前位是不是0讨论即可。
    时间复杂度:O((n^3))
    这已经足够通过本题(我太菜了),考虑如何优化。
    发现(i)确定时,(j+k)是个定值。所以可以把(j,k)挤进一个变量里。
    时间复杂度:O((n^2))
    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define re register int
    #define F(x,y,z) for(re x=y;x<=z;x++)
    #define FOR(x,y,z) for(re x=y;x>=z;x--)
    typedef long long ll;
    #define I inline void
    #define IN inline int
    #define C(x,y) memset(x,y,sizeof(x))
    #define STS system("pause")
    I read(int &res){
    	res=0;re g=1;register char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')g=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch)){
    		res=(res<<3)+(res<<1)+(ch^48);
    		ch=getchar();
    	}
    	res*=g;
    }
    int n,m,a[110],v[110],s[110],f[110][110][2],A,B;
    int main(){
    	read(n);
    	F(i,1,n){
    		read(a[i]);s[i]=s[i-1];
    		if(!a[i])a[i]=-1,s[i]++;
    		else v[a[i]]=1,a[i]&=1;
    	}
    	F(i,1,n){
    		if(!v[i]){
    			if(i&1)B++;else A++;
    		}
    	}
    //	F(i,1,n)cout<<a[i]<<" ";
    	//cout<<endl;
    	C(f,63);
    	f[0][0][0]=0;f[0][0][1]=0;
    	if(a[1]!=-1){
    		F(j,0,min(s[1],A))if(s[1]-j<=B)f[1][j][a[1]]=min(f[0][j][0],f[0][j][1]);
    	}
    	else{
    		F(j,0,min(s[1],A)){
    			if(s[1]-j>B)continue;
    			if(j)f[1][j][0]=min(f[0][j-1][0],f[0][j-1][1]);
    			f[1][j][1]=min(f[0][j][0],f[0][j][1]);
    		}
    	}
    	F(i,2,n){
    		if(a[i]!=-1){
    			F(j,0,min(s[i],A))if(s[i]-j<=B)f[i][j][a[i]]=min(f[i-1][j][0]+a[i],f[i-1][j][1]+(a[i]^1));
    			continue;
    		}
    		F(j,0,min(s[i],A)){
    			if(s[i]-j>B)continue;
    			if(j)f[i][j][0]=min(f[i-1][j-1][0],f[i-1][j-1][1]+1);
    			f[i][j][1]=min(f[i-1][j][0]+1,f[i-1][j][1]);
    		}
    	}
    	//F(i,1,n)F(j,0,min(s[i],A))cout<<i<<" "<<j<<" "<<f[i][j][0]<<" "<<f[i][j][1]<<endl;
    	cout<<min(f[n][A][0],f[n][A][1]);
    	return 0;
    }
    

    D. Numbers on Tree

    题面:https://codeforces.com/contest/1287/problem/D
    题解:考虑从下到上解决问题。
    每次操作,我们可以把当前节点子树中的点的值都加进一个堆里,
    找到分界位置把当前节点的(a[i])赋值,并给其后面的对应点的值+1。
    但这样做是不对的,因为有可能在一次操作中,这样的加操作可能会改变
    之前子树内点的大小关系。考虑如何避免这个问题。
    可以证明,如果有解,一定存在一种方案,使得所有点的(a[i])都不一样。
    因此,我们可以记录一下上次堆里的最大值,下次先给所有点的值加上这个最大值,再进堆。
    时间复杂度:O((n^2)logn)
    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define re register int
    #define F(x,y,z) for(re x=y;x<=z;x++)
    #define FOR(x,y,z) for(re x=y;x>=z;x--)
    typedef long long ll;
    #define I inline void
    #define IN inline int
    #define C(x,y) memset(x,y,sizeof(x))
    #define STS system("pause")
    I read(int &res){
    	res=0;re g=1;register char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')g=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch)){
    		res=(res<<3)+(res<<1)+(ch^48);
    		ch=getchar();
    	}
    	res*=g;
    }
    typedef pair<int,int>pii;
    priority_queue<pii>q;
    vector<int>e[2020];
    int n,m,root,tot,bas,dep[2020],fa[2020],c[2020],w[2020];
    pii b[2020];
    I D_1(int x,int d){
    	dep[x]=d;q.emplace(make_pair(d,x));
    	for(auto p:e[x])D_1(p,d+1);
    }
    I D_2(int x){
    	w[x]+=bas;
    	b[++tot]=make_pair(w[x],x);
    	for(auto p:e[x])D_2(p);
    }
    int main(){
    	read(n);
    	F(i,1,n)read(fa[i]),read(c[i]);
    	F(i,1,n)if(!fa[i])root=i;else e[fa[i]].emplace_back(i);
    	D_1(root,1);
    	while(!q.empty()){
    		m=q.top().second;q.pop();tot=bas=0;
    		for(auto p:e[m]){
    			D_2(p);sort(b+1,b+1+tot);bas=b[tot].first;
    		}
    		if(tot<c[m]){cout<<"NO";return 0;}
    		sort(b+1,b+1+tot);w[m]=b[c[m]].first+1;
    		F(i,c[m]+1,tot)w[b[i].second]++;
    	}
    	cout<<"YES"<<endl;
    	F(i,1,n)cout<<w[i]<<" ";
    	return 0;
    }
    

    E Madhouse

    题面:https://codeforces.com/contest/1287/problem/D
    题解:首先考虑简单版。
    我们可以询问([1,n])以及([1,n-1])
    发现第一次询问比第二次多了(n)个串,这(n)个串恰好是
    这个串的(n)个后缀的乱序版本。找到这(n)个串即可还原整个串。
    总串数:O((n^2))
    对于困难版,我们可以采用同样的方法,先求出([1,n/2])这部分的串。
    然后再询问([1,n])这部分。
    (f[i][x])表示这次询问所有长度为i的串中,字符(x)的出现次数。
    考虑(f[i+1][x]-f[i][x])的意义,发现这个东西即为原串([i+1,n-i])这段区间内
    字符(x)的出现次数。
    因为我们已经求出了前半段,后半段可以通过倒序枚举(i)逐个求出。
    总串数:O(0.75*(n^2))
    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define re register int
    #define F(x,y,z) for(re x=y;x<=z;x++)
    #define FOR(x,y,z) for(re x=y;x>=z;x--)
    typedef long long ll;
    #define I inline void
    #define IN inline int
    #define C(x,y) memset(x,y,sizeof(x))
    #define STS system("pause")
    template<class D>I read(D &res){
    	res=0;register D g=1;register char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')g=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch)){
    		res=(res<<3)+(res<<1)+(ch^48);
    		ch=getchar();
    	}
    	res*=g;
    }
    map<string,int>mp;
    struct P{
    	string a;
    	friend bool operator > (P x,P y){
    		return x.a.size()==y.a.size()?x.a.compare(y.a)>0:x.a.size()>y.a.size();
    	}
    }p;
    priority_queue<P,vector<P>,greater<P> >q;
    char c[110],ans[110];
    string s;
    int n,m,cnt[30],now[30],f[110][30];
    namespace solve1{
    	I solve(int x){
    		if(x==1){
    			cout<<"? 1 1"<<endl;fflush(stdout);
    			cin>>c+1;ans[1]=c[1];return;
    		}
    		cout<<"? 1 "<<x<<endl;fflush(stdout);
    		F(i,1,x*(x+1)/2){
    			cin>>c+1;m=strlen(c+1);sort(c+1,c+1+m);p.a.clear();p.a.append(c+1);q.emplace(p);
    		}
    		cout<<"? 1 "<<x-1<<endl;fflush(stdout);
    		F(i,1,x*(x-1)/2){
    			cin>>c+1;m=strlen(c+1);sort(c+1,c+1+m);s.clear();s.append(c+1);mp[s]++;
    		}
    		C(cnt,0);m=0;
    		while(!q.empty()){
    			s=q.top().a;q.pop();//cout<<"@"<<s<<endl;
    			if(mp.count(s)){
    				if(mp[s]==1)mp.erase(s);
    				else mp[s]--;
    				continue;
    			}
    			C(now,0);
    			F(i,0,s.size()-1){
    				now[s[i]-'a'+1]++;
    			}
    			F(i,1,26)if(now[i]>cnt[i]){ans[++m]=i+'a'-1;cnt[i]++;break;}
    		}
    		reverse(ans+1,ans+1+x);
    	}
    };
    namespace solve2{
    	I solve(){
    		cout<<"? 1 "<<n<<endl;fflush(stdout);
    		F(i,1,n*(n+1)>>1){
    			cin>>c+1;m=strlen(c+1);
    			F(j,1,m)f[m][c[j]-'a'+1]++;
    		}
    		re l,r;
    		FOR(i,(n-1)>>1,0){
    			l=i+1;r=n-i;
    			C(cnt,0);
    			F(j,l,r-1)cnt[ans[j]-'a'+1]++;
    			F(j,1,26)if(f[i+1][j]-f[i][j]>cnt[j]){ans[r]=j+'a'-1;break;}
    		}
    		cout<<"! "<<ans+1<<endl;fflush(stdout);
    	}	
    };
    int main(){
    	read(n);
    	if(n==1){
    		cout<<"? 1 1"<<endl;fflush(stdout);
    		cin>>c+1;cout<<"! "<<c[1]<<endl;fflush(stdout);
    		return 0;
    	}
    	solve1::solve(n/2);
    	solve2::solve();
    	return 0;
    }
    
  • 相关阅读:
    我的2017年总结
    iOS App图标和启动画面尺寸
    苹果手机屏幕一览
    纯 HTML5 APP与原生APP的差距在哪?
    设置全局导航栏颜色,标题大小和UIBarButtonItem字体大小
    OCiOS开发:CAGradientLayer 渐变色
    UICollectionViewCell的设置间距
    NSUserDefault的使用
    WKWebView进度及title
    TextView中的部分文字响应点击事件
  • 原文地址:https://www.cnblogs.com/Purple-wzy/p/12160709.html
Copyright © 2020-2023  润新知