ASC 16

A Cactus

给一棵树,可以连边(不能连重边),问连出仙人掌的方案数。
把模型转化为,给树染色,要求相同颜色的形成一条长度大于1的链或单点,树形dp

#include<bits/stdc++.h>

using namespace std;

const double eps=1e-10;
const double pi=3.1415926535897932384626433832795;
const double eln=2.718281828459045235360287471352;

#define IN freopen("cactus.in", "r", stdin)
#define OUT freopen("cactus.out", "w", stdout)
#define scan(x) scanf("%d", &x)
#define mp make_pair
#define pb push_back
#define sqr(x) (x) * (x)
#define pr(x) printf("Case %d: ",x)
#define prn(x) printf("Case %d:\n",x)
#define prr(x) printf("Case #%d: ",x)
#define prrn(x) printf("Case #%d:\n",x)
#define lowbit(x) (x&(-x))
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vi;

struct BigInteger {
    typedef unsigned long long LL;

    static const int BASE = 100000000;
    static const int WIDTH = 8;
    vector<int> s;

    BigInteger& clean(){while(!s.back()&&s.size()>1)s.pop_back(); return *this;}
    BigInteger(LL num = 0) {*this = num;}
    BigInteger(string s) {*this = s;}
    BigInteger& operator = (long long num) {
        s.clear();
        do {
            s.push_back(num % BASE);
            num /= BASE;
        } while (num > 0);
        return *this;
    }
    BigInteger& operator = (const string& str) {
        s.clear();
        int x, len = (str.length() - 1) / WIDTH + 1;
        for (int i = 0; i < len; i++) {
            int end = str.length() - i*WIDTH;
            int start = max(0, end - WIDTH);
            sscanf(str.substr(start,end-start).c_str(), "%d", &x);
            s.push_back(x);
        }
        return (*this).clean();
    }

    BigInteger operator + (const BigInteger& b) const {
        BigInteger c; c.s.clear();
        for (int i = 0, g = 0; ; i++) {
            if (g == 0 && i >= s.size() && i >= b.s.size()) break;
            int x = g;
            if (i < s.size()) x += s[i];
            if (i < b.s.size()) x += b.s[i];
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c;
    }
    BigInteger operator - (const BigInteger& b) const {
        assert(b <= *this); // 减数不能大于被减数
        BigInteger c; c.s.clear();
        for (int i = 0, g = 0; ; i++) {
            if (g == 0 && i >= s.size() && i >= b.s.size()) break;
            int x = s[i] + g;
            if (i < b.s.size()) x -= b.s[i];
            if (x < 0) {g = -1; x += BASE;} else g = 0;
            c.s.push_back(x);
        }
        return c.clean();
    }
    BigInteger operator * (const BigInteger& b) const {
        int i, j; LL g;
        vector<LL> v(s.size()+b.s.size(), 0);
        BigInteger c; c.s.clear();
        for(i=0;i<s.size();i++) for(j=0;j<b.s.size();j++) v[i+j]+=LL(s[i])*b.s[j];
        for (i = 0, g = 0; ; i++) {
            if (g ==0 && i >= v.size()) break;
            LL x = v[i] + g;
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c.clean();
    }
    BigInteger operator / (const BigInteger& b) const {
        assert(b > 0);  // 除数必须大于0
        BigInteger c = *this;       // 商:主要是让c.s和(*this).s的vector一样大
        BigInteger m;               // 余数:初始化为0
        for (int i = s.size()-1; i >= 0; i--) {
            m = m*BASE + s[i];
            c.s[i] = bsearch(b, m);
            m -= b*c.s[i];
        }
        return c.clean();
    }
    BigInteger operator / (const ll& b) const {
        assert(b > 0);  // 除数必须大于0
        BigInteger c = *this;       // 商:主要是让c.s和(*this).s的vector一样大
        ll m=0;               // 余数:初始化为0
        for (int i = s.size()-1; i >= 0; i--) {
            m = m*BASE + s[i];
            c.s[i] = m/b ;
            m -= b*c.s[i];
        }

        return c.clean();
    }
    BigInteger operator % (const ll& b) const {
        assert(b > 0);  // 除数必须大于0
        BigInteger c = *this;       // 商:主要是让c.s和(*this).s的vector一样大
        ll m=0;               
        for (int i = s.size()-1; i >= 0; i--) {
            m = m*BASE + s[i];
            m%=b;
        }

        return BigInteger(m);
    }

    BigInteger operator % (const BigInteger& b) const { //方法与除法相同
        BigInteger c = *this;
        BigInteger m;
        for (int i = s.size()-1; i >= 0; i--) {
            m = m*BASE + s[i];
            c.s[i] = bsearch(b, m);
            m -= b*c.s[i];
        }
        return m;
    }

    // 二分法找出满足bx<=m的最大的x
    int bsearch(const BigInteger& b, const BigInteger& m) const{
        int L = 0, R = BASE-1, x;
        while (1) {
            x = (L+R)>>1;
            if (b*x<=m) {if (b*(x+1)>m) return x; else L = x;}
            else R = x;
        }
    }
    BigInteger& operator += (const BigInteger& b) {*this = *this + b; return *this;}
    BigInteger& operator -= (const BigInteger& b) {*this = *this - b; return *this;}
    BigInteger& operator *= (const BigInteger& b) {*this = *this * b; return *this;}
    BigInteger& operator /= (const BigInteger& b) {*this = *this / b; return *this;}
    BigInteger& operator %= (const BigInteger& b) {*this = *this % b; return *this;}

    BigInteger& operator /= (const ll& b) {*this = *this / b; return *this;}
    BigInteger& operator %= (const ll& b) {*this = *this % b; return *this;}


    bool operator < (const BigInteger& b) const {
        if (s.size() != b.s.size()) return s.size() < b.s.size();
        for (int i = s.size()-1; i >= 0; i--)
            if (s[i] != b.s[i]) return s[i] < b.s[i];
        return false;
    }
    bool operator >(const BigInteger& b) const{return b < *this;}
    bool operator<=(const BigInteger& b) const{return !(b < *this);}
    bool operator>=(const BigInteger& b) const{return !(*this < b);}
    bool operator!=(const BigInteger& b) const{return b < *this || *this < b;}
    bool operator==(const BigInteger& b) const{return !(b < *this) && !(b > *this);}
};

ostream& operator << (ostream& out, const BigInteger& x) {
    out << x.s.back();
    for (int i = x.s.size()-2; i >= 0; i--) {
        char buf[20];
        sprintf(buf, "%08d", x.s[i]);
        for (int j = 0; j < strlen(buf); j++) out << buf[j];
    }
    return out;
}

istream& operator >> (istream& in, BigInteger& x) {
    string s;
    if (!(in >> s)) return in;
    x = s;
    return in;
}

const int maxn=205;
BigInteger dp[maxn][4];
vi g[maxn];
int n;

void DFS(int u,int f)
{
    if(g[u].size()==1 && g[u][0]==f)
    {
        dp[u][1]=0;
        dp[u][0]=0;
        dp[u][2]=1;
        dp[u][3]=0;
        return;
    }
    dp[u][2]=1;dp[u][0]=dp[u][1]=dp[u][3]=0;
    for(int p : g[u])
        if(p!=f)DFS(p,u);
    int l=g[u].size();
    BigInteger cj=1;
    for(int p : g[u])
        if(p!=f)
        {
            dp[u][2]*=(dp[p][0]+dp[p][1]+dp[p][2]-dp[p][3]);
            //xj*=(dp[p][0]+dp[p][1]+dp[p][2]-dp[p][3]);
        }
    cj=dp[u][2];
    for(int i=0;i<l;i++)
        for(int j=i+1;j<l;j++)
        {
            int x=g[u][i],y=g[u][j];
            if(x==f || y==f)continue;
            dp[u][0]+=cj/(dp[x][0]+dp[x][1]+dp[x][2]-dp[x][3])/(dp[y][0]+dp[y][1]+dp[y][2]-dp[y][3])*(dp[x][1]+dp[x][2])*(dp[y][1]+dp[y][2]);
        }
    for(int x : g[u])
        if(x!=f)
        {
            dp[u][3]+=cj/(dp[x][0]+dp[x][1]+dp[x][2]-dp[x][3])*dp[x][2];
            dp[u][1]+=cj/(dp[x][0]+dp[x][1]+dp[x][2]-dp[x][3])*(dp[x][2]+dp[x][1]);
        }
}

int main()
{
    IN;OUT;
    scanf("%d",&n);
    if(n==1){printf("1\n");return 0;}
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        g[x].pb(y);g[y].pb(x);
    }
    DFS(1,0);
    cout<<dp[1][0]+dp[1][1]+dp[1][2]-dp[1][3]<<endl;
    return 0;
}

C Domino in Casino

给1个n*m的矩阵(元素均为正数),你可以选k个不重叠的1*2小矩形,问所以小矩形的2个数的乘积的和最大是多少。
就是简单网络流

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (100000+10)
#define MAXM (100000+10)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
class Cost_Flow  
{  
public:  
    int n,s,t;  
    int q[MAXM];  
    int edge[MAXM],Next[MAXM],Pre[MAXN],weight[MAXM],size;  
    int cost[MAXM];  
    void addedge(int u,int v,int w,int c)    
    {    
        edge[++size]=v;    
        weight[size]=w;    
        cost[size]=c;    
        Next[size]=Pre[u];    
        Pre[u]=size;    
    }    
    void addedge2(int u,int v,int w,int c=0){addedge(u,v,w,c),addedge(v,u,0,-c);}   
    bool b[MAXN];  
    int d[MAXN];  
    int pr[MAXN],ed[MAXN];  
    bool SPFA(int s,int t)    
    {    
        For(i,n) d[i]=INF,b[i]=0; 
        d[q[1]=s]=0;b[s]=1;    
        int head=1,tail=1;    
        while (head<=tail)    
        {    
            int now=q[head++];    
            Forp(now)    
            {    
                int &v=edge[p];    
                if (weight[p]&&d[now]+cost[p]<d[v])    
                {    
                    d[v]=d[now]+cost[p];    
                    if (!b[v]) b[v]=1,q[++tail]=v;    
                    pr[v]=now,ed[v]=p;    
                }    
            }    
            b[now]=0;    
        }    
        return d[t]!=INF;    
    }   
    int totcost;    

    int CostFlow(int s,int t)    
    {    
        int maxflow=0;
        while (SPFA(s,t))    
        {    
            int flow=INF;    
            for(int x=t;x^s;x=pr[x]) flow=min(flow,weight[ed[x]]); 
            totcost+=flow*d[t]; 
            maxflow+=flow;   
            for(int x=t;x^s;x=pr[x]) weight[ed[x]]-=flow,weight[ed[x]^1]+=flow;         
        }    
//        cout<<maxflow<<endl;
        return totcost;    
    }    
    void mem(int n,int t)  
    {  
        (*this).n=n;  
        size=1;  
        totcost=0;  
        MEM(Pre) MEM(Next)   
    }  
}S;  
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
ll id[120][120];
ll a[120][120];
int main()
{
    freopen("domino.in","r",stdin);
    freopen("domino.out","w",stdout);
    int m=read(),n=read(),k=read();
    int p1=0,p2=0;
    For(i,m) For(j,n) {
        a[i][j]=read();
        id[i][j]=++p1;
    }
    int s=++p1,ta=++p1,tb=++p1;
    S.mem(p1,p1);
    For(i,m) For(j,n) {
        if ((i+j)%2==0) {
            S.addedge2(s,id[i][j],1);
            if (i<m) S.addedge2(id[i][j],id[i+1][j],1,-a[i][j]*a[i+1][j]);
            if (j<n) S.addedge2(id[i][j],id[i][j+1],1,-a[i][j]*a[i][j+1]);
            if (i>1) S.addedge2(id[i][j],id[i-1][j],1,-a[i][j]*a[i-1][j]);
            if (j>1) S.addedge2(id[i][j],id[i][j-1],1,-a[i][j]*a[i][j-1]);
        }else {
            S.addedge2(id[i][j],ta,1);
        }
    }
    S.addedge2(ta,tb,k);
    cout<<-S.CostFlow(s,tb)<<endl;


    return 0;
}

E Set Partitions

我们定义一个集合大小的比较方式是,集合中的元素从小到大排序后得到的序列的字典序。定义一个集合的划分的比较是,先比较最小的,再比较次小的……,直到比出为止。现在有1~n个整数拆分到若干非空集合中,已知某个划分方案,问这个划分的下一个划分(next_permutation)是?

#include<cstdio>
#include<set>
using namespace std;
int a[501];
int main()
{
    freopen("partitions.in","r",stdin);
    freopen("partitions.out","w",stdout);
    int n,m;
    while(scanf("%d%d",&n,&m)==2&&n){
        int cnt=0;
        getchar();
        for(int i=0;i<m;i++){
            do scanf("%d",&a[cnt++]);
            while(getchar()!='\n');
            a[cnt++]=0;
        }
        set<int> s;s.insert(a[cnt-2]);
        bool flag=false;
        for(int i=cnt-3;i>0;i--){
            if(!a[i])m--;
            else s.insert(a[i]);
            if(a[i-1]){
                auto it=s.upper_bound(a[i]?a[i]:a[i-1]);
                if(it!=s.end()){
                    a[i]=*it;
                    s.erase(it);
                    cnt=i+1;a[cnt]=0;
                    flag=true;break;
                }
            }
        }
        printf("%d ",n);
        if(flag){
            printf("%d\n",m+s.size());
            for(int i=0;i<=cnt;i++){
                if(a[i])printf("%d ",a[i]);
                else printf("\n");
            }
            for(int t:s)
                printf("%d\n",t);
        }
        else{
            printf("%d\n",n);
            for(int i=1;i<=n;i++)
                printf("%d\n",i);
        }
        printf("\n");
    }
}
close

F Pipe Layout

r*c的矩阵的哈密尔顿回路个数(r*c<=100)

经典题,打表过。

I HTML Table

大模拟

#include<bits/stdc++.h> 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
                        For(j,m-1) cout<<a[i][j]<<' ';\
                        cout<<a[i][m]<<endl; \
                        } 
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
#define fr(x) freopen(x,"r",stdin)
#define fw(x) freopen(x,"w",stdout)
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
string Filename="table";
int f[3100][3100]={},color=0;
char Map[3100][3100]={};
int last_tag;
int col,row;
bool _is_end;
// last_tag = 0(table) 1(tr) 2(td) 3(col) 4(wol) 
int main()
{
    freopen((Filename+".in").c_str(), "r", stdin);
    freopen((Filename+".out").c_str(), "w", stdout);
    MEM(f)
    char ch,lch;
    int n=0,m=0,cnt=0;
    int p=0,l=0,pl[3]={};
    int nowi=0,nowj;
    lch=0;
    bool b=0;
    int N=0,M=0;
    while(1) {
        lch=ch;
        ch=getchar();
        ch=tolower(ch);
//      cout<<lch<<ch;
        if (ch=='<') {
            b=1;
            ++p;
            if (p==4) {
                For(l,2)
                    if (!pl[l]) pl[l]=1;
                    ++color;
                while(f[nowi][nowj]) ++nowj;
                Fork(i,nowi,nowi+pl[1]-1) {
                    Fork(j,nowj,nowj+pl[2]-1) {
                        if (f[i][j]) {
                            puts("ERROR");return 0;
                        }
                        f[i][j]=color;
//                      cout<<i<<' '<<j<<endl;
                    }
                } 
                Map[2*nowi-1][2*nowj-1] ='+';
                Map[2*nowi-1][2*nowj+pl[2]*2-1] ='+';

                Map[2*nowi+pl[1]*2-1][2*nowj-1] ='+';
                Map[2*nowi+pl[1]*2-1][2*nowj+pl[2]*2-1] ='+';

                gmax(N,2*nowi+pl[1]*2-1);
                gmax(M,2*nowj+pl[2]*2-1);
                Fork(i,2*nowi,2*nowi+pl[1]*2-2) {
                    if (Map[i][2*nowj-1]!='+')
                        Map[i][2*nowj-1]='|';
                    if (Map[i][2*nowj+pl[2]*2-1]!='+')      
                        Map[i][2*nowj+pl[2]*2-1]='|';
                }
                Fork(j,2*nowj,2*nowj+pl[2]*2-2) {
                    if (Map[2*nowi-1][j]!='+')
                        Map[2*nowi-1][j]='-';
                    if (Map[2*nowi+pl[1]*2-1][j]!='+')
                    Map[2*nowi+pl[1]*2-1][j]='-';
                }


//              cout<<nowi<<' '<<pl[1]<<' '<<nowj<<' '<<(-1+nowj+pl[2])<<endl;

                nowj+=pl[2];
                pl[1]=pl[2]=l=0;
            }
        }
        if(b && ch=='>') {
            b=0;
        }
        if (!b) continue;
        if (ch=='/') {
            p-=2;
            if (!p) break;
        }
        if(lch=='t'&&ch=='r' && p==2) {
            ++nowi;nowj=1;
        }
        if (ch=='r') {
            l=1;            
        } else if (ch=='c') {
            l=2;
        }
        if (isdigit(ch)) {
            pl[l]=pl[l]*10+ch-'0';
        }
        if (ch==EOF) break;

    }


//  For(i,n) {
//      For(j,m) {
//          cout<<f[i][j]<<' ';
//      }
//  }


    For(i,N){
        int tm=0;
        For(j,M) if (Map[i][j]) tm=j;
        For(j,tm) {
            putchar(Map[i][j]?Map[i][j]:' ');
        }cout<<endl;
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值