Chieh's Blog

Because Of Coding

HDU 5277 YJC counts stars

飞机票:http://acm.hdu.edu.cn/showproblem.php?pid=5277

题意:就是给你n个点n个坐标xi,yi(1<=i<=n),然后给你m条边,表示u和v相连,保证没重边,也保证没有边相交。然后 让你求最大的点子集,使里面的点可以两两相连(不是图相连,线段相连),且求处个数。

分析:其实分析分析,就发现最大就只有4个点的点急,因为5个点就会有边相交,与题目不符,所以只要枚举到4个点就行了,具体怎么枚举才比较好?可以先枚举两两的,就是加入i和j有边相连,就把i和j算一对保存起来,这样我们就知道两两相连的子集个数有多少个了,怎么枚举三个的,很简单,只要把两个相连的与一个个点比较,只要这两个点能同事与第三个点连接,那么就是ok的,这里注意:假设i和j和k是属于三个相连的,我们求出来两两的就是(i,j)(i,k)(j,k)然后枚举三个点的时候会有三种方法,但是实际上就只有1种,所以答案要/3,这样我们就知道三个点的自己个数了,现在是四个点了,四个点也很方便,只要把两个点的两两进行判断就行了,只要互不相同然后互相连接就可以了,但是要注意:假设我们i,j,p,q,是四个相连的点集,那么我们两两求出来的就是(i,j)(i,p)(i,q)(j,p)(j,q)(p,q),这样的话,他们两两按数序的话会求出来三组,因为我们重复计算了,所以答案要/3到此为止,所有的都已经判断了, 按照4,3,2,1只要有一个是满足的,直接ok,结束。然后啪啪啪就可以AC了

/*
Author:Chieh
Because Of Coding
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#define LL long long
#define INF 1e9
#define EPS 1e-9
using namespace std;
const int maxn=1234;
int x[maxn],y[maxn];
int ai[maxn][maxn];
int n,m;
void init()
{
    for(int i=1; i<=n; i++)scanf("%d%d",&x[i],&y[i]);
    int u,v;
    memset(ai,0,sizeof(ai));
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&u,&v);
        ai[u][v]=ai[v][u]=1;
    }
}
int bi[maxn*maxn][2];
void play()
{
    if(m==0)
    {
        printf("1 %d\n",n);
        return;
    }
    if(m==1)
    {
        printf("2 1\n");
        return ;
    }
    int st=1;
    int sum2=0;
    //判断连通性
    for(int i=1; i<=n; i++)
    {
        for(int j=i+1; j<=n; j++)
        {
            if(ai[i][j])
            {
                bi[st][0]=i;
                bi[st][1]=j;
                st++;
                sum2++;
            }
        }
    }
    int sum3=0;
    //判断三个点的
    for(int i=1; i<st; i++)
    {
        for(int j=1; j<=n; j++)
        {
            int u=bi[i][0];
            int v=bi[i][1];
            if(ai[u][j]&&ai[v][j])
            {
                sum3++;
            }
        }
    }
    int sum4=0;
    //判断四个点的
    for(int i=1; i<st; i++)
    {
        for(int j=i+1; j<st; j++)
        {
            int u1=bi[i][0];
            int u2=bi[i][1];
            int v1=bi[j][0];
            int v2=bi[j][1];
            if(u1!=v1&&u1!=v2&&u2!=v1&&u2!=v2&&ai[u1][v1]&&ai[u1][v2]&&ai[u2][v1]&&ai[u2][v2])sum4++;
        }
    }
    if(sum4!=0)
    {
        printf("4 %d\n",sum4/3);

    }
    else if(sum3!=0)
    {
        printf("3 %d\n",sum3/3);
    }
    else if(sum2!=0)
    {
        printf("2 %d\n",sum2);
    }


}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        play();
    }
//    cout << "Hello world!" << endl;
    return 0;
}

HDU 5276 YJC tricks time

飞机票:http://acm.hdu.edu.cn/showproblem.php?pid=5276

题意:就是给你时钟的分针和时针的角度,且乘上12000,求现在的时间是几时几分几秒,且秒要是10的倍数。而且题目给的是劣角的角度,即不会大于12000*180,

分析:枚举时间的话肯定不会超时,怎么判断角度呢,我们可以先求出分针的角度,加入当前的时间是i:j:k,且k是10的倍数,那么分针的角度就是j*6+0.1*k,因为一秒分钟转0.1度,分针一分钟转6度,可以知道j*6+0.1*k是整数,假设是q。我们知道时针转的角度是i*30,因为小时转30度,且每分钟转1/360*30,所以总的转了i*30+30*q/360,因为有精度误差,因为30*q不一定能整除,但是题目给了乘上12000,所以可以直接提高倍数,就是q=12000*q,设时针角度为p,所以p=i*30*12000+30*q/360,因为q已经乘过了,所以不用乘了。这样就可以保证q和p都是整数,但是还有个问题就是劣角,所以一共有两个角。一个是abs(q-p),一个是360*12000-abs(q-p),因为扩大了12000,只要其中一个和输入的角度一样就是对的时间。中间不要用double,直接int,因为我double就wa,int就AC,然后啪啪啪就可以AC了

/*
Author:Chieh
Because Of Coding
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#define LL long long
#define INF 1e9
#define EPS 1e-9
using namespace std;
int n;
void init()
{

}
void play()
{
    for(int i=0; i<=11; i++)
    {
        for(int j=0; j<=59; j++)
        {
            for(int k=0; k<=59; k+=10)
            {
                int q=j*6;
                q+=0.1*k;
                q*=12000;
                int p=i*30*12000;
                p+=q*30/360;
                int s1=abs(q-p);
                int s2=360*12000-s1;
                if(s1==n||s2==n)
                {
                    printf("%02d:%02d:%02d\n",i,j,k);
                }
            }
        }
    }

}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        play();
    }
//    cout << "Hello world!" << endl;
    return 0;
}

HDU 5273 Dylans loves sequence

飞机票:http://acm.hdu.edu.cn/showproblem.php?pid=5273

题意:给你N个数ai 1<=i<=n,N<=1000,以及Q个查询,Q<=100000,每个查询有两个整数L,R 求[L,R]逆序对的数量(逆序对就是当i<j 时,ai>aj)

分析:要求[L,R]之间的逆序对数量,且Q<=100000,我们可以O(n^2)的时间求出[i,j]之间的逆序对的数量,i<=j,然后用O(1)的时间查询答案,具体怎么算,我们先来个辅助数组fi[maxn][maxn],其中maxn是题目给的最大N,因为N最大是1000,所以数组大小为1000000,不会爆空间,然后我们令fi[i][j],表示以i为逆序对的端点,然后计算j从i~1,以j为右端点的总数,用递推就可以在O(n^2)算出来,接着来个sum[maxn][maxn]数组,这个数组就是答案,其中sum[i][j]表示从i到j一共用多少组逆序对,因为我们有fi数组,所以只要累加fi数组就可以了,j从i到n,然后sum[i][j]=sum[i][j-1]+fi[j][i];这个怎么解释,好好想想就知道了,假设我们要知道从i到j的sum,因为我们已经知道sum[i][j-1]的sum了,而以j结尾,且已i开始的之间的总数就是fi[j][i],所以加上就是答案,复杂度O(n*n+Q),然后啪啪啪,就可以AC了

/*
Author:Chieh
Because Of Coding
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <stack>
#include <vector>
#include <queue>
#define LL long long
#define INF 1e9
#define EPS 1e-9
using namespace std;
const int maxn=1234;
LL ai[maxn];
LL fi[maxn][maxn];
LL sum[maxn][maxn];
int n,Q;
void init()
{
    for(int i=1; i<=n; i++)scanf("%I64d",&ai[i]);
}
void play()
{

    memset(fi,0,sizeof(fi));
    memset(sum,0,sizeof(sum));
    for(int i=1; i<=n; i++)
    {
        fi[i][i]=0;
        for(int j=i-1; j>=1; j--)
        {
            fi[i][j]=fi[i][j+1];
            if(ai[i]<ai[j])
            {
                fi[i][j]++;
            }
        }
    }
    for(int i=1;i<=n;i++){
        sum[i][i]=0;
        for(int j=i+1;j<=n;j++){
            sum[i][j]=sum[i][j-1]+fi[j][i];
        }
    }
    int L,R;
    while(Q--)
    {
        scanf("%d%d",&L,&R);
        printf("%I64d\n",sum[L][R]);
    }

}
int main()
{
    while(scanf("%d%d",&n,&Q)!=EOF)
    {
        init();
        play();
    }
    //    cout << "Hello world!" << endl;
    return 0;
}

HDU 5269 ZYB loves Xor I

飞机票:http://acm.hdu.edu.cn/showproblem.php?pid=5269

题意:给你一个数组A,A[i]^A[j]之后,假设为P,求lowbit(P)(就是P最低位为1的位置,然后就是2^为1位置)。然后求和,这里的话要计算两遍,即i和j j和i算两个,并不算一个。

分析:起先以为是最低位:不用为2的幂掌握的不够深刻啊。然后百度才知道要幂的。。。这次印象深刻了这种题的话,可以用分治,即分成两个块然后求值。具体怎么求值:

(1)先把所有的数转换为2进制。

(2)从最低位开始,如果是1就放入左边块,如果是0就放入右边块。(这里我是定义vector l,r ,每次是1就存入l,右边就存入r),这样的话就知道l里的元素和r里的元素是异或之后最低位为当前深度的2的幂,然后把l的大小*r的大小*2加到答案里去。*2是因为l和r算一边,然后r和l算遍。

(3)然后把l和r分别进行第二步。因为l和r已经不相干了。这里要及时退出,就是当l和r其中是0时就要退出,不然会TLE

总体复杂的O(n*logn),然后啪啪啪,就可以AC了

/*
Author:Chieh
Because Of Coding
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <stack>
#include <vector>
#include <queue>
#define LL long long
#define INF 1e9
#define EPS 1e-9
using namespace std;
const int maxn=5*12345;
int T;
int n;
int  ai[maxn];
int bi[30];
struct he
{
    bool isok[30];
} Sky[maxn];
int MOD=998244353;
void getBir()
{
    for(int i=1; i<=n; i++)
    {
        memset(Sky[i].isok,0,sizeof(Sky[i].isok));
        for(int j=29; j>=0; j--)
        {
            if(ai[i]-bi[j]>=0)
            {
                ai[i]-=bi[j];
                Sky[i].isok[j]=1;
            }
        }
    }
}
void init()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++)scanf("%d",&ai[i]);
    getBir();

}
LL ans;
void DFS(vector<int> V,int depth)
{
    if(depth==30)
    {
        return;
    }
    if(V.size()==0)return;
    vector<int> l;
    vector<int> r;
    for(int i=0; i<V.size(); i++)
    {
        int id=V[i];
        if(Sky[id].isok[depth])
        {
            l.push_back(id);
        }
        else
        {
            r.push_back(id);
        }
    }
    int ls=l.size();
    int rs=r.size();
    LL p=ls*rs;
    ans=(ans+((p*(bi[depth]%MOD)%MOD)*2)%MOD)%MOD;
    DFS(l,depth+1);
    DFS(r,depth+1);
}
int Case;
void play()
{
    ans=0;
    vector<int> V;
    for(int i=1;i<=n;i++)V.push_back(i);
    DFS(V,0);
    printf("Case #%d: %I64d\n",++Case,ans);
}
int main()
{
    bi[0]=1;
    for(int i=1; i<=29; i++){bi[i]=bi[i-1]*2;}
    scanf("%d",&T);
    Case=0;
    while(T--)
    {
        init();
        play();
    }
    // cout << "Hello world!" << endl;
    return 0;
}

 

HDU 5154 Harry and Magical Computer

飞机票: http://acm.hdu.edu.cn/showproblem.php?pid=5154

很好理解的题。。。

题目分析:最多100个点 跑一边floyd 看是否有环 复杂度 0(n^3)。一个trick就是自己到自己有环也是NO

/*
Author:Chieh
Grow up happy
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#define LL long long
using namespace std;
const int maxn=123;
int ai[maxn][maxn];
int n,m;
void init()
{
    int u,v;
    memset(ai,0,sizeof(ai));
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&u,&v);
        ai[u][v]=1;
    }
}
void play()
{
    for(int k=1; k<=n; k++)
    {
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                if(ai[i][k]&&ai[k][j])
                {
                    ai[i][j]=1;
                }
            }
        }
    }   
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if(ai[i][j]&&ai[j][i])
            {
                printf("NO\n");
                return;
            }
        }
    }

    printf("YES\n");
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        play();
    }
    return 0;
}

HDU 5150 Sum Sum Sum

链接 http://acm.hdu.edu.cn/showproblem.php?pid=5150

Bestcoder的一道题。。。直接暴力即可。。。但是看见被hack的好多。。。原来是在1这里出了问题。。。后面几个题没几个做的出来。看来这场的题偏难了

/*
Author:Chieh
Grow up happy
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <stack>
#include <vector>
#define LL long long
using namespace std;
const int maxn=1234;
int n;
int ai[maxn];
int bi[maxn];
void init()
{
    for(int i=1; i<=n; i++)scanf("%d",&bi[i]);
}
void play()
{
    int over=0;
    for(int i=1; i<=n; i++)
    {
        if(!ai[bi[i]])over+=bi[i];
    }
    printf("%d\n",over);
}
int main()
{
    memset(ai,0,sizeof(ai));
    for(int i=1; i<=1000; i++)
    {
        for(int j=2; j<i; j++)
        {
            if(i%j==0)ai[i]=1;
        }
    }
    while(scanf("%d",&n)!=EOF)
    {
        init();
        play();
    }
    return 0;
}