题目链接: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;
}