T1:
题意:有2N个数,排成两列,要求每一列中的数递增,并且同一位置右边的数比左边的大。
ans(1…4)=1,2,5,14很明显的Catalan数。。
怎么推出来的我也不知道。
F[n] = F[n-1] * (4n-2) / (n+1),预处理逆元。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
template <class T> inline void read(T &x)
{
x = 0;
T flag = 1;
char ch = (char)getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = (char)getchar();
}
while(ch>='0' && ch<='9')
{
x = (x<<1) + (x<<3) + ch - '0';
ch = (char)getchar();
}
x *= flag;
}
template <class T> T gcd(T a,T b) { return !b?a:gcd(b,a%b); }
const int INF=0x3f3f3f3f;
const int mod = 1000000009;
const int maxn = 1000005;
const int N = 1000000;
int inv[maxn];
int Cat[maxn];
void pre_work()
{
inv[1] = 1;
for(int i=2;i<=N+1;i++) inv[i] = (LL) (mod-mod/i)*inv[mod%i]%mod;
Cat[1] = 1;
for(int i=2;i<=N;i++) Cat[i] = (LL) Cat[i-1]*(4*i-2)%mod*inv[i+1]%mod;
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
pre_work();
int T;
read(T);
while(T--)
{
int n;
read(n);
printf("%d\n",Cat[n>>1]);
}
return 0;
}
T2:
题意:有n个数,需要按顺序拿取这n个数,一开始的初值是q,每次给出,拿一个数加上其值,,求至少删除多少个问题才能使任意时刻cur>=0。
解法一:贪心,时间复杂度理论上是O(nmlogn),过不了,但是实际上的复杂度远小于这个值,因为负数没那么多,并且就算有很多,当前cur<0的时候又会pop,用手写的heap很快就可以过。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
template <class T> inline void read(T &x)
{
x = 0;
register T flag = 1;
register char ch = (char)getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = (char)getchar();
}
while(ch>='0' && ch<='9')
{
x = (x<<1) + (x<<3) + ch - '0';
ch = (char)getchar();
}
x *= flag;
}
template <class T> T gcd(T a,T b) { return !b?a:gcd(b,a%b); }
const int INF=0x3f3f3f3f;
const int maxn = 1005;
int a[maxn];
int n,q;
inline void init()
{
read(n); read(q);
for(register int i=1;i<=n;i++) read(a[i]);
}
int que[maxn],maxnode;
inline void push(const int x)
{
que[++maxnode] = x;
int root = maxnode;
while(root > 1)
{
if(que[root] <= que[root>>1]) break;
swap(que[root],que[root>>1]);
root >>= 1;
}
}
inline int pop()
{
int ret = que[1];
que[1] = que[maxnode--];
int root = 1;
while(root < maxnode)
{
int nxt = root<<1;
if(nxt > maxnode) break;
if((nxt|1)<=maxnode && que[nxt]<que[nxt|1]) nxt|=1;
if(que[root] >= que[nxt]) break;
swap(que[root],que[nxt]);
root = nxt;
}
return ret;
}
inline int Greedy()
{
maxnode=0;
int ans = 0;
LL cur; read(cur);
for(register int i=1;i<=n;i++)
{
if(a[i]<0) push(-a[i]);
cur += a[i];
if(cur < 0) ans++,cur+=pop();
}
return ans;
}
int main()
{
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
init();
while(q--) printf("%d\n",Greedy());
return 0;
}
解法二:正解DP
用dp(i,j)表示从i到n这一段的前缀的最小需要值的最大值。
考虑转移,dp(i,j) = min(dp(i+1,j),0) + a[i],也就是如果后面一段是negative,加上当前的负数应该负得更多,所以求其前缀应该加上这段negative,如果是positive,那么直接舍去,因为最小前缀已经在前面出现了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
template <class T> inline void read(T &x)
{
x = 0;
T flag = 1;
char ch = (char)getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = (char)getchar();
}
while(ch>='0' && ch<='9')
{
x = (x<<1) + (x<<3) + ch - '0';
ch = (char)getchar();
}
x *= flag;
}
template <class T> T gcd(T a,T b) { return !b?a:gcd(b,a%b); }
const int INF=0x3f3f3f3f;
const int maxn = 1005;
int a[maxn];
int n,q;
LL dp[maxn][maxn];
void dynamic()
{
memset(dp,0,sizeof(dp));
dp[n+1][0] = 0;
for(int i=n;i;i--)
{
dp[i][n-i+1] = 0;
for(int j=0;j<n-i+1;j++)
{
dp[i][j] = min(dp[i+1][j],0ll) + a[i]; // if positive , abandon the contribution for the first MIN
if(j>=1) smax(dp[i][j],dp[i+1][j-1]);
}
}
}
int work(int x)
{
int l=0,r=n;
while(l < r)
{
int mid = (l+r)>>1;
if(dp[1][mid]+x >= 0) r = mid;
else l = mid + 1;
}
return l;
}
inline void init()
{
read(n); read(q);
for(int i=1;i<=n;i++) read(a[i]);
}
int main()
{
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
init();
dynamic();
while(q--)
{
int x; read(x);
int ans = work(x);
printf("%d\n",ans);
}
return 0;
}
T3:
题意:数独,但是填在不同位置有不同价值,答案就是SIGMA(当前数*对应位置权值)。
正解貌似是搜索加位运算?
DLX很快就出结果了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
template <class T> inline void read(T &x)
{
x = 0;
T flag = 1;
char ch = (char)getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = (char)getchar();
}
while(ch>='0' && ch<='9')
{
x = (x<<1) + (x<<3) + ch - '0';
ch = (char)getchar();
}
x *= flag;
}
template <class T> T gcd(T a,T b) { return !b?a:gcd(b,a%b); }
const int INF=0x3f3f3f3f;
const int maxrow = 9*9*9+5;
const int maxcol = 4*9*9+5;
const int maxn = maxrow*maxcol;
struct Node
{
int left,right,up,down;
int row,col;
}node[maxn];
#define left(x) node[x].left
#define right(x) node[x].right
#define up(x) node[x].up
#define down(x) node[x].down
#define row(x) node[x].row
#define col(x) node[x].col
int rows,cols;
int maxnode,mustselect;
int tot[maxcol];
int head;
inline void disable_row(int root)
{
left(right(root)) = left(root);
right(left(root)) = right(root);
}
inline void disable_col(int root)
{
up(down(root)) = up(root);
down(up(root)) = down(root);
}
inline void enable_row(int root)
{
left(right(root)) = root;
right(left(root)) = root;
}
inline void enable_col(int root)
{
up(down(root)) = root;
down(up(root)) = root;
}
inline void remove(int colnum)
{
disable_row(colnum);
for(int i=down(colnum);i^colnum;i=down(i))
for(int j=right(i);j^i;j=right(j))
disable_col(j),tot[col(j)]--;
}
inline void restore(int colnum)
{
enable_row(colnum);
for(int i=up(colnum);i^colnum;i=up(i))
for(int j=left(i);j^i;j=left(j))
enable_col(j),tot[col(j)]++;
}
inline void initialize()
{
memset(node,0,sizeof(node));
memset(tot,0,sizeof(tot));
rows=0; cols=4*9*9;
head=0;
left(head)=cols; right(head)=1;
for(int i=1;i<=cols;i++)
{
left(i) = i-1;
right(i) = i+1;
up(i) = i;
down(i) = i;
row(i) = 0;
col(i) = i;
}
right(cols) = head;
maxnode=cols;
mustselect = 0;
}
struct Info
{
int x,y;
int num;
Info(const int _x = 0,const int _y = 0,const int _num = 0)
{
x=_x; y=_y; num=_num;
}
}val[maxrow];
int a[maxcol];
Info ans[maxrow];
int top;
void add_row(int a[maxcol],int cnt,Info info)
{
rows++;
val[rows] = info;
for(int i=1;i<=cnt;i++)
{
maxnode++;
tot[a[i]]++;
if(i==1)
{
left(maxnode) = maxnode;
right(maxnode) = maxnode;
}
else
{
left(maxnode) = maxnode-1;
right(maxnode) = right(maxnode-1);
enable_row(maxnode);
}
up(maxnode) = up(a[i]);
down(maxnode) = a[i];
enable_col(maxnode);
col(maxnode) = a[i];
row(maxnode) = rows;
}
}
void insert_num(int i,int j,int num)
{
int N = (i-1)/3*3 + (j-1)/3 + 1;
a[1] = (i-1)*9 + j;
a[2] = (i-1)*9 + num + 81;
a[3] = (j-1)*9 + num + 162;
a[4] = (N-1)*9 + num + 243;
add_row(a,4,Info(i,j,num));
ans[mustselect++] = val[rows];
for(int i=1;i<=4;i++) tot[a[i]]=-1,remove(a[i]);
}
void insert_empty(int i,int j)
{
int N = (i-1)/3*3 + (j-1)/3 + 1;
a[1] = (i-1)*9 + j;
a[2] = (i-1)*9 + 81;
a[3] = (j-1)*9 + 162;
a[4] = (N-1)*9 + 243;
for(int k=1;k<=9;k++)
{
a[2]++; a[3]++; a[4]++;
bool flag=true;
for(int p=1;p<=4;p++)
if(!~tot[a[p]]) flag=false;
if(flag) add_row(a,4,Info(i,j,k));
}
}
const int VAL[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}
};
int g[100][100];
int ANS;
bool flag;
void update()
{
flag = true;
memset(g,0,sizeof(g));
for(int i=0;i<top;i++)
{
Info tmp = ans[i];
g[tmp.x][tmp.y] = tmp.num;
}
int now = 0;
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
now += VAL[i][j] * g[i][j];
smax(ANS,now);
}
void Dance(int k)
{
int c1 = right(head);
if(c1 == head)
{
top = k;
update();
return;
}
for(int i=right(c1);i^head;i=right(i))
{
if(tot[i] < tot[c1]) c1 = i;
if(!tot[i]) return;
}
remove(c1);
for(int i=down(c1);i^c1;i=down(i))
{
ans[k] = val[row(i)];
for(int j=right(i);j^i;j=right(j)) remove(col(j));
Dance(k+1);
for(int j=left(i);j^i;j=left(j)) restore(col(j));
}
restore(c1);
}
const int maxlen = 11;
int graph[maxlen][maxlen];
void init()
{
initialize();
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
read(graph[i][j]);
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
if(graph[i][j]) insert_num(i,j,graph[i][j]);
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
if(!graph[i][j]) insert_empty(i,j);
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
init();
Dance(mustselect);
if(flag) printf("%d",ANS);
else printf("-1");
return 0;
}