$$ \newcommand{\seq}[2]{{#1}_{1},{#1}_{2},\cdots,{#1}_{#2}} \newcommand{\num}[1]{1,2,\cdots,#1} \newcommand{\stra}[2]{\begin{bmatrix}#1 \\ #2\end{bmatrix}} \newcommand{\strb}[2]{\begin{Bmatrix}#1 \\ #2\end{Bmatrix}} \newcommand{\dw}[1]{\underline{#1}} \newcommand{\up}[1]{\overline{#1}} $$

Codeforces 1215

A.

分类讨论。

Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=100003;
int main(){
	int a1,a2,k1,k2,n;
	cin>>a1>>a2>>k1>>k2>>n;
	if(k1>k2)swap(a1,a2),swap(k1,k2);
	int ans1=n/k1;
	if(ans1>a1)ans1=a1+(n-a1*k1)/k2;
	int tmp=n/a2,ans2;
	if(tmp<k2-k1)ans2=0;
	else{
		int m=n-a2*(k2-k1);
		tmp=(m+a1+a2-1)/(a1+a2);
		if(tmp<k1)ans2=0;
		else if(tmp==k1)ans2=(m%(a1+a2)==0?a1+a2:m%(a1+a2));
		else ans2=a1+a2;
	}
	cout<<ans2<<' '<<ans1;
	return 0;
}

B.

考虑前缀和的正负性。

C.

\(^{a\;a}_{b\;b}\rightarrow ^{a\;b}_{a\;b}\)
\(^{a\;b}_{b\;a}\rightarrow ^{a\;a}_{b\;b}\rightarrow ^{a\;b}_{a\;b}\)

执行完以上转换后,如果还没相等,那就不可能。

Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=200003;
int n;
char s[maxn],t[maxn];
vector<int> u,v;
int main(){
	scanf("%d%s%s",&n,s+1,t+1);
	for(int i=1;i<=n;i++){
		if(s[i]=='a'&&t[i]=='b')u.push_back(i);
		if(s[i]=='b'&&t[i]=='a')v.push_back(i);
	}
	if(u.size()%2+v.size()%2==1){puts("-1");return 0;}
	int cnt=u.size()/2+v.size()/2+u.size()%2+v.size()%2;
	printf("%d\n",cnt);
	for(int i=0;i+1<int(u.size());i+=2){
		printf("%d %d\n",u[i],u[i+1]);
	}
	for(int i=0;i+1<int(v.size());i+=2){
		printf("%d %d\n",v[i],v[i+1]);
	}
	if(u.size()%2+v.size()%2){
		printf("%d %d\n%d %d\n",u.back(),u.back(),u.back(),v.back());
	}
	return 0;
}

D.

被叉掉了

Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=200003;
int n,cnt0,cnt1,sum0,sum1;
char s[maxn];
int main(){
	scanf("%d%s",&n,s+1);
	for(int i=1;i<=n/2;i++){
		if(s[i]=='?')cnt0++;
		else sum0+=s[i]-48;
	}
	for(int i=n/2+1;i<=n;i++){
		if(s[i]=='?')cnt1++;
		else sum1+=s[i]-48;
	}
	if(sum0<sum1)swap(cnt0,cnt1),swap(sum0,sum1);
	int game=(cnt0+cnt1)/2;
	for(int i=1;i<=game;i++){
		if(cnt0){
			sum0+=9;
			cnt0--;
		}
		else{
			cnt1--;
			if(sum1+9>sum0)sum1+=9,swap(sum0,sum1),swap(cnt0,cnt1); // important
		}
		if(cnt1){
			sum1+=min(9,sum0-sum1);
			cnt1--;
		}
		else{
			cnt0--;
		}
	}
	puts(sum0==sum1?"Bicarp":"Monocarp");
	return 0;
}

E.

看到20,4s,考虑状压。
先预处理出 \(pre[i][j]\) 表示位置1到i有多少个元素等于j,然后在用其处理出 \(sum[i][j]\) 表示序列中每个等于i的元素的pre[j]之和。
然后 \(O(2^n*n^2)\) 状压dp,对于已处理的集合S和不在S中的i,我们的目标是把所有等于i的元素移到未处理元素的左边,S中元素的右边。这样它的贡献就是 \(\sum sum[i][j](j≠i,j∉S)\)
有点类似统计逆序对。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long D;
const int maxn=400003,maxm=20,maxb=1<<maxm;
const D INF=0x3f3f3f3f3f3f3f3fll;
int n,a[maxn],pre[maxn][maxm];
D dp[maxb],sum[maxm][maxm];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",a+i),a[i]--;
	for(int i=1;i<=n;i++){
		for(int j=0;j<maxm;j++)pre[i][j]=pre[i-1][j];
		pre[i][a[i]]++;
	}
	for(int i=1;i<=n;i++){
		for(int j=0;j<maxm;j++){
			sum[a[i]][j]+=pre[i][j];
		}
	}
	memset(dp,0x3f,sizeof(dp));
	dp[0]=0;
	for(int S=0;S<maxb;S++){
		for(int i=0;i<maxm;i++){
			if(!((S>>i)&1)){
				D res=0;
				for(int j=0;j<maxm;j++){
					if(i!=j&&!((S>>j)&1)){
						res+=sum[i][j];
					}
				}
				dp[S|(1<<i)]=min(dp[S|(1<<i)],dp[S]+res);
			}
		}
	}
	printf("%lld\n",dp[maxb-1]);
	return 0;
}
posted @ 2019-09-20 20:09  chc_1234567890  阅读(94)  评论(0编辑  收藏  举报