北方大学 ACM 多校训练赛 第四场 题解

A. 恶魔包毁灭世界

已知一张二分图,问哪些边是二分图的可行边?
先跑最小流,再把残余网络建图,几个重要结论是:
·最小割的可行边(满流&&2点不在一个SCC中)
·最小割的必行边(可行边&&2点分别与源点和汇点在同一SCC中)
·二分图的可行边(两点在一个SCC中)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;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,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector 
#define pi pair
#define SI(a) ((a).size())
typedef long long ll;
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+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
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;
} 
#define MAXN (3000*2+100)
#define MAXM (18000000+12000+10)
int n,k;
bool b[3010][3010]={};
class tar{
public:
    vi G[MAXN];
    int pre[MAXN],lowlink[MAXN],sccno[MAXN],dfs_clock,scc_cnt;
    stack<int> S; 
    void dfs(int u) {
        pre[u] = lowlink[u] = ++dfs_clock;
        S.push(u);
        int sz=SI(G[u]);
        Rep(i,sz) {
            int v=G[u][i];
            if (!pre[v]) {
                dfs(v);
                lowlink[u]=min(lowlink[u],lowlink[v]);
            } else if (!sccno[v]) {
                lowlink[u]=min(lowlink[u],pre[v]);
            } 
        } 
        if (lowlink[u]==pre[u]) {
            scc_cnt++;  
            while(1) {
                int x=S.top();S.pop();
                sccno[x]=scc_cnt;
                if (x==u) break;  
            } 
        }       
    } 
    void find_scc(int n) {
        dfs_clock = scc_cnt = 0;
        MEM(sccno) 
        MEM(pre)
        Rep(i,n) if (!pre[i]) dfs(i);
    }
    void print(int n,int n1,int m1) {
        // Rep(i,n) cout<
        Rep(i,n1) {
            int sz=SI(G[i]);
            Rep(j,sz) {
                int v=G[i][j];
                if (sccno[i]==sccno[v]&&n1<=v&&v1][v-n1+1]=1;
                }
            }
        }
    }
    void mem(int n) {
        Rep(i,n) G[i].clear();
    }
}S2;
class Max_flow  //dinic+当前弧优化   
{    
public:    
    int n,t;    
    int q[MAXN];    
    int edge[MAXM],Next[MAXM],Pre[MAXN],weight[MAXM],size;    
    void addedge(int u,int v,int w)      
    {      
        edge[++size]=v;      
        weight[size]=w;      
        Next[size]=Pre[u];      
        Pre[u]=size;      
    }      
    void addedge2(int u,int v,int w){addedge(u,v,w),addedge(v,u,0);}     
    bool b[MAXN];    
    int d[MAXN];    
    bool SPFA(int s,int t)      
    {      
        For(i,n) d[i]=INF;    
        MEM(b)    
        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]&&!b[v])      
                {      
                    d[v]=d[now]+1;      
                    b[v]=1,q[++tail]=v;      
                }      
            }          
        }      
        return b[t];      
    }     
    int iter[MAXN];  
    int dfs(int x,int f)  
    {  
        if (x==t) return f;  
        Forpiter(x)  
        {  
            int v=edge[p];  
            if (weight[p]&&d[x]int nowflow=dfs(v,min(weight[p],f));  
                  if (nowflow)  
                  {  
                    weight[p]-=nowflow;  
                    weight[p^1]+=nowflow;  
                    return nowflow;  
                  }  
            }  
        }  
        return 0;  
    }  
    int max_flow(int s,int t)  
    {  
        (*this).t=t;
        int flow=0;  
        while(SPFA(s,t))  
        {  
            For(i,n) iter[i]=Pre[i];  
            int f;  
            while (f=dfs(s,INF))  
                flow+=f;   
        }  
        return flow;  
    }   
    void mem(int n)    
    {    
        (*this).n=n;  
        size=1;    
        MEM(Pre)   
    }
    void init(int n,int n1,int m1) {
        For(i,n) {
            Forp(i) {
                int v=edge[p];  
                // cout<
                if (!weight[p]) {
                    if (i<=n1&&v>n1&&v<=n1+m1) {
                        ::b[i][v-n1]=1;
                        // cout<
                    }
                }
                else S2.G[i-1].pb(v-1);

            }
        }
    }


}S;  
int main() {
    // freopen("A.in","r",stdin);
    int T=read();
    while(T--) {
        int n,m;
        cin>>n>>m;

        int s=n+m+1,t=s+1;
        S.mem(t);
        For(i,n) {
            int k=read();
            while(k--) {
                S.addedge2(i,n+read(),1);
            }
        }
        For(i,n) S.addedge2(s,i,1);
        For(i,m) S.addedge2(n+i,t,1);
        MEM(b)
        int p=S.max_flow(s,t);
        cout<if (b[i][j]) v.pb(j);
            int sz=SI(v);
            cout<cout<<' '<puts("");
        }
        S2.mem(t);
    }
    return 0;
}

B. 翻硬币

用硬币玩游戏。他在n*m的矩阵中的每个小格中放一枚硬币,他想将所有的硬币都变成正面向上,但是,他给自己增加一些难度,他只能将整行或者整列的硬币都翻面。当然,他一点也不想做无用功,所以,他想知道当前的状态是否能通过一系列操作后使得所有硬币正面朝上。

先翻第一列,然后看每行是否都一样

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;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,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector 
#define pi pair
#define SI(a) ((a).size())
typedef long long ll;
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+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
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;
} 
#define MAXN (1000000+10)
int main() {
    // freopen("B.in","r",stdin);
    int T=read();
    while(T--) {
        int n=read(),m=read();
        vector v;
        Rep(i,n) {
            v.pb(vector<int>(m) );
            Rep(j,m) cin>>v[i][j];
        }
        Rep(j,m) if (v[0][j]) {
            Rep(i,n) v[i][j]^=1;
        }
        bool fl=0;
        Rep(i,n) {
            For(j,m-1) if (v[i][j]!=v[i][j-1]) fl=1;
        }
        puts(fl?"NO":"YES");
    }
    return 0;
}

C. 海豹的队列

fi,j 表示前i个换了j个数(且最后一个不换)的最优值,注意考虑开头,结尾的处理

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;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,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector 
#define pi pair
#define SI(a) ((a).size())
typedef long long ll;
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+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
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;
} 
#define MAXN (510)
int n,k;
ll f[MAXN][MAXN];
ll a[MAXN];
ll Abs(ll x) {
    return max(x,-x);
}
int main() {
    // freopen("C.in","r",stdin);
    int T=read();
    while(T--) {
        n=read();k=read();k=min(k,n);
        MEMI(f)
        f[0][0]=0;
        // For(i,k) f[i][i]=0;

        For(i,n) a[i]=read();
        For(i,n) {
            Rep(j,min(i,k)+1) {
                Fork(l,max(i-j-1,0),i-1) if (j-(i-l-1)>=0) {
                    if (!l) f[i][j]=0;
                    ll p=Abs(a[l]-a[i]);
                    p=ceil((double)p/(i-l-1+1));
                    f[i][j]=min(f[i][j],max(f[l][j-(i-l-1)],p));
                }
            }
        }
        ll ans=f[n][k];
        while(k>=0) {
            k--,n--;ans=min(ans,f[n][k]);
        }
        cout<return 0;
}

D. 积性函数

定义函数f(n,0)=1;

f(n,m)=sigma(d|n) f(d,m-1)*f(n/d,m-1)(m>0)

因子个数在2000左右,所以暴力。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;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,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector 
#define ALL(x) (x).begin(),(x).end()
#define pi pair
#define SI(a) ((a).size())
typedef long long ll;
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+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
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;
} 
#define MAXN (510)
int n,k;
ll f[30000][60];
ll a[MAXN];
ll Abs(ll x) {
    return max(x,-x);
}
int main() {
    // freopen("D.in","r",stdin);
    int T=read();
    while(T--) {
        ll n; int m;
        cin>>n>>m;
        vector v;
        for(ll i=1;i*i<=n;i++) {
            if (n%i==0) {
                v.pb(i);
                if (i*i!=n) v.pb(n/i);
            }
        }

        sort(ALL(v));
        int l=SI(v);
        MEM(f)
        Rep(j,l) f[j][0]=1;
        For(k,m)
            for(int i=0;iint t=i;
                for(int j=0;j<=i;j++) if (v[i]%v[j]==0) {
                    while(v[i]/v[j]!=v[t]) --t;
                    f[i][k]+=f[j][k-1]*f[t][k-1]%10007;
                    f[i][k]%=10007;
                }
            }
        cout<1][m]<return 0;
}

E. 金角大王的葫芦

金角大王的水杯是紫金红葫芦。金角大王无聊的时候想到,如何求葫芦表面上两点间的最短路径呢?为了简化这个问题,我们把葫芦看做两个球体相交。最短路径指的是一个点移动达到另一个点的最短路径,可以在球体表面移动包括在其他球体内部的球面。虽然金角大王想知道答案,但是他太菜了不会做,你能帮帮他吗?

没啥难度,可是就是过不了。
后来假定2个点不在一个球上就过了
不知道什么情况……先放着

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;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,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector 
#define SI(a) ((a).size())
typedef long long ll;
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+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
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;
} 
class node{
public:
    double x,y,z;
    node(double _x,double _y,double _z):x(_x),y(_y),z(_z){}
};
double pf(double x)
{
    return x*x;
}

double d,r;
double caldis(node o,node a,node b)
{
    double l=sqrt(pf(a.x-b.x)+pf(a.y-b.y)+pf(a.z-b.z));
    l/=2.0;
    // cout<
    // cout<

    // cout<
    double ang=asin(l/r)*2.0;
    // cout<
    return ang*r;
}

#define MAXN (1000000+10)
double pi=acos(-1.0);
double get(double &x,double &y,double &z,double t) {
    x=cos(t),y=sin(t),z=d/2;
}
double x0,Y0,z0,x3,y3,z3;
double x1,Y1,z1;
double x2,y2,z2;

double f(double t) {
    double x,y,z;
    double len=sqrt(r*r-(d/2)*(d/2));
    get(x,y,z,t); x*=len,y*=len;
    node a(x,y,z),b(x1,Y1,z1),c(x2,y2,z2),o1(x0,Y0,z0),o2(x3,y3,z3);
    return caldis(o1,a,b)+caldis(o2,c,a);
}

double ans;
void calc(double l,double r) {
    while(1) {
        double m1=l+(r-l)/3;
        double m2=r-(r-l)/3;
        double p1=f(m1),p2=f(m2);
        if (p1else l=m1;
        if (fabs(r-l)<1e-10&&fabs(p1-p2)<1e-10) return;
        ans=min(ans,p1);
        ans=min(ans,p2);
    }
    return ;
}
int main() {
//     freopen("jsk14900.in","r",stdin);
    int T=read();
    while(T--) {
        cin>>r>>d;
        cin>>x1>>Y1>>z1>>x2>>y2>>z2;
        if (z1>z2) {
            swap(z1,z2);
            swap(x1,x2);
            swap(Y1,y2);
        }
        x0=0,Y0=0,z0=0;
        x3=0,y3=0,z3=d;

        double plc=d/2;
        ans=0;
        if (1 ) { //
            ans=INF;
            double l=-pi,r=pi,delta=2*pi/30;
            Rep(i,30) {
                double l1=l+i*delta,l2=l1+delta;
                calc(l1,l2);
            }
        } 
        else if (z1else {
            ans=caldis(node(x3,y3,z3),node(x1,Y1,z1),node(x2,y2,z2));
        }
        printf("%.8lf\n",ans);


    }
    return 0;
}

F. 这个游戏很休闲么

left-right先生和up-down先生很喜欢玩游戏。但是由于他们智商不是很高,别的游戏对于他们来说都太耗脑力了,于是他们便找到一款非常休闲的游戏。这个游戏需要用到一个N行M列的表格,每个格子上写着 ’*’,‘.’ 这两个字符的其中一种。

对于left-right先生来说,他要找到相邻的、在同一行上的一对 ’*’,将它们都变为 ’.’ ;

对于up-down先生来说,他要找到相邻的、在同一列上的一对 ’*’,将它们都变为 ’.’ 。

双方交替进行操作,当一方无法操作时,那一方便输了,对方获胜。

这个游戏虽然很休闲,以至于双方在每一步上都能采取最佳策略进行游戏,然而由于他们堪忧的智商,他们无法对一个给定的表格判断谁胜谁负。现在他们找到了你,请你帮忙告诉他们这个游戏的最终结果。

“毕竟,这个游戏很休闲的。”二位先生异口同声地说道。

输入:

第一行一个正整数T,表示一共有T组数据。

每组数据的第一行为两个正整数N, M,分别表示表格的行数和列数。

接下来N行,每行是一个长度为M的字符串,且仅由 ‘*’, ‘.’ 构成,这N行表示一个N行M列的表格。

对于所有的数据,保证对于每一个 ’’ 所在的联通块(两个格子之间有公共边,且两个格子均为 ’’ ,即这两格联通),’*’ 的个数不会多于5个。

数据范围:

T <= 100

对于不超过10组数据,有 N, M <= 1000;

其他组的数据均满足N, M <= 20 .

输出:

对于每一组数据,输出一行字符串(均不含引号)。

如果是先手必胜,输出 “offensive” ;

如果是后手必胜,输出 “defensive” ;

如果无论先后手,均是left-right先生必胜,输出 “left-right” ;

如果无论先后手,均是up-down先生必胜,输出 “up-down” .
样例输入

2
1 2
**
5 5
*..
.*.
….*
**…
.*.

样例输出

left-right
defensive

(⊙o⊙)…

你可能感兴趣的:(比赛题解,网络流,二分图,最小割,计算几何)