NOIP模拟题 2016.11.12 [Catalan数] [贪心] [动态规划] [DLX] [数独]

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;
}
原创文章 152 获赞 15 访问量 6万+

猜你喜欢

转载自blog.csdn.net/ourfutr2330/article/details/53140421