数学题
#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;
}
找出最高最低最左最右的点,然后暴力判断就好了
#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;
}
模拟排序,首先将这些字符串按含有元音数量从大到小排序,元音数量相等时按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;
}
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;
}
欧拉降幂+矩阵快速幂
首先等式两边同时乘上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;
}
神仙数学题,设在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; }