2020牛客寒假算法基础集训营

A

题意:

给一个n*m的矩形方格,问能找到多少个①面积为1②有一条边平行x轴或y轴的三角形③每个顶点都在格点上。

我们可以直接推出以下图形

2020牛客寒假算法基础集训营_第1张图片

 

 (忽略字体。。。太困了草草写完睡觉)由于感觉会相乘的时候爆掉,写了个快乘;

#include
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1000000007;
int n,m,T;
string s;
int a[maxn];
ll res1,res2,res3,res4;
ll mymul(ll a,ll b,ll c)
{
    ll ans=0;
    a%=c;
    while(b){
        if(b&1) ans=(a+ans)%c;
        a=(a+a)%c;
        b>>=1;
    }
    return ans%c;
}
int main()
{
//    cout<=2&&m>=3){
    res1=mymul(m-2,m-2,mod);
    res1=mymul(res1,2*n-2,mod);
    }
    if(n>=3&&m>=2){
    res2=mymul(n-2,n-2,mod);
    res2=mymul(res2,2*m-2,mod);
    }
    if(n>=3&&m>=2){
    res3=mymul(m-1,m,mod);
    res3=mymul(res3,2*n-4,mod);
    }
    if(n>=2&&m>=3){
    res4=mymul(n-1,n,mod);
    res4=mymul(res4,2*m-4,mod);
    }
    ll res=((((res1+res2)%mod+res3)%mod+res4)%mod);
    printf("%lld\n",res);
    }
}

  

c

 C-umi和弓道

题意:

umi站在一个位置,还有其他n个靶子在其他位置,你可以在x轴或y轴上放置一堵墙使umi最多只能射中k个靶子,求出墙的最短长度,不能则输出-1

#include
#include
#include
#include
 using namespace std;
 vector a,b;
 int main()
 {
     double x0,y0,x,y;
     int n,k;
     cin>>x0>>y0>>n>>k;
     k=n-k;
     for(int i=1;i<=n;i++){
         cin>>x>>y;
         if(x*x0<0) a.push_back(y0-x0*(y-y0)/(x-x0));
         if(y*y0<0) b.push_back(x0-y0*(x-x0)/(y-y0));
     }
    double ans=1e18;
    sort(a.begin(),a.end());
    sort(b.begin(),b.end());
    if(a.size()>=k){
        int s=0,e=k-1;
        while(e=k){
        int s=0,e=k-1;
        while(e 
 

  E

定义f(x)为x的因数个数,设f(x)=n则不断进行x=n为几次后n=2

直接o(根号n)算出

#include
using namespace std;
typedef long long ll;
ll n;
ll get_num(ll n){
    ll tot=1;
    for(ll i=2;i*i<=n;++i){
        if(n%i==0){
            ll x=0;
            while(n%i==0){
                n/=i;
                x++;
            }
            tot*=(x+1);
        }
    }
    if(n>1)tot*=2;
    return tot;
}
 
int main(){
    cin>>n;
    for(ll i=1;i<=1e12;i++){
        n=get_num(n);
        if(n==2) {printf("%lld\n",i);break;}
    }
}

  

 F-maki和tree

题意:

一颗树中有白色的点与黑色的点,问有多少个点对满足两点连线上只有一个黑色的点

思路:

可以发现,黑点要么在端点要么在两点之间,我们就分这两种情况讨论

在计算之前,我们先将所有只有白色点的连通块利用并查集缩点,sum[i]记录i点所在连通块内白点的个数

①黑点作为端点,那么符合要求的点对就为其所连白点sum[i]的求和

②黑点作为中间点,那么符合要求的点对就为∑∑sum[i]*sum[j](1≤i≤k,i<j≤k) k为其所连白点数

#include
#include
#include
 using namespace std;
 const int maxn=1e5+10;
 typedef long long ll;
int fa[maxn],siz[maxn],num[maxn];//siz为儿子的数量,num为i所在白块内点的数量
  vector a[maxn],temp;
  char s[maxn];
  ll sum[maxn];
  int find(ll x)
  {
      if(fa[x]==x) return x;
      return find(fa[x]);
  }
  void uni(int x,int y)
  {
      int f1=find(x),f2=find(y);
      if(x!=y){
          if(siz[f1]>siz[f2])    fa[f2]=f1,siz[f1]+=siz[f2]+1;
          else    fa[f1]=f2,siz[f2]+=siz[f1]+1;
      }
  }
  ll solve()
  {
      if(temp.size()==0)    return 0;
      int n=temp.size();
      sum[n]=0;    
      for(int i=n-1;i>=0;i--) sum[i]=sum[i+1]+temp[i];
      ll ret=sum[0];
      for(int i=0;i 
 

  G

G-eli和字符串

题意:

给一个字符串包含01,问你可以最多将k个0变为1也可以将1变为0求最长子串长度是多少

#include
using namespace std;
typedef long long ll;
int mp[30];
string s;
int n,k;
queueq[100];
int main(){
    cin>>n>>k;
    cin>>s;
    int ans=0x3f3f3f3f;
    for(int i=0;i 
 

I

给一个字符串s,使用其中的nico可得a分,使用niconi可得b分,使用niconiconi可得c分,使用过的不可使用,问最多能得几分

思路:

dp即可

if(i>=3&&s.substr(i-3,4)=="nico") dp[i]=max(dp[i],dp[i-4]+a);

if(i>=5&&s.substr(i-5,6)=="niconi") dp[i]=max(dp[i],dp[i-6]+b);

if(i>=9&&s.substr(i-9,10)=="niconiconi") dp[i]=max(dp[i],dp[i-10]+c);

#include
#include
#include
#include
 using namespace std;
 const int maxn= 3e+5;
 typedef long long ll;
 ll dp[maxn];
 string s;
 int main()
 {
     int n,a,b,c;
     scanf("%d%d%d%d",&n,&a,&b,&c);
     cin>>s;
     dp[0]=0;
     for(int i=0;i=0) dp[i]=dp[i-1]; 
         if(i>=3&&s.substr(i-3,4)=="nico") dp[i]=max(dp[i],dp[i-4]+a);
         if(i>=5&&s.substr(i-5,6)=="niconi")    dp[i]=max(dp[i],dp[i-6]+b);
         if(i>=9&&s.substr(i-9,10)=="niconiconi")    dp[i]=max(dp[i],dp[i-10]+c);
     }
    cout< 
 

 J

用到了 矩阵快速幂+欧拉降幂+快速幂
前两项特判就不说了
从第三项开始 都会呈现一定的规律
f( 3) =x1 * y1 * ab
f( 4) =x1 * y2 * a2b
f( 5) =x2 * y3 * a4
f( 6) =x3 * y5 * a7
设 xx yy aa 分别为x y a 的幂
再设g(1)=1 g(2)=1 ,当i>3时 g(i)=g(i-1)+g(i-2)
那么xx=g(n-2) ,yy=g(n-1) aa=g(n)-1 【n>3】
所以我们来一次矩阵快速幂就好了~

 

但是斐波拉契数列到几十项就快爆了,我们一定要取模,但是怎么取了?
这里用到了欧拉降幂 假如我们要求ab ,现在我们用mod=1e9+7,题目也说了mod是个质数,当a=mod时,可能出现a=k*mod的情况,我们要提前特判此时 ab%mod=0 即可(我被这里卡了几个小时)
最后是个快速幂,我就不说了.

(欧拉定理:当a和n互质时,a^b(modn)=a^(b mod(&n) )&n表示n所含的小于他的质数个数

由于n是质数,则&n=n-1;

所以运算的时候顺便mod(n-1)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1);
LL n,m;
struct node
{
    LL f[3][3];
}t;
template
inline void read(T &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
node mult(const node &a,const node &b)
{
    node res;
    FOR(i,1,2)
    FOR(j,1,2){
        res.f[i][j]=0;
        FOR(k,1,2) res.f[i][j]=(res.f[i][j]+a.f[i][k]*b.f[k][j])%(mod-1);
    }
    return res;
}
LL qpow(LL a,LL p)
{
    LL res=1;
    while(p){
        if(p&1) res=res*a%mod;
        a=a*a%mod;
        p>>=1;
    }
    return res;
}
int main()
{
    LL x,y,a,b;
    rrr(n,x,y); r(a); r(b);
    x%=mod; y%=mod; a%=mod; b%=(mod-1);
    if(n==1){cout<>=1;
    }
    aa=now.f[1][1]+now.f[1][2];
    yy=now.f[2][1]+now.f[2][2];
    yy=yy%(mod-1);
    xx=(aa-yy+(mod-1))%(mod-1);
    aa=(aa-1+(mod-1))%(mod-1);
    //cout< 
 

  

 

  

你可能感兴趣的:(2020牛客寒假算法基础集训营)