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;
}