Codeforces Round #554 Div. 2

  A:奇偶配对。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,m,a[N],b[N];
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read(),m=read();
	int x1=0,x2=0,y1=0,y2=0;
	for (int i=1;i<=n;i++)
	{
		a[i]=read();
		x1+=a[i]&1,x2+=a[i]&1^1;
	}
	for (int i=1;i<=m;i++)
	{
		b[i]=read();
		y1+=b[i]&1,y2+=b[i]&1^1;
	}
	cout<<min(x1,y2)+min(x2,y1); 
	return 0;
	//NOTICE LONG LONG!!!!!
}

  B:从高位到低位考虑,每遇到一个0就考虑将其改成1,即如果该位之后全是0就改下一位,否则改这一位。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 1000010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,ans[100],t;
signed main()
{
	n=read();
	for (int i=19;i>=0;i--)
	if (!(n&(1<<i)))
	{
		if (((n>>i)<<i)==n) 
		{
			ans[++t]=i;
			n^=(1<<i)-1;n++;
		}
		else
		{
			ans[++t]=i+1;
			n^=(1<<i+1)-1;n++;
		}
	}
	cout<<t*2<<endl;
	for (int i=1;i<=t;i++) cout<<ans[i]<<' ';
	return 0;
	//NOTICE LONG LONG!!!!!
}

  C:显然无论如何变化两者gcd一定是a-b的因子。确定gcd(是某数倍数)的情况下很容易求出最小k。枚举每个因子取最优解即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 1000010
#define pii pair<ll,int>
#define mp(x,y) make_pair((x),(y))
int a,b;
pii ans;
pii calc(int x)
{
	int t=(x-a%x)%x;
	return mp(1ll*(a+t)*(b+t)/x,t);
}
signed main()
{
	cin>>a>>b;
	if (a<b) swap(a,b);if (a==b) {cout<<0;return 0;}
	ans.first=1ll*inf*inf;ans.second=inf;
	for (int i=1;i*i<=a-b;i++)
	if ((a-b)%i==0)
	ans=min(ans,calc(i)),ans=min(ans,calc((a-b)/i));
	cout<<ans.second;
	return 0;
	//NOTICE LONG LONG!!!!!
}

  D:做法似乎非常多。考虑n++后树形态的变化。可以发现是给当前所有没有左儿子的点添加左儿子,并给该左儿子一直添加右儿子直至所有叶子节点深度相同。任意时刻没有左儿子的点都构成很多条链,上述过程就是这些链所引发的,可以考虑dp出各种长度的链的条数,转移考虑上述过程即可。然后考虑怎么利用这个东西求出答案。这棵树的最大匹配可以自底向上贪心求得。画画图观察一下,容易发现最大匹配中各层间是无关的,即上述过程的第一步所添加的边选进最大匹配不会更优。那么一条链对最大匹配的贡献就是链上点的个数/2了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 1010
#define P 1000000007
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,f[N][N],g[N][N],ans;
signed main()
{
	n=read();
	f[0][1]=1;for (int j=0;j<=n+1;j++) g[0][j]=1;
	for (int i=1;i<=n;i++)
	{
		for (int j=2;j<=i+1;j++)
		{
			f[i][j]=g[i-1][j-1];
			ans=(ans+1ll*f[i][j]*(j>>1))%P;
		}
		for (int j=n+1;j>=0;j--) g[i][j]=(g[i][j+1]+f[i][j])%P;
	}
	cout<<ans;
	return 0;
	//NOTICE LONG LONG!!!!!
}

  E:除开头和结尾位置上的数都会在给出的数组中的相邻位置出现两次,开头和结尾会各出现一次。将每个数看成一个点,给出的每对数看成一条边,就相当于找一条欧拉路。跑出来再判一下是否合法即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 200010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,a[N],b[N],p[N],u[N<<1],ans[N],tot,degree[N],cnt,t=-1,top;
bool flag[N];
map<int,int> f[N];
struct data{int to,nxt;
}edge[N<<1];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k)
{
	for (int i=p[k];~i;i=edge[i].nxt)
	if (!flag[i>>1])
	{
		flag[i>>1]=1;
		p[k]=edge[i].nxt;
		cnt++;
		dfs(edge[i].to);
		ans[top--]=edge[i].to;
		if (cnt==n-1) break;
	}
}
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read();memset(p,255,sizeof(p));
	for (int i=1;i<n;i++) u[++tot]=a[i]=read();
	for (int i=1;i<n;i++) u[++tot]=b[i]=read();
	sort(u+1,u+tot+1);
	tot=unique(u+1,u+tot+1)-u-1;
	for (int i=1;i<n;i++) a[i]=lower_bound(u+1,u+tot+1,a[i])-u;
	for (int i=1;i<n;i++) b[i]=lower_bound(u+1,u+tot+1,b[i])-u; 
	for (int i=1;i<n;i++) addedge(a[i],b[i]),addedge(b[i],a[i]),degree[a[i]]++,degree[b[i]]++,f[a[i]][b[i]]++;
	int qwq=0;
	for (int i=1;i<=tot;i++) if (degree[i]&1) qwq++;
	if (qwq!=2&&qwq!=0) {cout<<-1;return 0;}
	top=n;for (int i=1;i<=tot;i++) if (qwq==0||(degree[i]&1)) {dfs(i);ans[1]=i;break;}
	for (int i=1;i<n;i++)
	if (f[min(ans[i],ans[i+1])][max(ans[i],ans[i+1])]==0) {cout<<-1;return 0;}
	else f[min(ans[i],ans[i+1])][max(ans[i],ans[i+1])]--;
	for (int i=1;i<=n;i++) printf("%d ",u[ans[i]]);
	return 0;
	//NOTICE LONG LONG!!!!!
}

  F:由于要求每个数各不相同,考虑按数的顺序dp。不妨考虑从大到小。则每次向序列中插入一个数时,需要满足其后一个数-m<=该数。于是设f[i][j][k]为插入i后序列中有j个数其中i~i+m-1在序列中的存在性为k。矩阵快速幂优化。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define P 1000000007
#define N 210
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,m,k,ans,size[N];
struct matrix
{
	int n,a[N][N];
	matrix operator *(const matrix&b) const
	{
		matrix c;c.n=n;memset(c.a,0,sizeof(c.a));
		for (int i=0;i<n;i++)
			for (int j=0;j<b.n;j++)
				for (int k=0;k<b.n;k++)
				c.a[i][j]=(c.a[i][j]+1ll*a[i][k]*b.a[k][j])%P;
		return c;
	}
}f,a;
int trans(int x,int y){return (x<<m)+y;}
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read(),k=read(),m=read();
	f.n=1;f.a[0][0]=1;
	a.n=k+1<<m;
	for (int i=1;i<(1<<m);i++) size[i]=size[i^(i&-i)]+1;
	for (int i=0;i<=k;i++)
		for (int j=0;j<(1<<m);j++)
		{
			a.a[trans(i,j)][trans(i,(j<<1)&(1<<m)-1)]++;
			if (i<k) a.a[trans(i,j)][trans(i+1,((j<<1)&(1<<m)-1)|1)]+=size[j]+1;
		}
	for (;n;n>>=1,a=a*a) if (n&1) f=f*a;
	for (int j=0;j<(1<<m);j++) ans=(ans+f.a[0][trans(k,j)])%P;
	cout<<ans;
	return 0;
	//NOTICE LONG LONG!!!!!
}

  小小小号打的。result:rank 248 rating +166 彻底自闭.jpg

 

posted @ 2019-04-29 17:40  Gloid  阅读(166)  评论(0编辑  收藏  举报