HUST2012校赛,USC2013新队员训练第二场

由于前天熬夜,昨天开赛前两个小时没点动静,吐槽下题目,真长!


Problem A. Triangles

给你N个点M条边(N<200,M<20000),点的下标为-100000~100000,现在问这些个点能组成多少个三角形。

首先,若点A,B,C共线,AB,BC有边,那么AC也为有边,我们要把这些情况都预处理掉。因为最多200个点,这里可以用到floyd思想,枚举中间点K,看I,J,K是否满足情况,满足连上IJ边。接下来就好做了,直接枚举三个点看是否能构成三角形~~

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<map>
#include<string.h>
#include<math.h>
using namespace std;
struct node
{
    double x,y;
}p[210];
map<double,int> mymap;
double tomap[210];
int ans,n,m,mp[210][210];
double hash(double x,double y)
{
    x*=1000000;
    return x+y;
}
int online(node a,node b,node c)
{
    double x,y,z,t;
    x=a.x-c.x;
    y=a.y-c.y;
    z=b.x-c.x;
    t=b.y-c.y;
    if((t<1e-8&&t>-1e-8)&&(y<1e-8&&y>-1e-8))return 1;
    else
    {
        if((t<1e-8&&t>-1e-8)||(y<1e-8&&y>-1e-8))return 0;
        t=(x/y)-(z/t);
        return (t<1e-8&&t>-1e-8);
    }
}
double dis(node a,node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int rejudge(node a,node b,node c)
{
    double x,y,z;
    x=dis(a,b);
    y=dis(a,c);
    z=dis(b,c);
    if(x+y-z>1e-8&&x+z-y>1e-8&&y+z-x>1e-8)
        return 1;
    else return 0;
}
int istrue(int a,int b,int c)
{
    if (mp[a][b]&&mp[a][c]&&mp[b][c]) return rejudge(p[a],p[b],p[c]);
    return 0;
}
int main()
{
    int i,j,k;
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        mymap.clear();
        memset(mp,0,sizeof(mp));
        double tx1,ty2,tx2,ty1;
        for (i=0;i<n;i++)
        {
            scanf("%lf%lf",&tx1,&ty1);
            p[i].x=tx1,p[i].y=ty1;
            tomap[i]=hash(tx1,ty1);
            mymap[tomap[i]]=i;
        }
        for (i=0;i<m;i++)
        {
            scanf("%lf%lf%lf%lf",&tx1,&ty1,&tx2,&ty2);
            mp[mymap[hash(tx1,ty1)]][mymap[hash(tx2,ty2)]]=1;
            mp[mymap[hash(tx2,ty2)]][mymap[hash(tx1,ty1)]]=1;
        }
        for (i=0;i<n;i++)
            for (j=0;j<n;j++)
            {
                if (i==j) continue;
                for (k=0;k<n;k++)
                {
                    if (k==i||k==j) continue;
                    if (!mp[j][k]&&mp[i][j]&&mp[i][k]&&online(p[i],p[j],p[k]))
                        mp[j][k]=1,mp[k][j]=1;
                }
            }
        ans=0;
        for (i=0;i<n;i++)
            for (j=i+1;j<n;j++)
                for (k=j+1;k<n;k++)
                    ans+=istrue(i,j,k);
        printf("%d\n",ans);
    }
    return 0;
}

Problem B. Dating With Girls

给定一个有向图,图中节点各有一个权值w[ i ],求从0节点出发,到权值最小的点(权值有负值)的路径中,能获得的总权值最大的那个值,路径上不能有负权点(终点必须为负)。

很简单可以想到,BFS求路径,然后~~就是这样做了。


Problem C. Anti-Virus

有N个病毒,给定一条字符串,问字符串中含有多少种病毒。

AC自动机模版题。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct node
{
    int next[26],id,flag,fail;
}tree[150*2010];
int last,used[2010];
char s[100010];
int queue[150*2010];
void insert(char *str,int len,int id)
{
    int i,now=1;
    for (i=0;i<len;i++)
        if (tree[now].next[str[i]-'a'])
            now=tree[now].next[str[i]-'a'];
        else
        {
            tree[now].next[str[i]-'a']=last;
            now=last++;
            memset(&tree[now],0,sizeof(node));
        }
    tree[now].id=id;
}
void buildtrie()
{
    int l,r,now,i;
    l=r=0;
    queue[r++]=1;
    while (l<r)
    {
        now=queue[l++];
        for (i=0;i<26;i++)
            if (tree[now].next[i])
            {
                queue[r++]=tree[now].next[i];
                tree[tree[now].next[i]].fail=tree[tree[now].fail].next[i];
            }else
                tree[now].next[i]=tree[tree[now].fail].next[i];
    }
}
void mask(int place)
{
    while (place)
    {
        if (!place || tree[place].flag) break;
        used[tree[place].id]=1;
        tree[place].flag=1;
        place=tree[place].fail;
    }
}
int solved(int n)
{
    int cnt=0,i;
    for (i=1;i<=n;i++)
        if (used[i]==1) cnt++;
    return cnt;
}
int main()
{
    int T,i,j,k,n,len,place,ans;
    char str[200];
    scanf("%d",&T);
    while (T--)
    {
        memset(&tree[0],0,sizeof(node));
        memset(&tree[1],0,sizeof(node));
        memset(used,0,sizeof(used));
        for (i=0;i<26;i++)
            tree[0].next[i]=1;
        last=2;
        scanf("%d",&n);
        for (i=1;i<=n;i++)
        {
            scanf("%s",str);
            insert(str,strlen(str),i);
        }
        buildtrie();
        scanf("%s",s);
        len=strlen(s);
        place=1,i=0;
        while (i<len)
        {
            if (s[i]>='a'&&s[i]<='z')
            {
                place=tree[place].next[s[i]-'a'];
                mask(place);
                i++;
            }else
            {
                int tmp=0;
                for (++i;s[i]>='0'&&s[i]<='9';i++)
                    tmp=tmp*10+s[i]-'0';
                char tc=s[i++];
                cout<<tc<<" ";
                for (j=0;j<tmp;j++)
                {
                    if (place==tree[place].next[tc-'a']) break;
                    place=tree[place].next[tc-'a'];
                }
            i++;
            }
        }
        ans=solved(n);
        if (ans) printf("Yes\n%d\n",ans);
        else printf("No\n0\n");
    }
    return 0;
}



Problem E. The mell hall

给定A[ I ] B[ I ],M[ I ]=(A1A2...Ai-1)/Bi。AI,BI为关联关系,AIBI位置可任意,求使得M[ I ]最大的那个元素在元数列中的位置。

因为(Bi < 10 < Ai*Bi),那么对于任意的M[ I ]/M[ I+1]有其小于1,也就是说M[ I ]<M[ I+1]。也就是说只要把元素I放到队列最后,就可以求出这个元素可以得到的最大M[ ],算出所有的M[ ],找到最大的那个的原坐标~~


Problem F. A new tree game

给你一棵树,N个点,M条边,每条边可以砍K下砍断,砍断的边及其所链接的子树将消失。两个人来砍边,不能砍了就输了,问先手还是后手赢。

博弈,SG函数。

题解链接:http://www.cnblogs.com/jianglangcaijin/archive/2012/12/18/2824053.html


Problem H. Little Sheep and a paper

折纸,可以向上向下向左向右折,问经过某些操作之后,面向自己这面的纸上有多少条突出的折痕。

显然第一下折是不会产生突出折痕的。若不记第一下,那么

剩下的操作中,竖着折N下的突出折痕为2^n-1,  若横着再折M下就要翻M翻 也就是2^m 那么S1=(2^n-1)2^m。

同理可得S2= ((2^m-1)2^n),ans=S1+S2。


Problem I. Matrix

给你一个N*N的01矩阵A,问A乘以A的转置阵B后,矩阵中有多少个元素不为0。

显然,这就是将矩阵的行乘以自己的行,也就是说,枚举每一行为得到矩阵的元素的行数,再枚举每一行为得到矩阵元素的列数,看那两行中不为0的元素中是否有相同的列下标,若有则表明得到矩阵的该元素不为0。因为只有原矩阵元素不为0的元素相乘才会生成不为0的元素,所以只要扫不为0的点,最坏情况也就是1000*1000的复杂度。


#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<map>
using namespace std;
map<int,int> mymap;
struct node
{
    int x,y;
}p[1010];
int cmp(node a,node b)//按行排序
{
    return a.x<b.x;
}
int main()
{
    int t,n,m,i,j,k,ans;
    int lb[1010];
    scanf("%d",&t);
    while (t--)
    {
        memset(lb,0,sizeof(lb));
        scanf("%d%d",&n,&m);
        for (i=0;i<m;i++)
            scanf("%d%d",&p[i].x,&p[i].y);
        sort(p,p+m,cmp);
        j=0;
        for (i=1;i<m;i++){
            if (p[i].x!=p[i-1].x) lb[++j]=i;//lb数组维护每一行从哪个下标开始
        }
        ans=0;
        for (i=0;i<=j;i++)
        {
            mymap.clear();
            for (k=lb[i];k<(i==j?m:lb[i+1]);k++){
                mymap[p[k].y]=1;
            }
            int row=0;
            k=0;
            for (k=0;k<=j;k++)
            {
                for (row=lb[k];row<(k==j?m:lb[k+1]);row++)
                    if (mymap.find(p[row].y)!=mymap.end())
                    {
                        ans++;
                        break;
                    }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值