Codeforces Round #566 (Div. 2)

A.Filling Shapes

  数学题

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
int n;
long long p[40];
int main()
{
	scanf("%d",&n);
	p[0]=1; for (int i=1;i<=30;i++) p[i]=p[i-1]*2ll;
	if (n&1) return printf("0\n"),0;
	printf("%lld\n",p[n/2]);
return 0; 
}

B.Plus from Picture

  找出最高最低最左最右的点,然后暴力判断就好了

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <cmath>
#define pii pair<int,int>;
using namespace std;
const int maxn=1010;
int n,m,topt,xmin,xmax,ymin,ymax,a,b,c,d,e,f,g,h,sum,now;
char s[maxn];
bool ff[510][510],ok;
set<int>ss;
int main()
{
	scanf("%d%d",&n,&m); xmin=501; ymin=501;
	for (int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for (int j=1;j<=m;j++)
		 if (s[j]=='*') 
		 {
		 	if (i>xmax) {xmax=i; g=i; h=j;}
		 	if (i<xmin) {xmin=i; e=i; f=j;}
		 	if (j>ymax) {ymax=j; a=i; b=j;}
		 	if (j<ymin) {ymin=j; c=i; d=j;}
		 	ff[i][j]=1;
		 	sum++;
		 }
	}
	if (a!=c || h!=f) return printf("NO\n"),0;
	for (int i=e;i<=g;i++) if (!ff[i][f]) return printf("NO\n"),0;else now++;
	for (int j=d;j<=b;j++) if (!ff[a][j]) return printf("NO\n"),0;else now++;
	now--;
	if (a==e || a==g) return printf("NO\n"),0;
	if (sum>now) return printf("NO\n"),0;
	printf("YES\n");	
return 0;
}

C.Beautiful Lyrics

   模拟排序,首先将这些字符串按含有元音数量从大到小排序,元音数量相等时按a,e,i,o,u排序,

   那么我们应该先找出最多的元音数量相同且后缀元音一样的对数S,然后再将剩下的元音数量相同的字符对分别与S配对,

   配完之后S中多余的再两两配对

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <cmath>
#define pii pair<int,int>;
using namespace std;
const int maxn=1010;
int n,m,topt,xmin,xmax,ymin,ymax,a,b,c,d,e,f,g,h,sum,now;
char s[maxn];
bool ff[510][510],ok;
set<int>ss;
int main()
{
	scanf("%d%d",&n,&m); xmin=501; ymin=501;
	for (int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for (int j=1;j<=m;j++)
		 if (s[j]=='*') 
		 {
		 	if (i>xmax) {xmax=i; g=i; h=j;}
		 	if (i<xmin) {xmin=i; e=i; f=j;}
		 	if (j>ymax) {ymax=j; a=i; b=j;}
		 	if (j<ymin) {ymin=j; c=i; d=j;}
		 	ff[i][j]=1;
		 	sum++;
		 }
	}
	if (a!=c || h!=f) return printf("NO\n"),0;
	for (int i=e;i<=g;i++) if (!ff[i][f]) return printf("NO\n"),0;else now++;
	for (int j=d;j<=b;j++) if (!ff[a][j]) return printf("NO\n"),0;else now++;
	now--;
	if (a==e || a==g) return printf("NO\n"),0;
	if (sum>now) return printf("NO\n"),0;
	printf("YES\n");	
	/*sort(a+1,a+topt+1,cmp); 
	for (int i=1;i<=topt-1;i++)
	{
		if (a[i].x!=a[i-1].x && a[i].x!=a[i+1].x) yy=y;
	 	if (a[i].x==a[i+1].x) ss.insert(a[i].x);
	 	if (a[i+1].x-a[i].x>1) {f=1; break;}
	}
	if ((int)ss.size()>=2 || f) return printf("NO\n"),0;
	sort(a+1,a+topt+1,cmp1); ss.clear();
	for (int i=1;i<=topt-1;i++)
	{
		if (a[i].y==a[i+1].y || f) ss.insert(a[i].y);
		if (a[i+1].y-a[i].y>1) {f=1; break;}
	}
	if ((int)ss.size()>=2 || f) return printf("NO\n"),0;
	printf("YES\n");*/
return 0;
}

D.Complete Mirror

    1.首先找出直径,先判断直径的两端点是否可行(BFS判断),若可行,直接输出。

    2.再判断直径上有多少个点,若有偶数个点,直接不行(直径两端点始终不能满足条件),若有奇数个点,我们构造一棵以直径中点为root的树

    3.对于这棵树,考虑有now个深度<最大深度的叶子节点

       (1) 判断root可不可以,若可以,直接输出

       (2) 若now>=2 直接不行(任一now<maxdep的叶子节点和直径一端不能同时满足)

       (3) 若now==1,那么满足条件的根节点只可能是该节点,判断下改点是否可以就ok了

       (4) 若now==0,找一条从根到叶子节点的所有father都只有一个儿子,若无这条链,直接不行,若有则判断这条链的叶子节           点是否满足条件

zzytql  orz

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int maxn=100010;
int n,st[maxn<<1],nt[maxn<<1],to[maxn<<1],topt,a[2],di,d[2][maxn],deg[maxn],dep[maxn],root;
int dd[maxn],q[maxn],head,tail,col[maxn],ma,kk[maxn];
int madep;
bool f[maxn];
void add(int x,int y)
{to[++topt]=y; nt[topt]=st[x]; st[x]=topt;}
void find(int x,int de,int id)
{
	f[x]=1; int p=st[x]; if (de>ma) {ma=de; a[id]=x;}
	while (p)
	{
		if (!f[to[p]]) find(to[p],de+1,id);
		p=nt[p];
	}
}
void calc(int x,int y,int num)
{
	if (x==y) {di=num; return;}
	f[x]=1; int p=st[x];
	while (p)
	{
		if (!f[to[p]]) calc(to[p],y,num+1);
		p=nt[p];
	}
}
void dfs(int x,int num,int id)
{
	f[x]=1; d[id][x]=num; int p=st[x];
	while (p)
	{
		if (!f[to[p]]) dfs(to[p],num+1,id);
		p=nt[p];
	}
}
void getdep(int x,int de)
{
	f[x]=1; dep[x]=de; int p=st[x];
	if (x==a[0]) madep=de;
	if (deg[x]==1) kk[x]=x;
	int nn=0,too;
	while (p)
	{
		if (!f[to[p]]) getdep(to[p],de+1),nn++,too=to[p];
		p=nt[p];
	}
	if (nn==1) kk[x]=kk[too];
}
bool ok(int x)
{
	for (int i=1;i<=n;i++) dd[i]=0,col[i]=0;
	q[1]=x; head=tail=1; dd[x]=1; col[1]=deg[x];
	while (head<=tail)
	{
		int x=q[head++]; 
		if (!col[dd[x]]) col[dd[x]]=deg[x];
		else if (col[dd[x]]!=deg[x]) return 0;
		int p=st[x];
		while (p)
		{
			if (!dd[to[p]]) {dd[to[p]]=dd[x]+1; q[++tail]=to[p];}
			p=nt[p];
		}
	}
return 1;
}
int main()
{	
	scanf("%d",&n); a[0]=a[1]=1;
	for (int i=1;i<n;i++)
	{
		int xx,yy; scanf("%d%d",&xx,&yy);
		add(xx,yy); add(yy,xx); deg[xx]++; deg[yy]++;
	}
	ma=0; find(1,0,0); memset(f,0,sizeof f); ma=0; find(a[0],0,1);
	memset(f,0,sizeof f); calc(a[0],a[1],1); 
	if (ok(a[0])) return printf("%d\n",a[0]),0;
	if (ok(a[1])) return printf("%d\n",a[1]),0;
	if (di%2==0) return printf("-1\n"),0;
	memset(f,0,sizeof f); dfs(a[0],0,0); memset(f,0,sizeof f); dfs(a[1],0,1);
	for (int i=1;i<=n;i++) if (d[0][i]==di/2 && d[1][i]==di/2) {root=i; break;}
	//printf("lala %d %d %d %d\n",a[0],a[1],di,root);
	memset(f,0,sizeof f); getdep(root,0); int now=0,lc;
	for (int i=1;i<=n;i++)
	 if (i!=a[0] && i!=a[1] && deg[i]==1 && dep[i]<madep) now++,lc=i;
	if (now>=2) return printf("-1\n"),0;
	if (now==1)
	{
		if (ok(lc)) printf("%d\n",lc);else printf("-1\n");
		return 0;
	}
	if (!now)
	{
		if (ok(root)) return printf("%d\n",root),0;
		if (!kk[root]) return printf("-1\n"),0;
		if (ok(kk[root])) return printf("%d\n",kk[root]),0;
		printf("-1\n"); return 0;
	}
return 0;
}	

 E.Product Oriented Recurrence

   欧拉降幂+矩阵快速幂

   首先等式两边同时乘上c^n,化简可得:c^n*f(n)=c^(n-1)*f(n-1) * c^(n-2)*f(n-2) * c^(n-3)*f(n-3)

   设g(n)=c^n*f(n);     那么问题就转化为求g(n);

   不妨设g(n)=g(1)^x(n)*g(2)^y(n)*g(3)^z(n);

    所以x(n)=x(n-1)+x(n-2)+x(n-3) 这个就可以矩阵快速幂一波(注意此时矩阵是在幂指数上搞的,所以要用欧拉降幂就是说%(mo-1)),然后y,z同理,那么g(n)就可以搞出来,然后f(n)就可以搞出来

    qwq我的代码比较窒息,被大佬教育了

    

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
using namespace std;
long long n,f1,f2,f3,c,g1,g2,g3,mo,x1,x2,x3,ans=1,mi;
const int N=3;  
long long tmp[N][N],now[N][N]; 
void multi(long long a[][N],long long b[][N],int n)  
{  
    memset(tmp,0,sizeof tmp);  
    for(int i=0;i<n;i++)  
     for(int j=0;j<n;j++)  
      for(int k=0;k<n;k++)  
        tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j]%mo)%mo;  
    for(int i=0;i<n;i++)  
     for(int j=0;j<n;j++)  
        a[i][j]=tmp[i][j];  
}  
long long res[N][N];  
void Pow(long long a[][N],long long n)  
{  
    memset(res,0,sizeof res);  
    for(int i=0;i<3;i++) res[i][i]=1;  
    while(n)  
    {  
        if(n&1)  
            multi(res,a,3);  
        multi(a,a,3); 
        n>>=1;  
    }  
}
long long po(long long a,long long b)
{
	if (b==0) return 1;
	if (b==1) return a%mo;
	long long c=po(a,b/2);
	if (b&1) return c*c%mo*a%mo;else return c*c%mo;
}
int main()
{
	scanf("%lld%lld%lld%lld%lld",&n,&f1,&f2,&f3,&c); mo=1e9+7;
	g1=f1*c%mo; g2=f2*c%mo*c%mo; g3=f3*c%mo*c%mo*c%mo;
	mo=1e9+6; x1=0; x2=0; x3=1;
	now[0][0]=1; now[0][1]=1; now[0][2]=0;
	now[1][0]=1; now[1][1]=0; now[1][2]=1;
	now[2][0]=1; now[2][1]=0; now[2][2]=0;
	Pow(now,n-3);
	mi=((x1*res[0][0]%mo+x2*res[1][0]%mo)%mo+x3*res[2][0]%mo)%mo;
	mo=1e9+7; ans=po(g1,mi);

	mo=1e9+6; x1=0; x2=1; x3=0;
	now[0][0]=1; now[0][1]=1; now[0][2]=0;
	now[1][0]=1; now[1][1]=0; now[1][2]=1;
	now[2][0]=1; now[2][1]=0; now[2][2]=0;
	Pow(now,n-3);
	mi=((x1*res[0][0]%mo+x2*res[1][0]%mo)%mo+x3*res[2][0]%mo)%mo;
	mo=1e9+7; ans=ans*po(g2,mi)%mo;

	mo=1e9+6; x1=1; x2=0; x3=0;
	now[0][0]=1; now[0][1]=1; now[0][2]=0;
	now[1][0]=1; now[1][1]=0; now[1][2]=1;
	now[2][0]=1; now[2][1]=0; now[2][2]=0;
	Pow(now,n-3);
	mi=((x1*res[0][0]%mo+x2*res[1][0]%mo)%mo+x3*res[2][0]%mo)%mo;
	mo=1e9+7; ans=ans*po(g3,mi)%mo;

	long long inv=po(po(c%mo,n),mo-2);
	printf("%lld\n",ans*inv%mo);
return 0;	
}

F.Maximum Sine

   神仙数学题,设在x=k处取得最大值,二分要求的x到k之间的最小距离,可用类欧判断是否可行,然后知道了最小距离dis后用exgcd反解出x   

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
int T;
long long a,b,p,q;
long long S(long long k){return (k*(k+1)/2ll);}
long long f(long long a,long long b,long long c,long long n)
{
    if (!a) return 0;
    if (n<0) return 0;
    if (!n) return b/c;
    if(a>=c || b>=c) return ((a/c)*S(n)+(n+1)*(b/c)+f(a%c,b%c,c,n));
    long long m=(a*n+b)/c; return (m*n-f(c,c-b-1,a,m-1));
}
long long work(long long a,long long b,long long c,long long l,long long r)
{return f(a,b,c,r)-f(a,b,c,l-1);}
void exgcd(long long a,long long b,long long &x,long long &y) 
{if(!b) {x=1; y=0; return;} exgcd(b,a%b,y,x),y-=a/b*x;}
long long solve(long long p,long long q,long long t) 
{
  long long gd=__gcd(p,q); if(t%gd!=0) {return 1e18;}
  p/=gd; q/=gd; t/=gd; long long x,y; exgcd(p,q,x,y);
  x*=t; y*=t; long long k=(a-x)/q; x+=k*q;
  while(x>=a) {x-=q;} while(x<a) {x+=q;}
return x;
}
int main()
{
	scanf("%d",&T);
	while (T--)
	{
		scanf("%lld%lld%lld%lld",&a,&b,&p,&q); p<<=1; q<<=1;
		long long l=0,m=q/2,r=m,ans=r;
		while (l<=r)
		{
			long long mid=(l+r)>>1,ll=m-mid,rr=m+mid;
			if (work(p,q-ll,q,a,b)-work(p,q-rr-1,q,a,b)) {ans=min(ans,mid); r=mid-1;}else l=mid+1;
		}
		printf("%lld\n",min(solve(p,q,m-ans),solve(p,q,m+ans)));
	}
return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值