CXMS 胡策2

T1: 

.Double color chessboard
程序名称:dcc.pas/c/cpp
时间限制:2000ms
空间限制:8MB
题目描述
有一个游戏:给出一个n行n列的棋盘,里面有n*n个方格,其中每个格子上有颜色,总共
两种颜色0和1。
Bob要遵循规则去玩:一张卡要正好覆盖两个相邻且同色的正常格子。
我们的任务是帮助Bob知道棋盘在上述规则下能覆盖多少格子。
输入格式
第1行:整数n表示棋盘的长和宽。
第2行到第n+1行,有n个数,表示棋盘颜色。
输出格式
一个整数,表示能覆盖多少格子。
n<=300
题目

坑点在于8M的空间,表示用一个unsigned short 和 char 代替 int 网络流跑。

发现wa了,原因在于二分图转流的时候不是加无向边。

#include<bits/stdc++.h>
#define us unsigned short
#define ma 60000
#define p(x,y) ((x)*301+(y)-1)
using namespace std;
struct Node{
    us x; char op;
    int into() {return op*ma+x;}
    void out(int xx){op=xx/ma;x=xx%ma;}
};
struct Maxflow{
    #define N 97007
    #define M 541007  
    #define eho(x) for(int i=head[x].into();i;i=net[i].into())
    #define Eho(x) eho(x)
    #define inf 50007
    int tim;
    int p[M];
    Node fall[M],net[M],head[N],que[N];
    int n,tot,s,t,be,ed,gap[N],d[N],x,ret;
    unsigned char cost[M];
    Maxflow() {tot=1;}
    inline void add(int x,int y,int z){
        fall[++tot].out(y); net[tot]=head[x]; head[x].out(tot); cost[tot]=z;
    }
    inline void Adds(int x,int y,int z){
        add(x,y,z); add(y,x,z);
    }
    inline void adds(int x,int y,int z){
        add(x,y,z); add(y,x,0);
    }
    void init() {
        ++gap[d[t]=1];
        que[be=ed=1].out(t);
        while (be<=ed) {
            x=que[be++].into();
            eho(x) if (!d[fall[i].into()]) ++gap[d[fall[i].into()]=d[x]+1],que[++ed]=fall[i]; 
        }
    }
    us get(int x,int fl){
        if (x==t) return fl; if (!fl) return 0;
        p[x]=tim;
        int flow=0,tmp;
        Eho(x) if (d[x]==d[fall[i].into()]+1&&(tmp=get(fall[i].into(),min(fl,(int)cost[i])))) {
            flow+=tmp; fl-=tmp; cost[i]-=tmp; cost[i^1]+=tmp; 
            if (!fl) return flow;
        }
        if (!(--gap[d[x]])) d[s]=n+1;
        ++gap[++d[x]];
        return flow; 
    }
    int isap(int S,int T,int Siz){
        s=S; t=T; n=Siz; init();
        ++tim; ret=get(s,inf);
        while (d[s]<=n) ++tim,ret+=get(s,inf);
        return ret;
    }
}G;
int s=p(301,0),t=p(301,1),xx;
int n; bitset<307> a[307];
signed main () {
    freopen("dcc.in","r",stdin);
    freopen("dcc.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
     for (int j=1;j<=n;j++) scanf("%d",&xx),a[i][j]=xx;
    for (int i=1;i<=n;i++)
     for (int j=1;j<=n;j++) {
         if ((i+j)&1) {
          G.adds(s,p(i,j),1); 
          if (j<n&&a[i][j]==a[i][j+1]) G.adds(p(i,j),p(i,j+1),1);
           if (i<n&&a[i][j]==a[i+1][j]) G.adds(p(i,j),p(i+1,j),1); 
        }
         else {
          G.adds(p(i,j),t,1); 
          if (j<n&&a[i][j]==a[i][j+1]) G.adds(p(i,j+1),p(i,j),1);
           if (i<n&&a[i][j]==a[i+1][j]) G.adds(p(i+1,j),p(i,j),1); 
        }
     }
     printf("%d\n",G.isap(s,t,n*n+3)*2);
}
View Code

T2:

题目描述
农场主Bob有无限的奶牛,奶牛分为A,B两种类型。现在Bob要选出N(2≤N≤10
15)头奶牛,
并把这N头奶牛围成一个环。为了美观且不单调,Bob希望任意相邻M(2≤M≤5,M≤N)头奶牛中
有不超过K(1≤K<M)头A类型的奶牛,其余奶牛均为B类型的奶牛。并且Bob想知道总共有多少
种不同的环。(结果 mod 1000000007)。
n<=1e15
题目

快速幂。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int M=5,p=1000000007;
LL n,m,k,ans;
LL f[1<<M],a[1<<M][1<<M];
int MAX,cnt;
bool pd[1<<M];
inline void mulself(LL a[1<<M][1<<M]) {
    LL c[1<<M][1<<M];
    memset(c,0, sizeof c);
    for(int i=0;i<MAX;++i)
        for(int j=0;j<MAX;++j)
            for(int k=0;k<MAX;++k)
                c[i][j]=(c[i][j]+a[i][k]*a[k][j])%p;
    memmove(a,c,sizeof c);
}
inline void mul(LL f[1<<M],LL a[1<<M][1<<M]) {
    static LL c[1<<M];
    memset(c,0,sizeof c);
    for(int j=0;j<MAX;++j)
        for(int k=0;k<MAX;++k)
            c[j]=(c[j]+f[k]*a[k][j])%p;
    memmove(f,c,sizeof c);
}
int main() {
    freopen("k.in","r",stdin);
    freopen("k.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&k);
    MAX=1<<m;
    for(int i=0;i<MAX;++i) {
        cnt=0;
        for(int j=0;j<m;++j)
            if(i&1<<j) ++cnt;
        if(cnt<=k) pd[i]=true;
    }
    for(int i=0;i<MAX;++i)
        if(pd[i]) {
            memset(f,0,sizeof f);f[i]=1;
            memset(a,0,sizeof a);
            for(int j=0;j<MAX;++j) if(pd[j]){
                a[j>>1][j]=1;
                a[(j>>1)+(1<<(m-1))][j]=1;
            }
            for(LL y=n;y;y>>=1,mulself(a)) if(y&1) mul(f,a);
            ans=(ans+f[i])%p;
        }
    printf("%lld\n",ans);
    return 0;
}
View Code

T3:

 buyef
程序名称:buyef.pas/c/cpp
时间限制:2000ms
空间限制:32MB
问题描述
CQH想要潜入女生宿舍,因此他不但需要策划完美的潜入路线,更要购买一些女装进行掩
饰。
商店里总共有N(1≤N≤10
6)件女装,第i件女装的价格为Wi(1≤Wi≤300),萌值为
Vi(1≤Vi≤10
9)。
CQH有一个总预算K(1≤K≤10
5),他希望知道对于每个[1,k]中的整数i,如果他带了i
元,能买到的女装的萌值之和最大是多少。由于CQH正在策划路线,这个问题就交给你了。
输入格式
第一行N和K。
接下来N行,每行Wi和Vi。
输出格式
第一行K个数,第i个数表示带了i元时的答案。
20% N≤300100% 1≤N≤1000000
1≤Wi≤3001≤Vi≤100000
1≤K≤100000
题目

对Wi分组sort,对每个Wi做决策分治。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
#define pb push_back
#define N 1001007
int n,m,w,k,b,lo,o,VV,K;
vector<LL> v[307];
LL f[2][N];
#define sight(c) ('0'<=c&&c<='9')
inline void read(int &x){
    static char c;
    for (c=getchar();!sight(c);c=getchar());
    for (x=0;sight(c);c=getchar())x=x*10+c-48;
}
void write(LL x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);}
inline void writeln(LL x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); }
inline void writel(LL x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); }
void solve(int l,int r,int L,int R){
    if (l>r) return ;
    int Mid=l+r>>1,d=Mid;
    LL tmp;
    f[o][Mid*k+b]=f[lo][Mid*k+b];
    for (int i=min(R,Mid-1);i>=L;i--) {
        if (Mid-i>v[k].size()) break;
        if ((tmp=f[lo][i*k+b]+v[k][Mid-i-1])>f[o][Mid*k+b]) 
          f[o][Mid*k+b]=tmp,d=i;
    }
    solve(l,Mid-1,L,d); solve(Mid+1,r,d,R);
}
int main () {
    freopen("buyef.in","r",stdin);
    freopen("buyed.out","w",stdout);
    read(n); read(m);
    for (int i=1;i<=n;i++){
        read(w); read(VV);
        K=max(K,w);
        v[w].pb(VV);
    }
//    cerr<<"rrsb"<<K;
    for (int i=1;i<=K;i++)  
     sort(v[i].begin(),v[i].end(),greater<LL>());
//    cerr<<"rrsb";
    for (int i=1;i<=K;i++) 
     for (int j=1;j<v[i].size();j++) v[i][j]+=v[i][j-1];
    o=1; 
    
    for (k=1;k<=K;k++) {
        if (!v[k].size()) continue;
        for (b=0;b<k;b++) solve(0,(m-b)/k,0,(m-b)/k);
        for (int i=1;i<=m;i++) f[o][i]=max(f[o][i],f[o][i-1]);
        o^=1; lo^=1;
    }
    for (int i=1;i<=m;i++) 
     writel(f[lo][i]);
    return 0;
}
View Code

 

posted @ 2018-05-20 18:17  泪寒之雪  阅读(238)  评论(0编辑  收藏  举报