2011 Multi-University Training Contest 1 - Host by HNU

A.A + B problem(待填坑)

 

B.Cat VS Dog(二分图匹配)

喜欢cat和喜欢dog的人构成了二分图,如果两个人有冲突则连一条边,则问题转化为二分图最大点独立集问题。ans=n-最大匹配。

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())=='-') flag=1;
    else if(ch>='0'&&ch<='9') res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=505;
//Code begin...

struct Child{string like, dis;}cat[N], dog[N];
int G[N][N], link[N], used[N], cat_num, dog_num;

int dfs(int k)
{
    FO(i,0,dog_num) if(!used[i] && G[k][i])  {
        used[i]=1;
        if(link[i]==-1 || dfs(link[i])) {link[i]=k; return 1;}
    }
    return 0;
}
int maxMatch()
{
    int cnt=0;
    FO(i,0,cat_num) {
        mem(used,0);
        if(dfs(i))  ++cnt;
    }
    return cnt;
}
int main()
{
    int n, m, p;
    string a, b;
    while(cin>>n>>m>>p)  {
        mem(G,0); mem(link,-1);
        cat_num=dog_num=0;
        while(p--) {
            cin>>a>>b;
            if(a[0] == 'C') cat[cat_num].like=a, cat[cat_num].dis=b, cat_num++;
            else  dog[dog_num].like=a, dog[dog_num].dis=b, dog_num++;
        }
        FO(i,0,cat_num) FO(j,0,dog_num) if(cat[i].like==dog[j].dis || cat[i].dis==dog[j].like)  G[i][j]=1;
        cout<<cat_num+dog_num-maxMatch()<<endl;
    }
    return 0;
}
View Code

 

C.Checkers(二分+LCA+辗转相除法)

考虑点对(a,b,c)可以转换的点对。容易发现这其实是一个无限二叉树。

如果左边的棋子或者右边的棋子往中间跳,就对应着父亲边往上的过程。中间的棋子往左跳,对应着左孩子边。中间的往右跳,对应着右孩子边。

那么我们判断解的存在性就相当于找到他们是不是同一个根。判断最小的解就相当于在树上找到LCA。

可以通过辗转相除法来优化向上爬的操作。由于不能倍增找LCA,我们二分向上爬的深度验证即可。

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 100000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())=='-') flag=1;
    else if(ch>='0'&&ch<='9') res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=505;
//Code begin...

LL a[3], b[3], root[2], dep[2], dis[2], temp1[3], temp2[3];

void get_root(LL x)
{
    root[x]=(x?b[1]:a[1]); dep[x]=0;
    LL val1, val2, t;
    if (x) val1=b[1]-b[0], val2=b[2]-b[1];
    else val1=a[1]-a[0], val2=a[2]-a[1];
    while (val1!=val2) {
        if (val1<val2) {
            if (val2%val1) t=val2/val1;
            else t=val2/val1-1;
            root[x]+=t*val1; dep[x]+=t; val2-=t*val1;
        }
        else {
            if (val1%val2) t=val1/val2;
            else t=val1/val2-1;
            root[x]-=t*val2; dep[x]+=t; val1-=t*val2;
        }
    }
    dis[x]=val1;
}
void go_up(LL (&a)[3], LL dep)
{
    while (dep) {
        LL val1=a[1]-a[0], val2=a[2]-a[1], t;
        if (val1>val2) {
            if (val1%val2) t=val1/val2;
            else t=val1/val2-1;
            if (dep>=t) a[1]-=t*val2, a[2]-=t*val2, dep-=t;
            else a[1]-=dep*val2, a[2]-=dep*val2, dep=0;
        }
        else {
            if (val2%val1) t=val2/val1;
            else t=val2/val1-1;
            if (dep>=t) a[1]+=t*val1, a[0]+=t*val1, dep-=t;
            else a[1]+=dep*val1, a[0]+=dep*val1, dep=0;
        }
    }
}
int main ()
{
    while (~scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&a[0],&a[1],&a[2],&b[0],&b[1],&b[2])) {
        sort(a,a+3); sort(b,b+3);
        get_root(0); get_root(1);
        if (root[0]!=root[1] || dis[0]!=dis[1]) {puts("NO"); continue;}
        LL ans=0;
        if (dep[0]>dep[1]) {
            LL t=dep[0]-dep[1]; dep[0]=dep[1];
            go_up(a,t);
            ans+=t;
        }
        else if (dep[0]<dep[1]) {
            LL t=dep[1]-dep[0]; dep[1]=dep[0];
            go_up(b,t);
            ans+=t;
        }
        if (a[0]==b[0]&&a[1]==b[1]&&a[2]==b[2]) {printf("YES\n%I64d\n",ans); continue;}
        LL l=0, r=dep[0]+1, mid;
        while (l<r) {
            mid=(l+r)>>1;
            temp1[0]=a[0]; temp1[1]=a[1]; temp1[2]=a[2];
            temp2[0]=b[0]; temp2[1]=b[1]; temp2[2]=b[2];
            go_up(temp1,mid); go_up(temp2,mid);
            if (temp1[0]==temp2[0]&&temp1[1]==temp2[1]&&temp1[2]==temp2[2]) r=mid;
            else l=mid+1;
        }
        printf("YES\n%I64d\n",ans+2*r);
    }
    return 0;
}
View Code

 

D.DICS(DP)

这是字符串编辑距离的拓展,多了一个改变后缀操作。dp数组多开一维记录改变的后缀类型。直接记搜即可。

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 100000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())=='-') flag=1;
    else if(ch>='0'&&ch<='9') res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=505;
//Code begin...

int dp[N][N][55], len1, len2;
char s1[N], s2[N];

int dfs(int x, int y, int z)
{
    if (~dp[x][y][z]) return dp[x][y][z];
    if (x==len1&&y==len2) return 0;
    if (x==len1) return len2-y;
    if (y==len2) return len1-x;
    int ans=min(dfs(x,y+1,z)+1,dfs(x+1,y,z)+1);
    if (z==0) ans=min(ans,dfs(x+1,y+1,z)+(s1[x]!=s2[y]));
    else ans=min(ans,dfs(x+1,y+1,z)+(z!=s2[y]));
    if ((z==0&&s1[x]!=s2[y]) || (z&&z!=s2[y])) ans=min(ans,dfs(x+1,y+1,s2[y])+1);
    return dp[x][y][z]=ans;
}
int main ()
{
    while (1) {
        scanf("%s",s1);
        if (s1[0]=='#') break;
        scanf("%s",s2);
        len1=strlen(s1); len2=strlen(s2);
        FO(i,0,len1) {
            if (s1[i]<='z'&&s1[i]>='a') s1[i]=s1[i]-'a'+1;
            else s1[i]=s1[i]-'A'+27;
        }
        FO(i,0,len2) {
            if (s2[i]<='z'&&s2[i]>='a') s2[i]=s2[i]-'a'+1;
            else s2[i]=s2[i]-'A'+27;
        }
        mem(dp,-1);
        printf("%d\n",dfs(0,0,0));
    }
    return 0;
}
View Code

 

E.Earth Hour(水题)

先抽象成图,然后问题转化为求图中3个点的生成树的最短路。数据范围很小,直接从这3个点bfs一次。因为这连接3个点的生成树一定是从图中一个点出发可以直接到达的。

枚举这个点更新答案即可。

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 100000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())=='-') flag=1;
    else if(ch>='0'&&ch<='9') res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=205;
//Code begin...

struct Edge{int p, next;}edge[N*N];
struct Cir{int x, y, r;}cir[N];
int head[N], cnt, fa[N], vis[N];

queue<int>Q;
int find(int x)
{
    int s, temp;
    for (s=x; fa[s]>=0; s=fa[s]) ;
    while (s!=x) temp=fa[x], fa[x]=s, x=temp;
    return s;
}
void union_set(int x, int y)
{
    int temp=fa[x]+fa[y];
    if (fa[x]>fa[y]) fa[x]=y, fa[y]=temp;
    else fa[y]=x, fa[x]=temp;
}
void add_edge(int u, int v){edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++;}
void init(){cnt=1; mem(head,0); mem(fa,-1);}
int dis(int x, int y){return (cir[x].x-cir[y].x)*(cir[x].x-cir[y].x)+(cir[x].y-cir[y].y)*(cir[x].y-cir[y].y);}
int main ()
{
    int T, n, u, v, w;
    scanf("%d",&T);
    while (T--) {
        int ans=0;
        init();
        scanf("%d",&n);
        FOR(i,1,n) scanf("%d%d%d",&cir[i].x,&cir[i].y,&cir[i].r);
        FOR(i,1,n) FOR(j,i+1,n) if (dis(i,j)<=(cir[i].r+cir[j].r)*(cir[i].r+cir[j].r)) {
            add_edge(i,j), add_edge(j,i);
            u=find(i), v=find(j);
            if (u!=v) union_set(u,v);
        }
        u=find(1); v=find(2); w=find(3);
        if (u!=v||u!=w||v!=w) {puts("-1"); continue;}
        FOR(i,1,n) {
            mem(vis,-1); vis[i]=0;
            while (!Q.empty()) Q.pop();
            Q.push(i);
            while (!Q.empty()) {
                int w=Q.front(); Q.pop();
                for (int v=head[w]; v; v=edge[v].next) {
                    int u=edge[v].p;
                    if (vis[u]!=-1) continue;
                    vis[u]=vis[w]+1; Q.push(u);
                }
            }
            if (vis[1]!=-1&&vis[2]!=-1&&vis[3]!=-1) ans=max(ans,n-1-vis[1]-vis[2]-vis[3]);
        }
        printf("%d\n",ans);
    }
}
View Code

 

F.YY's new problem(线段树维护字符串hash)

问题转化为 2*a[j]=a[i]+a[k].对于每一个a[j], 只需要验证点对(a[i],a[k])是否出现在a[j]的两侧。复杂度是O(n^2).

如果发现对于a[j],点对是连续的,比如(a[j]-1,a[j]+1),(a[j]-2,a[j]+2),(a[j]-k,a[j]+k).

从前往后扫描数组,如果扫描到a[m],就将vis[a[m]]置1,扫描到a[j]时,只需要验证每个点对的vis值是否是相等的。这样复杂度还是O(n^2).

实际上点对的分布在数轴上是关于点a[j]对称的,那么我们只需要检查关于vis值字符串a[j]-k...a[j]-2,a[j]-1和字符串a[j]+k...a[j]+2,a[j]+1.是否相等就行了。

于是我们需要一个能够快速实现更新一个点的hash,查询一个区间的hash值的数据结构,hash由于具有区间合并性。我们可以用线段树来维护区间的hash值。

复杂度是O(nlogn).

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 100000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())=='-') flag=1;
    else if(ch>='0'&&ch<='9') res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=10005;
//Code begin...

int a[N];
LL seg1[N<<2], seg2[N<<2], _hash[N];

LL mult_mod(LL a, LL b, LL c)
{
    a%=c; b%=c;
    LL ret=0, tmp=a;
    while (b) {
        if (b&1) {
            ret+=tmp;
            if (ret>c) ret-=c;
        }
        tmp<<=1;
        if (tmp>c) tmp-=c;
        b>>=1;
    }
    return ret;
}
LL pow_mod(LL a, LL n, LL mod)
{
    LL ret=1, temp=a%mod;
    while (n) {
        if (n&1) ret=mult_mod(ret,temp,mod);
        temp=mult_mod(temp,temp,mod);
        n>>=1;
    }
    return ret;
}
void init(int p, int l, int r)
{
    if (l<r) {
        int mid=(l+r)>>1;
        init(lch); init(rch);
        seg1[p]=(seg1[p<<1]*_hash[(r-l+1)>>1]+seg1[p<<1|1])%MOD;
        seg2[p]=(seg2[p<<1|1]*_hash[(r-l+2)>>1]+seg2[p<<1])%MOD;
        return ;
    }
    seg1[p]=seg2[p]=1;
}
void insert(int p, int l, int r, int L)
{
    if (L>r||L<l) return ;
    if (L==l&&L==r) seg1[p]=seg2[p]=2;
    else {
        int mid=(l+r)>>1;
        insert(lch,L); insert(rch,L);
        seg1[p]=(seg1[p<<1]*_hash[(r-l+1)>>1]+seg1[p<<1|1])%MOD;
        seg2[p]=(seg2[p<<1|1]*_hash[(r-l+2)>>1]+seg2[p<<1])%MOD;
    }
}
LL query1(int p, int l, int r, int L, int R)
{
    if (L>r||R<l) return 0;
    if (L<=l&&R>=r) return seg1[p]*_hash[R-r]%MOD;
    int mid=(l+r)>>1;
    return (query1(lch,L,R)+query1(rch,L,R))%MOD;
}
LL query2(int p, int l, int r, int L, int R)
{
    if (L>r||R<l) return 0;
    if (L<=l&&R>=r) return seg2[p]*_hash[l-L]%MOD;
    int mid=(l+r)>>1;
    return (query2(lch,L,R)+query2(rch,L,R))%MOD;
}
int main ()
{
    int n, T, flag;
    _hash[0]=1;
    FOR(i,1,10000) _hash[i]=_hash[i-1]*131%MOD;
    scanf("%d",&T);
    while (T--) {
        flag=0;
        scanf("%d",&n);
        FOR(i,1,n) scanf("%d",a+i);
        init(1,1,n);
        FOR(i,1,n) {
            if (a[i]!=1 && a[i]!=n) {
                int t=min(n-a[i],a[i]-1);
                //printf("%d %lld %lld\n",i,query1(1,1,n,a[i]-t,a[i]-1),query2(1,1,n,a[i]+1,a[i]+t));
                if (query1(1,1,n,a[i]-t,a[i]-1)!=query2(1,1,n,a[i]+1,a[i]+t)) {flag=1; break;}
            }
            insert(1,1,n,a[i]);
        }
        puts(flag?"Y":"N");
    }
    return 0;
}
View Code

 

G.Where am I(计算几何)

把小圆缩成点,大圆缩小,可以发现路径只会形成一个三角形,计算出这个三角形即可。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
const double eps = 1e-6;
const double pi = acos(-1.0);
typedef struct
{
double x,y;
}TPoint;
typedef struct
{
double x,y,r;
}TCircle;
TCircle ball,sball;
TPoint vec,convert;
double T;
int flag;
inline double squ(double x)
{
return x*x;
}
double dot(TPoint a,TPoint b,TPoint c)
{
return (b.x-a.x)*(c.x-a.x)+(b.y-a.y)*(c.y-a.y);
}
int cross(TPoint a,TPoint b,TPoint c)
{
double ret = (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
if(ret>eps)
return 1;
return -1;
}
void work()
{
convert.x = ball.x;
convert.y = ball.y;
sball.x -= convert.x;
sball.y -= convert.y;
ball.x =0;
ball.y = 0;
ball.r -= sball.r;
TPoint me = {sball.x,sball.y};
if(fabs(vec.x) < eps && fabs(vec.y) < eps)
{/*vec is zero*/
me.x += convert.x;
me.y += convert.y;
printf("%.1f %.1f\n",me.x,me.y);
return;
}
if(fabs(ball.r)<eps)
{/*sball.r == ball.r*/
me.x += convert.x;
me.y += convert.y;
printf("%.1f %.1f\n",me.x,me.y);
return;
}
if(squ(me.x+T*vec.x)+squ(me.y+T*vec.y)+eps<squ(ball.r))
{
me.x = me.x+T*vec.x;
me.y = me.y+T*vec.y;
me.x += convert.x;
me.y += convert.y;
printf("%.1f %.1f\n",me.x,me.y);
return ;
}
double k=vec.y/vec.x;
double b=me.y-k*me.x;
double x1;
//printf("k:%f   b:%f   %f\n",k,b,ball.r);
if(vec.x<0)
{
x1=(-k*b-sqrt(squ(k*ball.r)+squ(ball.r)-squ(b)))/(squ(k)+1);
}
else
{
x1=(-k*b+sqrt(squ(k*ball.r)+squ(ball.r)-squ(b)))/(squ(k)+1.0);
}
/*fjjjjj*/
double y1=k*x1+b;
/**
** x1 && y1
**/
// printf("(x1,y1)%f  %f\n",x1,y1);
TPoint tmp1 = {x1,y1};
TPoint tmp2 = {0,0};
double u = dot(tmp1,tmp2,me);
flag = cross(tmp1,tmp2,me);
/**
flag
**/
//printf("flag:%d\n",flag);
u = u/(sqrt(squ(x1-me.x)+squ(y1-me.y))*ball.r);
double l=(u)*ball.r;
l *= 2;
u = acos(u);
/**
l
**/
//printf("l:%f\n",l);
double t1 = l/sqrt(squ(vec.x)+squ(vec.y));
__int64 time = (T-(x1-me.x)/vec.x)/t1;
/**
time
**/
//printf("time:%I64d\n",time);
T = T-(x1-me.x)/vec.x-time*t1;
/**
lefttime
**/
// printf("lefttime:%f\n",T);
/*上面以对  很可能是角度算错了 下面的要仔细验证下!!!*/
double u2=atan2(y1,x1);
double u3 = (time+1)*(pi-2*u)*flag;
u2 += time*(pi-2*u)*flag;
double x2 = ball.r*cos(u2);
double y2 = ball.r*sin(u2);
//printf("%f   %f(x2,y2)\n",x2,y2);
TPoint vec2;
vec2.x = vec.x*cos(u3)-vec.y*sin(u3);
vec2.y = vec.x*sin(u3)+vec.y*cos(u3);
me.x = x2+vec2.x*T+convert.x;
me.y = y2+vec2.y*T+convert.y;
printf("%.1f %.1f\n",me.x,me.y);
return;
}
int main(void)
{
#ifndef ONLINE_JUDGE
freopen("G.in","r",stdin);
freopen("G.out","w",stdout);
#endif
int t;
scanf("%d",&t);
while(t--)
{
scanf("%lf%lf%lf",&ball.x,&ball.y,&ball.r);
scanf("%lf%lf%lf",&sball.x,&sball.y,&sball.r);
scanf("%lf%lf%lf",&vec.x,&vec.y,&T);
work();
}
return 0;
}
View Code

 

H.R(N)(水题)

打出平方表二分搜一下即可。

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())=='-') flag=1;
    else if(ch>='0'&&ch<='9') res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=100005;
//Code begin...

int a[N], P;

bool bin_sea(int x)
{
    int l=1, r=P+1, mid;
    while (l<r) {
        mid=(l+r)>>1;
        if (l==mid) break;
        if (a[mid]>x) r=mid;
        else l=mid;
    }
    return a[l]==x;
}
int main ()
{
    int n;
    P=(int)sqrt(1e9+0.5);
    FOR(i,1,P) a[i]=i*i;
    while (~scanf("%d",&n)) {
        if (n==0) {puts("1"); continue;}
        LL ans=0;
        if (bin_sea(n)) ans+=4;
        FOR(i,1,n) {
            if (2*i*i>n) break;
            else if (2*i*i==n) ans+=4;
            else if (bin_sea(n-i*i)) ans+=8;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

I.Equivalent Sets(强连通分量)

易知道当且仅当一个图是强连通图时题意成立。先把题中给出的图强连通分量缩点,然后变成了一个DAG,问题转化为求DAG最少加几条边变成强连通图。

有结论max(源,汇)。(具体还不会证)

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-3
# define MOD 100000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())=='-') flag=1;
    else if(ch>='0'&&ch<='9') res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}
const int N=20005;
//Code begin...

struct Edge{int p, next;}edge[N<<2];
int head[N], cnt;
int Low[N], DFN[N], Stack[N], Belong[N], num[N];
int Index, top, scc, a[N<<2][2], chu[N], ru[N];
bool Instack[N];

void add_edge(int u, int v){edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++;}
void Tarjan(int u)
{
    int v;
    Low[u]=DFN[u]=++Index; Stack[top++]=u; Instack[u]=true;
    for (int i=head[u]; i; i=edge[i].next) {
        v=edge[i].p;
        if (!DFN[v]) {
            Tarjan(v);
            if (Low[u]>Low[v]) Low[u]=Low[v];
        }
        else if (Instack[v]&&Low[u]>DFN[v]) Low[u]=DFN[v];
    }
    if (Low[u]==DFN[u]) {
        scc++;
        do{
            v=Stack[--top]; Instack[v]=false;
            Belong[v]=scc; num[scc]++;
        }while (v!=u);
    }
}
void solve(int n)
{
    mem(DFN,0); mem(Instack,0); mem(num,0);
    Index=scc=top=0;
    FOR(i,1,n) if (!DFN[i]) Tarjan(i);
}
void init(){mem(head,0); mem(chu,0); mem(ru,0); cnt=1;}
int main ()
{
    int n, m, u, v;
    while (~scanf("%d%d",&n,&m)) {
        init();
        FOR(i,1,m) scanf("%d%d",&u,&v), add_edge(u,v), a[i][0]=u, a[i][1]=v;
        solve(n);
        if (scc==1) {puts("0"); continue;}
        FOR(i,1,m) {
            if (Belong[a[i][0]]==Belong[a[i][1]]) continue;
            ++chu[Belong[a[i][0]]]; ++ru[Belong[a[i][1]]];
        }
        int ans1=0, ans2=0;
        FOR(i,1,scc) {
            if (chu[i]==0) ans1++;
            if (ru[i]==0) ans2++;
        }
        printf("%d\n",max(ans1,ans2));
    }
    return 0;
}
View Code

 

posted @ 2017-02-22 14:44  free-loop  阅读(167)  评论(0编辑  收藏  举报