Codeforces Round #566 (Div. 2) A-E

38 篇文章 0 订阅
29 篇文章 0 订阅

题目链接:http://codeforces.com/contest/1182

 

A. Filling Shapes

每两列有2种方法,所以是2的n/2次方

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
const int mx = 100 + 10;
int du[mx];
int main()
{
	int n;
	scanf("%d",&n);
	if(n&1) puts("0");
	else printf("%lld\n",1ll<<(n/2));
	return 0;
} 

B. Plus from Picture

找到中心直接往四个方向标记,然后再枚举所有点看是否存在一个点是‘*’号,且没有被标记过,那么就是no了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
const int mx = 500 + 10;
int n,m;
char str[mx][mx];
bool vis[mx][mx];
void full(int x,int y){
	int i,j;
	i = x,j = y;
	while(j<m&&str[i][j]=='*') vis[i][j] = 1,j++;
	i = x,j = y;
	while(j>=0&&str[i][j]=='*') vis[i][j] = 1,j--;
	i = x,j = y;
	while(i<n&&str[i][j]=='*') vis[i][j] = 1,i++;
	i = x,j = y;
	while(i>=0&&str[i][j]=='*') vis[i][j] = 1,i--;
}
int main()
{
	bool ok = 0;
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		scanf("%s",str[i]);
	}
	for(int i=1;i<n-1;i++){
		for(int j=1;j<m-1;j++){
			if(ok) break;
			if(str[i][j]=='*'){
				if(str[i-1][j]==str[i+1][j])
				if(str[i][j-1]==str[i][j+1])
				if(str[i-1][j]==str[i][j-1]) 
				if(str[i-1][j]=='*'){
					full(i,j);
					ok = 1;
				}
			}
		}
	}
	if(ok){
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++)
			if(str[i][j]=='*'&&!vis[i][j]) return 0*puts("no");
		}
		return 0*puts("yes");
	}
	puts("no");
	return 0;
}

C. Beautiful Lyrics

先令元音长度且最后一个元音字符相同的两两配对,那么放前面的一对肯定是元音长度是0和元音长度相同但最后元音字符不同。因为只有五个元音字符,所以每个元音字符长度最多组成2对最后元音不同的配对。然后就贪心。

#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair <int,int> pa; 
const int mod = 998244353;
const int mx = 1e5 + 10;
string s[mx];
char c[mx*10];
pa ret[mx],q[mx];
pair <pa,pa> a[mx];
int siz,tot;
int cnt[mx*10][8],is,cp[mx*10];
int check(char ch){
	if(ch=='a') return 1;
	if(ch=='e') return 2;
	if(ch=='i') return 3;
	if(ch=='o') return 4;
	if(ch=='u') return 5;
	return 0; 
}
int main()
{
	int n;scanf("%d",&n);
	for(int i=1;i<=n;i++){
		cin >> s[i];
		int hd = 0;
		for(int j=0;j<s[i].size();j++)
		if(check(s[i][j])) c[hd++] = s[i][j];
		c[hd] = 0;
		if(!hd){
			if(cnt[hd][0]){
				q[tot++] = pa(i,cnt[hd][0]);
				cnt[hd][0] = 0;
			}else cnt[hd][0] = i;
		}else{
			int id = check(c[hd-1]);
			if(cnt[hd][id]){
				ret[is++] = pa(i,cnt[hd][id]);
				cnt[hd][id] = 0;
			}else cnt[hd][id] = i;
		}
	}
	for(int i=1;i<mx*10;i++){
		for(int j=1;j<6;j++)
		if(cnt[i][j]){
			if(cp[i]){
				q[tot++] = pa(cnt[i][j],cp[i]);
				cp[i] = 0;
			}else cp[i] = cnt[i][j];
		}
	}
	int l = 0,r = 0,ans = 0;
	while(l<is){
		if(r!=tot){
			a[siz++] = {q[r],ret[l]};
			r++;
		}else{
			if(l+1==is) break;
			a[siz++] = {ret[l],ret[l+1]};
			l++;
		}
		l++;
	} 
	printf("%d\n",siz);
	for(int i=0;i<siz;i++){
		pa u = a[i].first;
		pa v = a[i].second;
		cout << s[u.fi] << " " << s[v.fi] << endl;
		cout << s[u.se] << " " << s[v.se] << endl;
	}
	return 0;
} 

D. Complete Mirror

先找到树的重心rt,首先check一下rt是不是可以的,不如不行。

那么这个点肯定是度为1的点,而且这个点到rt是一条"直线",也就是没有分叉。(根据重心的性质可以证明)

而且对于同一个深度的点,我们只需要考虑一次就行,所以最多sqrt(n)个点满足条件。

所以最快情况是O(n*sqrt(n))

#include <bits/stdc++.h>
using namespace std;
const int mx = 1e5 + 10;
vector <int> g[mx];
int n,rt,sz[mx],ma = 1e9; 
bool vis[mx];
void dfs_rt(int u,int fa){
	int c = 0;
	sz[u] = 1;
	for(int v:g[u]){
		if(v==fa) continue;
		dfs_rt(v,u);
		sz[u] += sz[v];
		c = max(c,sz[v]);
	}
	c = max(c,n-sz[u]);
	if(c<ma) ma = c,rt = u;
}
bool dfs(int u,int fa,int d){
	if(!sz[d]) sz[d] = g[u].size();
	else if(g[u].size()!=sz[d]) return 0;
	for(int v:g[u]){
		if(v==fa) continue;
		if(!dfs(v,u,d+1)) return 0;
	}
	return 1;
}
bool check(int u){
	memset(sz,0,sizeof(sz));
	return dfs(u,0,0);
}
int line(int u,int fa,int d){
	if(u==rt) return d;
	if(g[u].size()>2) return 0;
	for(int v:g[u]) if(v!=fa)
	return line(v,u,d+1);
}
int main(){
	scanf("%d",&n);
	int u,v;
	for(int i=1;i<n;i++){
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs_rt(1,0);
	if(check(rt)) return 0*printf("%d\n",rt);
	for(int i=1;i<=n;i++){
		if(g[i].size()==1){
			int d = line(i,0,0);
			if(d&&!vis[d]){
				vis[d] = 1;
				if(check(i)) return 0*printf("%d\n",i);
			}
		}
	}
	puts("-1");
	return 0;
}

E. Product Oriented Recurrence

简单明了算f1,f2,f3的贡献就好了。直接矩阵快速幂。

然后c的贡献可以令f[n] = f[n-1] + f[n-2] + f[n-3] + g[n],然后g[n] = 2*n - 6 = g[n-1] + 2,然后用一个五维矩阵就ok了。

#include<math.h>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int mx = 5; 
const int mod = 1e9 + 7;
ll m,f1,f2,f3,c,n;
struct node
{
	ll mat[mx][mx];
}base,ret;
node matrix(node a,node b,int siz)
{
	node c;
	memset(c.mat,0,sizeof(c.mat));
	for(int k=0;k<siz;k++){
		for(int i=0;i<siz;i++){
			if(a.mat[i][k])
			for(int j=0;j<siz;j++)
			c.mat[i][j] = (c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%(mod-1);
		}
	}
	return c;
}
node qpow(ll m,int siz)
{
	node ans = ret;
	node b = base;
	while(m){
		if(m&1) ans = matrix(ans,b,siz);
		m >>= 1;
		b = matrix(b,b,siz);
	}
	return ans;
}
ll qpows(ll x,ll y){
	ll ans = 1;
	while(y){
		if(y&1) ans = ans*x%mod;
		y >>= 1;
		x = x*x%mod;
	}
	return ans;
}
int main()
{
	scanf("%lld%lld%lld%lld%lld",&n,&f1,&f2,&f3,&c);
	base.mat[0][0] = base.mat[1][0] = base.mat[2][0] = 1;
	base.mat[0][1] = base.mat[1][2] = 1;
	memset(&ret,0,sizeof(ret));
	ret.mat[0][2] = 1;
	ll ans = 1;
	node now = qpow(n-3,3);
	ans = ans*qpows(f1,now.mat[0][0])%mod;
	memset(&ret,0,sizeof(ret));
	ret.mat[0][1] = 1;
	now = qpow(n-3,3);
	ans = ans*qpows(f2,now.mat[0][0])%mod;
	memset(&ret,0,sizeof(ret));
	ret.mat[0][0] = 1;
	now = qpow(n-3,3);
	ans = ans*qpows(f3,now.mat[0][0])%mod;
	memset(&ret,0,sizeof(ret));
	memset(&base,0,sizeof(base));
	for(int i=0;i<4;i++) base.mat[i][0] = 1;
	base.mat[0][1] = base.mat[1][2] = 1;
	base.mat[3][3] = base.mat[4][3] = 1;
	base.mat[4][4] = 1; 
	ret.mat[0][0] = 2,ret.mat[0][3] = 4,ret.mat[0][4] = 2;
	now = qpow(n-4,5);
	ans = ans*qpows(c,now.mat[0][0])%mod;
	printf("%lld\n",ans);
 	return 0;
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值