cqoi2018

题解:

很多模板题

第一次写莫队还比较顺利

除了把排序的cmp写错。。(还第一次遇到)

这题分块也可以

先预处理出g[i][j]代表前i个块,颜色为j的有多少种

f[i][j]表示i-j的块能构成多少对

处理的方法就是f[i][j-1]+j块内和j与j之前

算答案的时候即整块+两个单独块内部和两个单独块与整块之间

因为分块有几个地方都是$n\sqrt{n}$的 所以分块的常数比莫队要来的大

#include 

using namespace std;

#define rint register int

#define IL inline

#define rep(i,h,t) for (int i=h;i<=t;i++)

#define dep(i,t,h) for (int i=t;i>=h;i--)

#define ll long long 

#define me(x) memset(x,0,sizeof(x))

namespace IO

{

    char ss[1<<24],*A=ss,*B=ss;

    IL char gc()

    {

        return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;

    }

    template<class T>void read(T &x)

    {

        rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);

        while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;

    }

    char sr[1<<24],z[20]; int Z,C=-1;

    template<class T>void wer(T x)

    {

        if (x<0) sr[++C]='-',x=-x;

        while (z[++Z]=x%10+48,x/=10);

        while (sr[++C]=z[Z],--Z);

    }

    IL void wer1()

    {

        sr[++C]=' ';

    }

    IL void wer2()

    {

        sr[++C]='\n';

    }

    template<class T>IL void maxa(T &x,T y) {if (xy;}

    template<class T>IL void mina(T &x,T y) {if (x>y) x=y;}

    template<class T>IL T MAX(T x,T y){return x>y?x:y;}

    template<class T>IL T MIN(T x,T y){return xx:y;}

};

using namespace IO;

const int N=1e5+10;

const int M=350;

int n,m,k,block,q;

int a[N],pos[N],b[N],now1[N],now2[N];

ll ans2[N];

struct re{

    int a,b,c;

}p[N];

ll ans=0;

bool cmp(re x,re y)

{

    return pos[x.a]y.b);

}

IL void insert1(int x,int y)

{

    if (y==1)

    {

      now2[b[x]]+=y;

      now1[b[x-1]]+=y;

    }

    ans+=now2[b[x-1]^k]*y;

    if (y==-1)

    {

      now2[b[x]]+=y;

      now1[b[x-1]]+=y;

    }

}

IL void insert2(int x,int y)

{

    if (y==1)

    {

        now2[b[x]]+=y;

        now1[b[x-1]]+=y;

    }

    ans+=now1[b[x]^k]*y;

    if (y==-1)

    {

        now2[b[x]]+=y;

        now1[b[x-1]]+=y;

    }

}

int main()

{

    freopen("1.in","r",stdin);

    freopen("1.out","w",stdout);

    read(n); read(q); read(k);

    rep(i,1,n) read(a[i]);

    block=sqrt(n);

    m=(n-1)/block+1;

    rep(i,1,n) pos[i]=(i-1)/block+1;

    rep(i,1,q)

      read(p[i].a),read(p[i].b),p[i].c=i;

    sort(p+1,p+q+1,cmp);

    rep(i,1,n) b[i]=b[i-1]^a[i];

    rep(i,p[1].a,p[1].b)

    {

        now1[b[i-1]]++;

        ans+=now1[b[i]^k];

        now2[b[i]]++;

    }

    ans2[p[1].c]=ans;

    rep(i,2,q)

    {

        if (p[i].a>p[i-1].a)

          rep(j,p[i-1].a,p[i].a-1)

            insert1(j,-1);

        else dep(j,p[i-1].a-1,p[i].a) insert1(j,1);

        if (p[i].b>p[i-1].b)

          rep(j,p[i-1].b+1,p[i].b) insert2(j,1);

        else dep(j,p[i-1].b,p[i].b+1) insert2(j,-1);

        ans2[p[i].c]=ans;

    }

    rep(i,1,q) wer(ans2[i]),wer2();

    fwrite(sr,1,C+1,stdout);

    return 0;

}

 

题目上面画个矩形下面用点真的是傻逼

要是是矩形的画就比较麻烦 要判断4条边是否与那个线相交

可以写特殊处理 当然也可以直接用计算几何里的线段与线段相交判定了

要是直线的画直接叉积就可以了

预处理一下再状压dp

不太卡常

#include 
using namespace std;
#define rint register int
#define IL inline
#define rep(i,h,t) for (int i=h;i<=t;i++)
#define dep(i,t,h) for (int i=t;i>=h;i--)
#define ll long long 
#define me(x) memset(x,0,sizeof(x))
namespace IO
{
    char ss[1<<24],*A=ss,*B=ss;
    IL char gc()
    {
        return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
    }
    template<class T>void read(T &x)
    {
        rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
        while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;
    }
    char sr[1<<24],z[20]; int Z,C=-1;
    template<class T>void wer(T x)
    {
        if (x<0) sr[++C]='-',x=-x;
        while (z[++Z]=x%10+48,x/=10);
        while (sr[++C]=z[Z],--Z);
    }
    IL void wer1()
    {
        sr[++C]=' ';
    }
    IL void wer2()
    {
        sr[++C]='\n';
    }
    template<class T>IL void maxa(T &x,T y) {if (xy;}
    template<class T>IL void mina(T &x,T y) {if (x>y) x=y;}
    template<class T>IL T MAX(T x,T y){return x>y?x:y;}
    template<class T>IL T MIN(T x,T y){return xx:y;}
};
using namespace IO;
double ee=1.0000000000000000;
const double eps=1e-9;
const int N=(1<<20)+1000;
const int mo=100000007;
int n;
int f[21][N];
int p[40][40];
struct re{
    int x,y;
}a[40];
IL void js(register int &x,register int y)
{
    x=(x+y>mo)?x+y-mo:x+y;
}
int main()
{
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    read(n);
    rep(i,1,n)
    {
        read(a[i].x); read(a[i].y);
    }
    rep(i,1,n)
      rep(j,1,n)
        if (i!=j)
        rep(k,1,n)
        if (k!=i&&k!=j)
        {
          /*if (a[i].x==a[j].x)
          {
            if (a[k].x==a[i].x&&a[k].y>=MIN(a[i].y,a[j].y)&&a[k].y<=MAX(a[i].y,a[j].y))
              p[i][j]|=(1<<(k-1));
          }
          else
          {
              double now=ee*(a[j].y-a[i].y)/(a[j].x-a[i].x)*(a[k].x-a[i].x)+a[i].y;
            if (a[k].x<=MAX(a[i].x,a[j].x)&&a[k].x>=MIN(a[i].x,a[j].x)&&now+eps>a[k].y&&now*/
          if (a[k].x<=MAX(a[i].x,a[j].x)&&a[k].x>=MIN(a[i].x,a[j].x)&&a[k].y<=MAX(a[i].y,a[j].y)&&a[k].y>=MIN(a[i].y,a[j].y)
              &&(a[k].x-a[i].x)*(a[j].y-a[k].y)-(a[j].x-a[k].x)*(a[k].y-a[i].y)==0)
                p[i][j]|=1<<(k-1);
        }
    rep(i,1,n) f[i][1<<(i-1)]=1;
    int l=(1<1;
    int ans=0;
    rep(i,1,l)
      rep(j,1,n)
        if (f[j][i])
        {
            rep(k,1,n)
              if (((i>>(k-1))&1)==0&&(p[j][k]&(~i))==0) js(f[k][i|(1<<(k-1))],f[j][i]);
            if (__builtin_popcount(i)>=4) js(ans,f[j][i]);
        }
    wer(ans);
    fwrite(sr,1,C+1,stdout);
    return 0;
}

 

[CQOI2018]交错序列

这可能是六题里唯一一题不是模板的题

首先最暴力的做法

就是$f[i][j][0/1]$表示前i个数有j个1且当前是0/1的方案数

复杂度$O(n^2)$

发现这个dp方程比较简单,考虑直接用数学方法求解

先放1,然后再插空 答案就是$C(n-k+1,k)*k^a*(n-k)^b$

这个东西$nlogn$ 因为模数比较小 所以组合数需要用lucas定理计算

据游记所说这种做法好像并不能卡过?

晚上写

然后注意到这题a,b比较小

考虑去展开$k^a*(n-k)^b$

会发现我们只需要维护$k^{1~(a+b)}$就可以了

然后$(k+1)^x$这个东西又可以用关于k的次方递推

于是就可以上矩阵快速幂了

时间复杂度$(a+b)^3*logn$

转载于:https://www.cnblogs.com/yinwuxiao/p/10018490.html

你可能感兴趣的:(cqoi2018)