• 2013 ACMICPC China Nanjing Invitational Programming Contest 总结


    A.Play the Dice (HDU 4586)

    思路:

      很裸的一道概率题,容易得到公式ans=1/n*va[1]+1/n*va[2]+...+1/n*va[n]+m/n*ans,va[i]为对应位置得到的钱数,但是细节不得不注意!!第一次没看到无限多钱要输出inf,第二次没想到,即使n==m也不一定无限多钱,因为有可能每个面得到的钱数都是0.

    #include<stdio.h>
    #include<string.h>
    int va[300];
    int main()
    {
        int n,i,m,LL;
        while(scanf("%d",&n)!=EOF)
        {
            double ans=0;
            for(i=1;i<=n;i++){
                scanf("%d",&va[i]);
                ans+=1.0*va[i];
            }
            scanf("%d",&m);
            for(i=0;i<m;i++)
                scanf("%d",&LL);
            if(n==m)
            {
                if(ans==0)
                    printf("0.00\n");
                else
                    printf("inf\n");
                continue;
            }
            ans=ans/(1.0*(n-m));
            printf("%.2lf\n",ans);
        }
        return 0;
    }
    NJUST 1737


    B.TWO NODES (HDU 4587)

    思路:

      图论渣渣...等学了图论再看..

    C.Count The Carries (HDU 4588)

    思路:

      这题一直在想数位dp神马的,后来才发现其实是有规律的....1-n转化成2进制以后,每一位1出现都是循环的,所以可以直接求出1-n之间所有数转化成2进制后,每一位1的个数..然后就可以直接算进位的次数了.

    #include<stdio.h>
    #include<string.h>
    long long sum[100];
    long long solve(int a,int b)
    {
        memset(sum,0,sizeof(sum));
        long long cir=2;
        if(b>=0)
        {
            for(int i=1;i<=40;i++)
            {
                if(2*b<cir) break;
                sum[i]+=b/cir*(cir/2);
                int temp=b%cir;
                if(temp>(cir/2))
                    sum[i]+=temp-(cir/2);
                cir*=2;
            }
        }
        cir=2;
        if(a>=0)
        {
            for(int i=1;i<=40;i++)
            {
                if(2*a<cir) break;
                sum[i]-=a/cir*(cir/2);
                int temp=a%cir;
                if(temp>(cir/2))
                    sum[i]-=temp-(cir/2);
                cir*=2;
            }
        }
        long long ret=0;
        int pos=1;
        while(sum[pos]!=0)
        {
            ret+=sum[pos]/2;
            sum[pos+1]+=(sum[pos]/2);
            pos++;
        }
        return ret;
    }
    
    int main()
    {
        int a,b;
        while(scanf("%d%d",&a,&b)!=EOF)
        {
            printf("%lld\n",solve(a,b+1));
        }
        return 0;
    }
    NJUST 1739

    G.Boring Game (HDU 4592)
    思路:

      大家第一下一定都会想到枚举第一行的状态改变...目测这题卡的就是这种做法...TLE了好久,其实,不管哪种状态,最后都可以处理成,前n-1行全是0的状态,而第n行不确定,由于第n行的状态只有1<<n种,所以可以预处理出除了最后一行,其它行全是0时,哪种状态改变可以让第一行变成0,然后保存下来.以上预处理过后,求解每个棋盘的时候,第一行状态不变,从第二行开始向下先处理一遍,就变成了我们预处理过的状态,再用我们预处理出来的状态处理回去就可以全变成0了.当然,两次改变的位置是要异或一下的,因为按2下等于没按嘛.

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    using namespace std;
    #define INF 100000000
    int va[10],n,tem[10],NUM1[300],tem1[10],tem2[10];
    int MAP[10][300];
    vector<int>road[10][300];
    int min(int x,int y){
        return x<y?x:y;
    }
    int get1(int n){
        n=(n&0x55555555)+((n>>1)&0x55555555);
        n=(n&0x33333333)+((n>>2)&0x33333333);
        n=(n&0x0f0f0f0f)+((n>>4)&0x0f0f0f0f);
        n=(n&0x00ff00ff)+((n>>8)&0x00ff00ff);
        n=(n&0x0000ffff)+((n>>16)&0x0000ffff);
        return n;
    }
    
    void init(){
        int i,j,k,r;
        for(i=0;i<=255;i++){
            NUM1[i]=get1(i);
        }
        for(i=1;i<=8;i++)
        {
            int state=(1<<i)-1;
            for(j=0;j<=state;j++)
            {
                MAP[i][j]=j^((j<<1)&state)^(j>>1);
            }
            for(j=0;j<=state;j++)
            {
                for(k=0;k<=state;k++)
                {
                    memset(tem,0,sizeof(tem));
                    int pre=k;
                    tem[1]=j^MAP[i][k];
                    for(r=2;r<=i;r++)
                    {
                        tem[r]^=pre;
                        tem[r]^=MAP[i][tem[r-1]];
                        pre=tem[r-1];
                    }
                    if(tem[i]==0)
                    {
                        road[i][j].push_back(k);
                    }
                }
            }
        }
    }
    int make(int a[],int b[],int n,int sta)//初始状态,中间状态
    {
        int r;
        memset(tem,0,sizeof(tem));
        b[1]=sta;
        tem[1]=a[1]^MAP[n][sta];
        for(r=2;r<=n;r++)
        {
            tem[r]=a[r]^b[r-1];
            tem[r]^=MAP[n][tem[r-1]];
            b[r]=tem[r-1];
        }
        return tem[n];
    }
    
    int main()
    {
        int T,i,j,ans;
        init();
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            for(i=1;i<=n;i++)
                scanf("%d",&va[i]);
            memset(tem2,0,sizeof(tem2));
            tem2[1]=make(va,tem1,n,0);
            ans=INF;
            for(i=0;i<(int)road[n][tem2[1]].size();i++)
            {
                make(tem2,va,n,road[n][tem2[1]][i]);
                int cnt=0;
                for(j=1;j<=n;j++)
                    cnt+=NUM1[tem1[n-j+1]^va[j]];
                ans=min(ans,cnt);
            }
            if(ans==INF) printf("-1\n");
            else printf("%d\n",ans);
        }
        return 0;
    }
    NJUST 1743


    H.Robot (HDU 4593)

    思路:

      这个就略过了..

    K.Yet another end of the world (HDU 4596)

    思路:

      看数据量一定是枚举任意2个虫洞有没有交集,对于2个虫洞,只要能找到x1*k1+a=x2*k2+b(k1,k2为任意整数)就说明有交集,对等式移项可得x1*k1-x2*k2=b-a,如果有整数解,那么(b-a)%gcd(x1,x2)应该等于0,否则无整数解,现在a的范围是[y1,z1],b的范围是[y2,z2],那么b-a的范围也可以确定下来,剩下的只要判断一下是否存在(b-a)%gcd(x1,x2)==0就行了,第一次写的时候没完全想清楚区间的转化,代码写的比较挫..

    #include<stdio.h>
    #include<iostream>
    using namespace std;
    struct node
    {
        int x,y,z;
    }va[1200];
    long long gcd(long long x,long long y)
    {
        while(x)
        {
            long long temp=x;
            x=y%x;
            y=temp;
        }
        return y;
    }
    int check(int i,int j)
    {
        if(va[i].x==va[j].x){
            if(va[i].y<va[j].x)
                return 0;
            if(va[j].y<va[i].x)
                return 0;
            return 1;
        }
        long long tem=gcd(va[i].x,va[j].x);
        if(tem==1) return 1;
        long long max=va[j].z-va[i].y;
        long long min=va[j].y-va[i].z;
        if(min<0){
            long long k=(-min)/tem;
            max+=k*tem;
            min+=k*tem;
        }
        while(min<0){
            max+=tem;
            min+=tem;
        }
        if(min%tem==0||max%tem==0)
            return 1;
        if(min/tem!=max/tem)
            return 1;
        return 0;
    }
    int main()
    {
        int n,i,j;
        while(scanf("%d",&n)!=EOF)
        {
            for(i=1;i<=n;i++)
                scanf("%d%d%d",&va[i].x,&va[i].y,&va[i].z);
            int flag=0;
            for(i=1;i<=n;i++){
                for(j=1;j<=i;j++){
                    if(i==j) continue;
                    if(check(i,j)){
                        flag=1;
                        break;
                    }
                }
            }
            if(flag)
                printf("Cannot Take off\n");
            else
                printf("Can Take off\n");
        }
        return 0;
    }
    NJUST 1747
  • 相关阅读:
    linux驱动---等待队列、工作队列、Tasklets【转】
    Pinctrl子系统之一了解基础概念【转】
    Linux内存管理(最透彻的一篇)【转】
    linux驱动学习笔记---实现中断下半部以及驱动编写规范(七)【转】
    一些网址下载【转】
    Linux /proc/$pid部分内容详解【转】
    Linux kernel workqueue机制分析【转】
    Linux进程核心调度器之主调度器schedule--Linux进程的管理与调度(十九)【转】
    Linux Kernel PANIC(三)--Soft Panic/Oops调试及实例分析【转】
    Linux内核调试的方式以及工具集锦【转】
  • 原文地址:https://www.cnblogs.com/SolarWings/p/3078859.html
Copyright © 2020-2023  润新知