【2012长春区域赛】部分题解 hdu4420—4430

这场比赛特点在于两个简单题太坑,严重影响了心情。。导致最后只做出两题....当然也反映出心理素质的重要性

1002:

题意:一个矩阵b[n][n]通过数组 a[n]由以下规则构成,现在已知b[n][n]问是否有对应的数组a[n]

解法:

首先都是位运算所以不同位是不会互相影响的,即可按位考虑。

又发现,只要知道a[0]就可以算出通过b[0][]算出所有的a[],这样可以假设a[0]为0或1,由b[0][]得到一个完整的数组a[],再check这个数组a是否能正确的得到其他的b[][]即可

时间复杂度约为32*2*n^2 对于n=1000是可以接受的

当然队友是用2-SAT做的 吊吊吊吊吊orz 我就没写了,这里贴上队友的代码

代码:

#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include <stdio.h>
using namespace std;

const int maxn = 510;

struct TwoSAT
{
    int n;
    vector<int> G[maxn * 2];
    bool mark[maxn * 2];
    int S[maxn * 2], c;

    bool dfs(int x)
    {
        if(mark[x ^ 1]) return false;
        if(mark[x]) return true;
        mark[x] = true;
        S[c++] = x;
        for(int i = 0; i < G[x].size(); i++)
            if(!dfs(G[x][i])) return false;
        return true;
    }

    void init(int n) // 一定要注意初始化的点数,别弄错
    {
        this->n = n;
        for(int i = 0; i < n * 2; i++) G[i].clear();
        memset(mark, 0, sizeof(mark));
    }

    // x = xval or y = yval
    void add_clause(int x, int xval, int y, int yval) // 编号从0~n-1
    {
        x = x * 2 + xval;
        y = y * 2 + yval;
        G[x ^ 1].push_back(y);
        G[y ^ 1].push_back(x);
    }

    // 当x==xval 时可推导出 y==yval
    void add_edge(int x, int xval, int y, int yval)
    {
        x = x * 2 + xval;
        y = y * 2 + yval;
        G[x].push_back(y);
    }

    bool solve()
    {
        for(int i = 0; i < n * 2; i += 2)
            if(!mark[i] && !mark[i + 1])
            {
                c = 0;
                if(!dfs(i))
                {
                    while(c > 0) mark[S[--c]] = false;
                    if(!dfs(i + 1)) return false;
                }
            }
        return true;
    }
};

TwoSAT solver;
int n;
int a[maxn][maxn];

bool check(int l)
{
    solver.init(n);
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
        {
            int bit = (a[i][j] & (1 << l))>>l;

            if(i == j)
            {
                if(a[i][j] != 0)
                {
                    return false;
                }
            }
            else if(a[i][j] != a[j][i])
            {
                return false;
            }
            else if(i % 2 == 0 && j % 2 == 0) // &
            {
                solver.add_edge(i, 1, j, bit);
                solver.add_edge(j, 1, i, bit);
                if(bit)
                {
                    solver.add_edge(i, 0, i, 1);
                    solver.add_edge(j, 0, j, 1);
                }
            }
            else if(i % 2 == 1 && j % 2 == 1) // |
            {
                solver.add_edge(i, 0, j, bit);
                solver.add_edge(j, 0, i, bit);
                if(!bit)
                {
                    solver.add_edge(i, 1, i, 0);
                    solver.add_edge(j, 1, j, 0);
                }
            }
            else // ^
            {
                solver.add_edge(i, 1, j, bit ^ 1);
                solver.add_edge(j, 1, i, bit ^ 1);
                solver.add_edge(i, 0, j, bit);
                solver.add_edge(j, 0, i, bit);
            }
        }
    return solver.solve();
}

int main()
{

    while(~scanf("%d", &n))
    {
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
            {
                scanf("%d", &a[i][j]);
            }
        bool flag = true;
        // 枚举每一位,l为座椅的 位数
        for(int l = 0; l <= 31; l++)
        {
            if(!check(l))
            {
                flag = false;
                break;
            }
        }
        puts(flag?"YES":"NO");
    }

    return 0;
}

1003:

题意:

这个简单题题意挺恶心的。。先开始一直没读懂。。

小明要在五座山上采五堆蘑菇,每堆的个数是0~2012,采完后必须送出三堆和为1024倍数的蘑菇(否则全送出),回家之前如果总数大于1024还要一直被抢1024。

现在已经采了n堆(n<=5),剩下的可以任意采(0~2012)问最终最多能拿回家多少蘑菇.

解法:

分情况特判.....以下省略好多字

代码:

#include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
int a[6];
const int mod = 20121024;
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif
    int n;
    while (~scanf ("%d", &n))
    {
        memset(a, 0, sizeof(a));
        int sum = 0;
        for (int i = 0; i < n; i++)
        {
            scanf ("%d", a+i);
            sum += a[i];
        }
        int ans = 0, res = 0;
        if (n<=3)
        {
            printf("%d\n", 1024);
            continue;
        }
        if (n == 4)
        {
            int ans = 0;
            bool flag = 0;
            for (int i = 0; i < 4; i++)
            {
                for (int j = i+1; j < 4; j++)
                {
                    int tmp = a[i]+a[j];
                    if (tmp)
                    ans = max(ans, (tmp%1024) ? (tmp%1024) : 1024);
                    for (int k = j +1; k < 4; k++)
                    {
                        if ((a[i] + a[j] + a[k]) % 1024 == 0)
                            flag = 1;
                    }
                }
            }
            if (flag)
                printf("%d\n" , 1024);
            else
                printf("%d\n" ,ans);
            continue;
        }
        if (n == 5)
        {
            bool f = 0;
            int  ans = 0;
            for (int i = 0; i < 5; i++)
            {
                for (int j = i+1; j < 5; j++)
                {
                    for (int k = j+1; k < 5; k++)
                    {
                        int tmp = a[i] +a[j] +a[k];
                        if (tmp % 1024 == 0)
                        {
                            if (sum-tmp)
                            ans = max(ans, ((sum-tmp)%1024) ? (sum-tmp)%1024 : 1024);
                        }
                    }
                }
            }
            printf("%d\n",(ans > 1024) ? (ans %1024) : ans);
        }
    }
    return 0;
}

1004:

题意:

 求y的取值范围

思路:

高中数学题,移项得到一个二次函数,然后各种分类讨论,太麻烦了没敢写。。。

1005:

队友做的 先挖坑

1008:

题意:

知道n个数的和sum,以及n个数的LCM,求合法的组成方案(排列)

解法:
发现lcm的转移只可能通过lcm的约数,(一开始和分解质因数搞呢,后来经过学长提醒发现直接找出约数即可 orz),约数数量不是很多。。这样就可以dp了

把约数哈希一下 dp[i][j][k]代表考虑到第i个数,当前lcm为总LCM的第j个约数,当前sum为k的方案数,转移很容易

代码:

#include <iostream>
#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<ctype.h>
using namespace std;
#define MAXN 10000
const int mod=1e9+7;
bool is(int p)
{
    for(int i=2; i*i<=p; i++)
    {
        if(p%i==0)
            return 0;
    }
    return 1;
}
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
int lcm(int a,int b)
{
    return a/gcd(a,b)*b;
}
int prime[1010];
int s[50];
int dp[110][1100][50];
int a[1010];
int ha[1010];
int l[50][50];
int sum,L,n,m;
int main()
{
   // freopen("in.txt","r",stdin);
    m=0;
    for(int i=2; i<=1000; i++)
    {
        if(is(i))
        {
            prime[m++]=i;
        }
    }
    while(scanf("%d%d%d",&sum,&L,&n)!=EOF)
    {
        memset(ha,-1,sizeof(ha));
        int lim=0;
        for(int i=1;i<=L;i++)
        {
            if(L%i==0)
            {
                ha[L/i]=lim;
                s[lim++]=L/i;
            }
        }
        for(int i=0;i<lim;i++)
        {
            for(int j=0;j<lim;j++)
            {
                l[i][j]=lcm(s[i],s[j]);
            }
        }
        memset(dp,0,sizeof(dp));
        dp[0][0][lim-1]=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=sum;j++)
            {
                for(int k=0;k<lim;k++)
                {
                    if(!dp[i-1][j][k])
                        continue;
                    for(int t=0;t<lim;t++)
                    {
                        if(j+s[t]<=sum)
                        {
                            if(ha[l[k][t]]==-1)
                                continue;
                            dp[i][j+s[t]][ha[l[k][t]]]+=dp[i-1][j][k];
                            dp[i][j+s[t]][ha[l[k][t]]]%=mod;
                        }
                    }
                }
            }
        }
        cout<<dp[n][sum][0]<<endl;
    }
    return 0;
}

1010:

题意:
一个大矩形被一些线段分成了小矩形,现在给定两个点的坐标,求出删除一些线段使这两点在同一矩形后剩余矩形数量的最大值。

思路:

其实就是要找所求两点共同所在的最小的矩形(除此之外的线段都不删除,得到的剩余矩形数肯定最多)。

而按照题意的分割矩形法其实就是形成了一颗树,这样就发现两个点所在的最小矩形其实是这两个点当前所在矩形的lca

理论ac了。。代码还没写

1011:

题意:

给定一个等比数列 1(或者0)+k+k^2+....k^r的和 S,要求求出r 和k,多解首先满足r*k最小,然后满足 r最小

解法:

由于k>=2所以可以计算发现r最大为40,则可以枚举r,二分求得k ,如果r和二分出的k刚好等于 k或者k-1 则符合题意,可以统计答案

坑点是二分过程中容易溢出

代码:

#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long ll;

ll n;

ll equ(ll ak , int r)
{
    ll ans = 1;
    ll k = ak;
    for(int i = 1; i <= r; i++)
    {
        ans += k;
        if(ans > n + 1)
            break;
        if(ans<=0)
            return 10000000000000LL;
        k *= ak;
    }
    return ans;
}

int main()
{

    while(~scanf("%I64d", &n))
    {
        ll ansk = 10000000000000LL;
        int ansr = 100;

        // 枚举r
        for(int r = 1; r <= 40; r++)
        {
            // 二分k
            ll l = 1, R = 1000000000001LL;
            while(l < R)
            {
                ll m = (l + R + 1) / 2;
                if(equ(m, r) <= n)
                {
                    l = m;
                }
                else
                {
                    R = m - 1;
                }
            }

            ll k = l;
            if(equ(k, r) == n)
            {
                // 保存答案
                if((ansk * ansr > k * r) || ((ansk * ansr == k * r) && ansr > r))
                {
                    ansk = k;
                    ansr = r;
                }
            }

            // 二分k
            l = 1, R = 1000000000001LL;
            while(l < R)
            {
                ll m = (l + R + 1) / 2;
                if(equ(m, r) <= n + 1)
                {
                    l = m;
                }
                else
                {
                    R = m - 1;
                }
            }

            k = l;
            if(equ(l, r) == n + 1)
            {
                // 保存答案
                if((ansk * ansr > k * r) || ((ansk * ansr == k * r) && ansr > r))
                {
                    ansk = k;
                    ansr = r;
                }
            }
        }
        printf("%d %I64d\n", ansr, ansk);
    }

    return 0;
}

时间: 2024-08-27 05:56:10

【2012长春区域赛】部分题解 hdu4420—4430的相关文章

2015年ACM长春区域赛比赛感悟

距离长春区域赛结束已经4天了,是时候整理一下这次比赛的点点滴滴了. 也是在比赛前一周才得到通知要我参加长春区域赛,当时也是既兴奋又感到有很大的压力,毕竟我的第一场比赛就是区域赛水平,还是很有挑战性的.在接到通知后,我便开始临阵抱佛脚,课也不怎么听了,上课把时间全都用在了看各种算法上,回到实验室便整理模板.开cf练手.在去比赛前,已经将所看过的算法模板都整理好了. 周五上午9点三刻左右,我们便出发了,需要经历12个小时才能到达我们此次的目的地——长春,途中我还将计算几何稍微看了一下.直到晚上11点

hdu4271 Find Black Hand 2012长春网络赛E题 最短编辑距离

hdu4271 Find Black Hand  2012长春网络赛E题  最短编辑距离 Find Black Hand Time Limit : 5000/2000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 19   Accepted Submission(s) : 1 Problem Description I like playing game with my friend

2015长春区域赛赛后总结

比赛时间:2015.10.18 队名:哆啦小黄埋(alone kampai UMR) 成员:ST,QL,WC 解出题目:两道 网络赛的时候并没有出线,老师争取到了女队名额,才有了参加区域赛的机会(谢谢老师么么哒~ 这次的比赛打铁没有什么可怨的,实力不足+比赛策略不当+心里素质差,每一条都是超级致命的(哭 过了的两道水题,L和F,L是经过ST和WC讨论之后1A的,F是我和ST讨论过敲得,ST去看其他题,而我就在一直卡题.由于代码奇葩,队友都看不懂,只能干着急+出数据,所以只能自己调试,WA好多发,

【2012天津区域赛】部分题解 hdu4431—4441

1001: 题意:给你13张麻将牌,问可以胡哪些张 思路: 枚举可能接到的牌,然后dfs判断能否胡 1002: 题意: 已知n,m 求 n的所有约数在m进制下的平方和 做法:队长用java高精度写的 代码: import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.PrintWriter; import java.io.ObjectInputStream.GetField; im

Travel(HDU 5441 2015长春区域赛 带权并查集)

Travel Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 2404    Accepted Submission(s): 842 Problem Description Jack likes to travel around the world, but he doesn’t like to wait. Now, he is tr

hdu 4463 有一条边必须加上 (2012杭州区域赛K题)

耐克店 和 苹果店必须相连 Sample Input42 30 01 00 -1 1 -10 Sample Output3.41 1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 # include <cmath> 6 # define LL long long 7 using namespace std ; 8

HDU 4438 Hunters 区域赛水题

本文转载于 http://blog.csdn.net/major_zhang/article/details/52197538 2012天津区域赛最水之题: 题意容易读懂,然后就是分情况求出A得分的数学期望,所谓数学期望就是在该概率下的平均得分. 现在就是两种方案,Alice要根据输入给出的数据情况选出最优方案,也就是先选老虎,还是狼. 1.A先选老虎: a.B也先选老虎,则得分为Q(P*X+P*Y); //打完老虎还要打狼 b.B选狼,则两人可以直接获得猎物,则得分为(1-Q)*X 所以1方案

2014年北京赛区区域赛现场赛A,D,H,I,K题解(hdu5112,5115,5119,5220,5122)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud 下午在HDU上打了一下今年北京区域赛的重现,过了5题,看来单挑只能拿拿铜牌,呜呜. 先将这五题的题解放上来,剩余题目等搞出来再补上 A题 A Curious Matt Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others) Problem Description T

2015亚洲区域赛长春赛区网络预选赛

第一次打网络赛,第一场,总体来说还可以吧,但是我们队三个人状态都并不太好,主要就是 WA 的比较多吧,开场看最后一题是我的习惯了,虽然貌似那题到打了一半可能才有队伍做出来了,我看了感觉像前几天训练赛的时候做的一道题.刻盘开场看 06 ,凯神开场 01.接着两分钟学长发现 07 水题我就跟着看了发题意,求区间最大值,静态.然后数据范围也很小,就直接开敲暴力,四分钟的时候过的,大概 20 名左右吧,那就是我们的最高名次了2333……接着我准备继续研究下 13 ,刻盘告诉我 06 是关于循环的子串的问