2012 Multi-University Training Contest 3

时间:2023-01-23 08:57:01

1001  hdu 4320  http://acm.hdu.edu.cn/showproblem.php?pid=4320

题意:

V写下一个A进制的任意有限小数,如果S能将其翻译成B进制的有限小数,则S赢,输出Yes 否则V赢输出No;

思路:

只要A的所有质因子都包含在B中,S就能赢(证明没看懂!!求指教)

这里注意:

(N表示A,B的极限值)

1:一个数i的质因子,至多只会存在一个大于sqrt(i)的。所以这里我们只要枚举出小于sqrt(N)的所有质数即可,然后用所有小于sqrt(j)的质数来查找j的质因子,同时j也要做相应的除法把枚举道德质因子除去,当枚举完所有小于sqrt(j)质数时,j如果>1说明存在大于sqrt(j)的质因子,这时的质因子也就是j本身看了,所以要检查一下B是否还包含这个质因子,因为当存在大于sqrt(N)的质数时,我们没有枚举出来,所以必须在后边要算。

2012 Multi-University Training Contest 32012 Multi-University Training Contest 3View Code
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 1000007
#define ll __int64
using namespace std;

int nop[maxn];
int res[maxn],len;
//素数筛选法选出素数
void SP()
{
    len = 0;
    int i,j;
    memset(nop,0,sizeof(nop));
    nop[0] = nop[1] = 1;
    for (i = 2; i*i < maxn; ++i)
    {
        if (!nop[i])
        {
            for (j = i*2; j < maxn; j += i)
            {
                nop[j] = 1;
            }
        }
    }
    for (i = 2; i < maxn; ++i)
    {
        if (!nop[i])
        {
            res[len++] = i;
        }
    }
}

int main()
{
   //freopen("d.txt","r",stdin);
    int t,i;
    int cas = 1;
    ll a,b;
    SP();
    /*for (i = 0; i < 50; ++i) printf("%d ",res[i]);
    puts("");*/
    scanf("%d",&t);
    while (t--)
    {
        scanf("%I64d%I64d",&a,&b);
        bool flag = false;
        //枚举小于sqrt(a)的质因子
        for (i = 0; res[i] <= sqrt(1.0*a); ++i)
        {
            if (a%res[i] == 0)//属于A的质因子一定要属于B
            {
                if (b%res[i] != 0)
                {
                    flag = true;
                    break;
                }
                while (a%res[i] == 0)//a必须做相应处理,为后边出现大雨sqrt(a)的质因子做准备
                a /= res[i];
            }
        }
        if (b%a != 0) flag = true;//此时a可能是1,也可能是大与sqrt(a)的质因子
        printf("Case #%d: ",cas++);
        if (!flag) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

 

还有一个解法:首先明确每一个大于1的整数都能分解成质因数乘积的形式,还要要知道两个数的最大公约数就是这两个数的公共质因子的乘积,所以我们只要不断取他们的公共质因子的乘积,直到a只剩下1时,说明a的所有质因子都包含在b中,就是不断地取a,b的最大公约数,然后a再除去最大公约数。

2012 Multi-University Training Contest 32012 Multi-University Training Contest 3View Code
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 1000007
#define ll __int64
using namespace std;

ll gcd(ll a,ll b)
{
    if (b == 0) return a;
    return gcd(b,a%b);
 }
int main()
{
    //freopen("d.txt","r",stdin);
    ll a,b;
    int t;
    int cas = 1;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%I64d%I64d",&a,&b);
        printf("Case #%d: ",cas++);
        ll c = gcd(a,b);
        if (c == 1)//如果c为1说明不存在公共质因子
        {
            printf("NO\n");
        }
        else
        {
            while (c != 1)
            {
                a/=c;//除去
                c = gcd(a,b);//再取
            }
            if (a == 1) printf("YES\n");//公共质因子都能取完
            else printf("NO\n");
        }
    }
    return 0;
}

 

1004:hdu 4232 http://acm.hdu.edu.cn/showproblem.php?pid=4323

题意:

给出n个数字字符串,然后给出m个询问,每个询问包括一个数字字符串和一个最大值,要求在n个字符串里寻找与查询字符串的字符串编辑距离小于最大值的字符串个数。

思路:

直接利用dp求查询字符串与n个字符串的编辑距离,求解即可。

2012 Multi-University Training Contest 32012 Multi-University Training Contest 3View Code
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 1507
#define ll __int64
using namespace std;

char num[maxn][13];
int d[13][13];

bool solve(char *s1,char*s2,int mk)
{
    int i,j;
    int len1 = strlen(s1);
    int len2 = strlen(s2);
    if (abs(len1 - len2) > mk) return false;
    /*
       才开始以为只要字符串长度相同他们不同的点个数大于mk标记就返回false
       结果就wa了
       例如
       123
       324 
       虽然他们不同的点有三个,我们只要将4删除,在3前加1即可用两步操作实现
    */
    /*if (len1 == len2)
    {
        int tmp = 0;
        for (i = 0; i < len1; ++i)
        {
            if (s1[i] != s2[i]) tmp++;
        }
        if (tmp > mk) return false;
    }*/
    //关键是dp求编辑距离
    memset(d,0,sizeof(d));
    d[0][0] = 0;
    for (i = 1; i <= len1; ++i) d[i][0] = i;
    for (i = 1; i <= len2; ++i) d[0][i] = i;
    for (i = 1; i <= len1; ++i)
    {
        for (j = 1; j <= len2; ++j)
        {
            d[i][j] = d[i - 1][j - 1] + (s1[i - 1] == s2[j - 1]?0:1);
            d[i][j] = min(d[i][j],d[i - 1][j] + 1);
            d[i][j] = min(d[i][j],d[i][j - 1] + 1);
        }
    }
    //printf("%d %d %s %s\n",d[len1][len2],mk,s1,s2);
    if (d[len1][len2] <= mk) return true;
    else return false;
}
int main()
{
    //freopen("d.txt","r",stdin);
    int t,i,j,n,m;
    char str[13];
    int cas = 1,tmp;
    scanf("%d",&t);
    while (t--)
    {
        printf("Case #%d:\n",cas++);
        scanf("%d%d",&n,&m);
        memset(num,0,sizeof(num));
        for (i = 0; i < n; ++i)
        scanf("%s",num[i]);

        for (i = 0; i < m; ++i)
        {
            int ct = 0;
            scanf("%s%d",str,&tmp);
            for (j = 0; j < n; ++j)
            {
                if (solve(str,num[j],tmp))
                ct++;
            }
            printf("%d\n",ct);
        }
    }
    return 0;
}

 

1005: hdu 4324 http://acm.hdu.edu.cn/showproblem.php?pid=4324

题意:

给定n个人的爱情图,如果a爱b那么b一定不爱a,而且题目保证任意两点都存在一条边(there is love between any of two people, if A don’t love B, then B must love A

关系矩阵map[i][j] = 1表示i爱j,那么j一定不爱i,让你找出是否存在三角恋,即:A loves B, B loves C and C loves A.

思路:

按照官方解题报告的第二种方法做的,不是好理解;当第i个点加入时,(0 --- i - 1)里面肯定有i喜欢的将他们分到左边,那剩下的就是i不喜欢的了,也即喜欢i的了,(这里保证每条边i都会和其他n-1条变有关系,要么喜欢要么不喜欢),对于每次枚举i,我们在(0~i-1)的范围看下有多少个i指向的点(剩下的就是指向i的点),同时算下i指向的点的出度和。就可以知道这些 i指向的点 指向 指向i的点(剩下的点)的数目,如果 num * (num - 1) / 2 < sumout 那么就是被指向的点有指出去了,这样就形成了3元环。 否则,剩下的就是更新下出度即可,继续执行下一个节点。

2012 Multi-University Training Contest 32012 Multi-University Training Contest 3View Code
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 2007

using namespace std;

char map[maxn][maxn];
int outd[maxn];

int main()
{
    //freopen("d.txt","r",stdin);
    int t,i,j,n;
    int cas = 1;
    scanf("%d",&t);
    while (t--)
    {
        printf("Case #%d: ",cas++);
        scanf("%d",&n);
        for (i = 0; i < n; ++i)
        scanf("%s",map[i]);

        memset(outd,0,sizeof(outd));
         bool flag = false;
        for (i = 0; i < n; ++i)
        {
            int num = 0,out = 0;
           for (j = 0; j < i; ++j)//枚举出i指向的点
           {
               if (map[i][j] == '1')
               {
                   out += outd[j];//记录i指向的点的初读
                   num++;
                   outd[i]++;//同时本身的初度累加
               }
           }
           if ((num- 1)*num/2 < out)//比较
           {
               flag = true;
               break;
           }
           //更新出度
           for (j = 0; j < i; ++j)
           {
               if (map[j][i] == '1')
               outd[j]++;
           }
        }
        if (flag) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

1006 hdu 4325 http://acm.hdu.edu.cn/showproblem.php?pid=4325

题意:

给出每朵花的开花时间段[si,ti],存在又在同一时间段开花的,询问每个时间点pi几朵花在开放;

思路:

本来一道很简单的线段数的成端更新+单点询问+离散化的题目,可是我在离散化的时候只离散化了输入的时间段的端点,在询问时就出了问题,跳了很长时间很是不对,后来把所有的点都离散化后建树,做操作就简单的跟屎似的了,没有构思好就看似是敲代码。不行啊。。

2012 Multi-University Training Contest 32012 Multi-University Training Contest 3View Code
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define maxn 100007
using namespace std;

int val[12*maxn],X[3*maxn];
int L[maxn],R[maxn],w[maxn];
int bsearch(int l,int r,int sc)
{
    while (l <= r)
    {
        int m = (l + r)>>1;
        if (sc == X[m]) return m;
        else if (sc < X[m]) r = m - 1;
        else l = m + 1;
    }
    return l;
}
void pushdown(int rt)
{
    if (val[rt])
    {
        val[rt<<1] += val[rt];
        val[rt<<1|1] += val[rt];
        val[rt] = 0;
    }
}
void update(int L,int R,int sc,int l,int r,int rt)
{
    if (l >= L && r <= R)
    {
        val[rt] += sc;
        return;
    }
    pushdown(rt);
    int m = (l + r)>>1;
    if (L <= m) update(L,R,sc,l,m,rt<<1);
    if (R > m) update(L,R,sc,m + 1,r,rt<<1|1);
}
int query(int pos,int l,int r,int rt)
{
    if (l == r)
    {
        return val[rt];
    }
    pushdown(rt);
    int res = 0;
    int m = (l + r)>>1;
    if (pos <= m) res = query(pos,l,m,rt<<1);
    else res = query(pos,m + 1,r,rt<<1|1);
    return res;
}
int main()
{
    int t,i;
    int n,q;
    int cas = 1;
    scanf("%d",&t);
    while (t--)
    {
        printf("Case #%d:\n",cas++);
        scanf("%d%d",&n,&q);
        int mm = 0;
        for (i = 0; i < n; ++i)
        {
            scanf("%d%d",&L[i],&R[i]);
            X[++mm] = L[i];
            X[++mm] = R[i];
        }
        for (i = 0; i < q; ++i)
        {
            scanf("%d",&w[i]);
            X[++mm] = w[i];
        }
        sort(X + 1,X + 1 + mm);
        int m = 1;
        for (i = 2; i <= mm; ++i)
        {
            if (X[i] != X[i - 1]) X[++m] = X[i];
        }
        memset(val,0,sizeof(val));

        for (i = 0; i < n; ++i)
        {
            int l = bsearch(1,m,L[i]);
            int r = bsearch(1,m,R[i]);
            update(l,r,1,1,m,1);
        }
        for (i = 0; i < q; ++i)
        {
            int pos = bsearch(1,m,w[i]);
            printf("%d\n",query(pos,1,m,1));
        }
    }
    return 0;
}

 

 

 

官方解题报告:http://page.renren.com/601081183/note/863771603?ref=minifeed&sfet=2012&fin=0&ff_id=601081183&feed=page_blog&tagid=863771603&statID=page_601081183_2&level=1