[NOIP模拟题][Catalan数][逆元][贪心][线段树][DFS][搜索顺序剪枝]

T1

求Catalan数列,对1e9+9取模,n<=1e6

看到1,2,5,14就应该想到Catalan数,但是Catalan数的递推式里有除法,所以找下逆元就好了,我用的是扩展GCD,所以搞了0.6几秒,应该预处理顺推出逆元

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cmath>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
#define LL long long 
using namespace std;
const int N=1e6,mod=1e9+9;
int T,euler;
LL f[N+3];
int readint()
{
    int x=0; char ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
    return x;
}
void gcd(LL a,LL b,LL &d,LL &x,LL &y)
{
    if (!b) d=a,x=1,y=0;
    else gcd(b,a%b,d,y,x),y-=x*(a/b);
}
LL inv(LL a,LL n)
{
    LL d,x,y;
    gcd(a,n,d,x,y);
    return d==1?(x+n)%n:-1;
}
void init()
{
    f[3]=1; 
    for (int i=3;i<N+2;i++) f[i+1]=(4*i-6)*inv(i,mod)%mod*f[i]%mod;
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    init();
    for (int i=3;i<=N+2;i++) printf(AUTO"\n",f[i]);
    return 0;
}

T2

给定一个int序列,有正有负,给定一个初始值,初始值从左至右累加这个序列,求问至少要移除多少个数,才能保证任意时候初始值大于等于0

贪心无疑,但标算是DP

处理到一个负数使值小于零时,我们就要考虑找这个数和它之前最小的数,然后删去,可用堆来维护最小值
不过这道题数据量很大,用优先队列我怕被卡,又写不来堆,就手写了线段树(中间写的很丑,导致都没有时间做最后一道题)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
#define LL long long 
using namespace std;
const int maxn=1e3+5;
int n,m,cnt,ans,A[maxn],mp[maxn],cur,pos;
LL sum[maxn],S; 
struct Seg
{
    int minnum,key;
}seg[maxn];
#define Lson(x) (x<<1)
#define Rson(x) (x<<1|1)
#define val(x) seg[x].minnum
#define key(x) seg[x].key
int readint()
{
    int x=0,flag=1; char ch=getchar(); 
    while (!isdigit(ch)) {if (ch=='-') flag=-1; ch=getchar();} 
    while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
    return x*flag;
}
void pushup(int tr)
{
    if (val(Lson(tr))<=val(Rson(tr)))
    {
        val(tr)=val(Lson(tr));
        key(tr)=key(Lson(tr));
    }
    else
    {
        val(tr)=val(Rson(tr));
        key(tr)=key(Rson(tr));
    }
}
void update(int L,int R,int tr,int goal,int v)
{
    if (L==R)
    {
        val(tr)=v; key(tr)=L;
        return ;
    }
    int mid=(L+R)>>1;
    if (goal<=mid) update(L,mid,Lson(tr),goal,v);
    else update(mid+1,R,Rson(tr),goal,v);
    pushup(tr);
}
int main()
{
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
    n=readint(); m=readint();
    for (int i=1;i<=n;i++)
    {
        A[i]=readint();
        if (A[i]>=0) sum[i]=sum[i-1]+A[i];
        else  mp[++cnt]=i,sum[i]=0;
    }
    while (m--)
    { 
        memset(seg,0,sizeof(seg));
        ans=0; S=readint(); cur=1;
        while (cur<=cnt)
        {
            update(1,cnt,1,cur,A[mp[cur]]);
            S+=sum[mp[cur]-1]; S+=A[mp[cur]];
            while (S<0)
            {
                ans++; pos=key(1);
                update(1,cnt,1,pos,0); S-=A[mp[pos]];
            }
            cur++;
        }
        printf("%d",ans); putchar('\n'); 
    }
    return 0;
}

T3

NOIP靶形数独

首先为了程序好写一点,我们可以打两个表,一是方格权值,二是所属九宫格位置,不过我还打了两个表
一个重要的剪枝,从限制多的方格开始填数,因为限制多的地方搜索树能够伸展的很少,所以可以尽早的又去限制后面的方格,好吧,只需要这一个剪枝其实就可以过了
似乎inline还真的有用,这道题我加了inline快了0.1s
听说DLX可以很暴力的过掉,只有等NOIP完了再学了

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
int lim[10][10],cnt,ans,A[10][10],S;
bool row[10][10],column[10][10],square[10][10],judge[10][10];
struct Data
{
    int x,y;
}data[60];
const int w[10][10]=
{
    {},
    {0,6,6,6,6,6,6,6,6,6},
    {0,6,7,7,7,7,7,7,7,6},
    {0,6,7,8,8,8,8,8,7,6},
    {0,6,7,8,9,9,9,8,7,6},
    {0,6,7,8,9,10,9,8,7,6},
    {0,6,7,8,9,9,9,8,7,6},
    {0,6,7,8,8,8,8,8,7,6},
    {0,6,7,7,7,7,7,7,7,6},
    {0,6,6,6,6,6,6,6,6,6},
};
const int pos[10][10]=
{
    {},
    {0,1,1,1,2,2,2,3,3,3},
    {0,1,1,1,2,2,2,3,3,3},
    {0,1,1,1,2,2,2,3,3,3},
    {0,4,4,4,5,5,5,6,6,6},
    {0,4,4,4,5,5,5,6,6,6},
    {0,4,4,4,5,5,5,6,6,6},
    {0,7,7,7,8,8,8,9,9,9},
    {0,7,7,7,8,8,8,9,9,9},
    {0,7,7,7,8,8,8,9,9,9},
};
const int X[10][10]=
{
    {},
    {0,1,1,1,1,1,1,1,1,1},
    {0,1,1,1,1,1,1,1,1,1},
    {0,1,1,1,1,1,1,1,1,1},
    {0,4,4,4,4,4,4,4,4,4},
    {0,4,4,4,4,4,4,4,4,4},
    {0,4,4,4,4,4,4,4,4,4},
    {0,7,7,7,7,7,7,7,7,7},
    {0,7,7,7,7,7,7,7,7,7},
    {0,7,7,7,7,7,7,7,7,7},
};
const int Y[10][10]=
{
    {},
    {0,1,1,1,4,4,4,7,7,7},
    {0,1,1,1,4,4,4,7,7,7},
    {0,1,1,1,4,4,4,7,7,7},
    {0,1,1,1,4,4,4,7,7,7},
    {0,1,1,1,4,4,4,7,7,7},
    {0,1,1,1,4,4,4,7,7,7},
    {0,1,1,1,4,4,4,7,7,7},
    {0,1,1,1,4,4,4,7,7,7},
    {0,1,1,1,4,4,4,7,7,7},
};
int readint()
{
    int x=0; char ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
    return x; 
}
void get_order(int order)
{
    int flag=0,curx,cury;
    for (int i=1;i<=9;i++)
      for (int j=1;j<=9;j++)
        if (judge[i][j]==true&&lim[i][j]>flag)
          curx=i,cury=j;
    judge[curx][cury]=false;
    data[order].x=curx; data[order].y=cury;
    for (int i=1;i<=9;i++) lim[curx][i]++,lim[i][cury]++;
    for (int x=X[curx][cury];x<=X[curx][cury]+2;x++)
      for (int y=Y[curx][cury];y<=Y[curx][cury]+2;y++)
        lim[x][y]++;
}
void dfs(int dep,int value)
{
    if (dep==cnt+1)
    {
        ans=max(ans,value);
        return ;
    }
    int x=data[dep].x,y=data[dep].y;
    for (int i=1;i<=9;i++)
      if (row[x][i]&&column[y][i]&&square[pos[x][y]][i])
      {
        row[x][i]=false; column[y][i]=false; square[pos[x][y]][i]=false;
        dfs(dep+1,value+i*w[x][y]);
        row[x][i]=true; column[y][i]=true; square[pos[x][y]][i]=true;
      }
}
int main()
{
    freopen("c.in","r",stdin);
    memset(row,true,sizeof(row));
    memset(column,true,sizeof(column));
    memset(square,true,sizeof(square));
    for (int i=1;i<=9;i++)
      for (int j=1;j<=9;j++)
      {
        A[i][j]=readint();
        if (A[i][j])
        {
            row[i][A[i][j]]=false;
            column[j][A[i][j]]=false;
            square[pos[i][j]][A[i][j]]=false;
            for (int k=1;k<=9;k++) lim[i][k]++,lim[k][j]++;
            for (int x=X[i][j];x<=X[i][j]+2;x++)
              for (int y=Y[i][j];y<=Y[i][j]+2;y++)
                lim[x][y]++;
            S+=A[i][j]*w[i][j];
        }
        else cnt++,judge[i][j]=true;
      }
    for (int i=1;i<=cnt;i++) get_order(i);
    ans=-1; dfs(1,0);
    if (ans==-1) S=0;
    printf("%d",ans+S);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值