cf1900+训练

B. Letter Exchange 1900

https://codeforces.com/problemset/problem/1784/B
题解:对于每个字符串,若一个人w>1,n=0则其必然需要在某一步操作种交出w得到n或交出w得到i,再交出i得到n,我们可以把这个交换抽象为一条边w->n,对于图中的一组长度为2的环,即x->y->x,可以用一次交换解决。直到图中无2环时,我们发现,每个点的入度和出度一致,故剩下的环都为w->i->n->w的3元环,而对于每个三元环,容易知道只需两次交换即可消除,即可得到答案。
代码:

#include<bits/stdc++.h>
using namespace std;

char ff[10];
int cnt[10],f[5][5];
stack<int> g[5][5];
struct node{
	int x,y;
	char c1,c2;
}res[100100];
void solve(){
	int n;cin>>n;
	for(int i=1;i<=3;i++){
		for(int j=1;j<=3;j++){
			f[i][j]=0;
			while(g[i][j].size()) g[i][j].pop();
		}
	}
	for(int k=1;k<=n;k++){
		cnt[1]=cnt[2]=cnt[3]=0;
		int p=-1,q=-1;
		string s;cin>>s;
		for(int i=0;i<3;i++){
			int c=s[i];
			if(c=='w') cnt[1]++;
			else if(c=='i') cnt[2]++;
			else if(c=='n') cnt[3]++;
		}
		for(int i=1;i<=3;i++){
			if(cnt[i]==3){
				for(int j=1;j<=3;j++){
					if(j==i) continue;
					f[i][j]++;
					g[i][j].push(k);
				}
				break;
			}
			if(cnt[i]==2) p=i;
			else if(cnt[i]==0) q=i;
		}
		if(p>0&&q>0) f[p][q]++,g[p][q].push(k);
	}
	int ans=0;
	for(int i=1;i<=3;i++){
		for(int j=1;j<=3;j++){
			if(i==j) continue;
			while(f[i][j]&&f[j][i]){
				ans++;
				int x=g[i][j].top();g[i][j].pop();
				int y=g[j][i].top();g[j][i].pop();
				f[i][j]--,f[j][i]--;
				res[ans].x=x,res[ans].y=y,res[ans].c1=ff[i],res[ans].c2=ff[j];
			}
			int k=6-i-j;
			while(f[i][j]&&f[j][k]){
				ans++;
				int x=g[i][j].top();g[i][j].pop();
				int y=g[j][k].top();g[j][k].pop();
				f[i][j]--,f[j][k]--;
				f[i][k]++;
				g[i][k].push(y);
				res[ans].x=x,res[ans].y=y,res[ans].c1=ff[i],res[ans].c2=ff[j];
			}
		}
	}
	cout<<ans<<endl;
	for(int i=1;i<=ans;i++){
		cout<<res[i].x<<" "<<res[i].c1<<" "<<res[i].y<<" "<<res[i].c2<<endl;
	}
}

signed main(){
	ff[1]='w',ff[2]='i',ff[3]='n';
	int T;cin>>T;
	while(T--) solve();
}

Up the Strip 1900

https://www.luogu.com.cn/problem/CF1558B
题解:对于从n到1的点,我们考虑谁能到达它:所有比它大的位置,以及kx,kx+1,,,k*x+k-1(1<k<=x),即可完成转移。结合后缀和我们可以将复杂度优化为n(1+1/2+,,,+1/n)=nlogn,可通过本题。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int f[4000010],s[4000010];

signed main(){
	int n,m;cin>>n>>m;
	f[n]=1;
	s[n]=1;
	for(int i=n-1;i>=1;i--){
		f[i]=(f[i]+s[i+1])%m;
		for(int j=2;j*i<=n;j++){
			int w=min(n+1,i*j+j);
			f[i]=(f[i]+s[i*j]-s[w]+m)%m;
		}
		s[i]=(s[i+1]+f[i])%m;
	}
	cout<<f[1];
}

C. Music Festival 1900(?感觉更高)

https://codeforces.com/problemset/problem/1801/C
题解:显然我们需要将每一个专辑预处理成递增序列,然后按照最大值从小到达将专辑排序。定义f(i,j)为前i个专辑中选择若干,最大值为j时得到的最大满意度。这个dp是n2的,无法通过。考虑优化,由于其实每次我们转移都是转移到同一个最大值,即更新数量很少,而询问是询问前缀最大满意度,即动态区间查询,单点修改,可以使用线段树优化,每次枚举第i个专辑递增序列的各个值,对f(i,m[i]) 以max(1,a[i][j]-1)+cnt更新,最后答案即为max(1,maxx).复杂度为O(nlogn).需要注意的是每次需要离散化数据来初始化否则会t。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+100;
int a[N],m[N],id[N],nex[N],pre[N];
int f[N],q[N];
struct node{
	int c,l,r,lz;
}t[N*4];
void build(int p,int l,int r){
	t[p].l=l,t[p].r=r;
	if(l==r){
	t[p].c=0,t[p].lz=0;
	return;
	}
	int mid=(l+r)/2;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
}
void pushdown(int p){
	if(!t[p].lz) return;
	int w=t[p].lz;
	t[p*2].c=max(t[p*2].c,t[p].lz);
	t[p*2+1].c=max(t[p*2+1].c,w);
	t[p*2].lz=max(t[p*2].lz,w);
	t[p*2+1].lz=max(t[p*2+1].lz,w);
	t[p].lz=0;
}
void change(int p,int l,int r,int k){
	if(t[p].l>=l&&t[p].r<=r){
		t[p].lz=k;
		t[p].c=k;
		return;
	}
	pushdown(p);
	int mid=(t[p].l+t[p].r)/2;
	if(l<=mid) change(p*2,l,r,k);
	if(r>mid) change(p*2+1,l,r,k);
	t[p].c=max(t[p*2].c,t[p*2+1].c);
}
int ask(int p,int l,int r){
	if(t[p].l>=l&&t[p].r<=r){
		return t[p].c;
	}
	pushdown(p);
	int res=0,mid=(t[p].l+t[p].r)/2;
	if(mid>=l) res=max(res,ask(p*2,l,r));
	if(mid<r) res=max(res,ask(p*2+1,l,r));
	return res;
}
bool cmp(int x,int y){
	return m[x]<m[y];
}
void solve(){
	int n;cin>>n;
	int tot=0;
//	build(1,1,200000);
vector<int> g[n+1];
	for(int i=1;i<=n;i++){
		id[i]=i;
		int k;cin>>k;
		int maxx=0;
		for(int j=1;j<=k;j++){
			int x;cin>>x;
			if(x>maxx){
				maxx=x;
				q[++tot]=x;
				g[i].push_back(x);
			}
		}
		m[i]=maxx;
	}
	sort(q+1,q+tot+1);
	int tt=0;
	for(int i=1;i<=tot;i++){
		if(q[i]==q[i-1]) continue;
		f[q[i]]=++tt;
	}
	for(int i=1;i<=n;i++) m[i]=f[m[i]];
	for(int i=0;i<=tt*4;i++){
		t[i].c=0,t[i].lz=0,t[i].l=0,t[i].r=0;
	}
	build(1,1,tt);
	sort(id+1,id+n+1,cmp);
	for(int i=1;i<=n;i++){
		int cnt=g[id[i]].size();
		int maxx=ask(1,m[id[i]],m[id[i]]);
		for(auto j:g[id[i]]){
			int it=f[j];
			int y=ask(1,1,it-1);
			y=y+cnt;
			if(y>maxx)
			change(1,m[id[i]],m[id[i]],y);
			maxx=max(maxx,y);
			cnt--;
		}
	}
	int ans=ask(1,1,tt);
	cout<<ans<<endl;
}
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--) solve();
}
posted @ 2023-03-19 11:55  wrong,anser  阅读(53)  评论(0)    收藏  举报