2017中国大学生程序设计竞赛

来源:互联网 发布:黑马程序员训练营 编辑:程序博客网 时间:2024/06/07 16:21



首先.这次开局烂到家了,1200+人过了的03签到题,我队还一直在MLE中,因为怕超时,复杂度算不清不敢暴力.

最后还是过了07 05 04 之后才稳一点慢慢的改一点交一点 ...罚时爆炸的过了03..






hdu 6152 && 1003 Friend-Graph


这个题真的暴力也能过?还飞快.暴力不是 n3 吗. 哦不,好像并不是n3的.


这个题内存卡的比较紧,直接一个bool 类型了.


当时这个签到题我们队是最后出的,卡了很久,我一开始想并查集最后被推翻了,然后队友想了 最大团来做.然后就一直MLE.我最后写了个暴力,寻思直接是n3 我用两个vector 来存有边的和无边的,两种情况分别找,然后还想这记录1的个数多,还是0的个数多.来优化常数,可惜 都没用!!!因为MLE。。。

当时可能看到1200+人过有点不淡定了...没想到这么优雅的暴力呢.



PS: 主要是这个题目有个定理,保证6个点以上一定bad,所以很快就退出.

#include<iostream>#include<cstdio>#include<string.h>using namespace std;const int maxn = 3e3;bool w[maxn][maxn];bool flag(int n){    for(int i = 1; i <= n; ++ i)    {        for(int j = i + 1; j <= n; ++ j)        {            for(int k = j + 1; k <= n; ++ k)            {                if(w[i][j] == w[i][k] && w[i][k] == w[j][k] && w[i][j] == w[j][k])                    return true;            }        }    }    return false;}int main(){    int t, n, m;    scanf("%d", &t);    while(t --)    {        scanf("%d", &n);        for(int i = 1; i < n; ++ i)        {            for(int j = 1 + i; j <= n; ++ j)            {                scanf("%d", &m);                if(m == 1)                    w[j][i] = w[i][j] = false;                else                    w[j][i] = w[i][j] = true;            }        }        if(flag(n))            printf("Bad Team!\n");        else            printf("Great Team!\n");    }    return 0;}


队友的xjb做法:

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;#include<cstdio>#include<cstring>#define N 3005bool flag[N], a[N][N];int ans, cnt[N], group[N], n, vis[N];bool dfs( int u, int pos ){    if(ans >= 3) return 1;//因为递归层数太多,所以这里加了个剪枝....     int i, j;    for( i = u+1; i <= n; i++){        if( cnt[i]+pos <= ans ) return 0;        if( a[u][i] )        {            for( j = 0; j < pos; j++ ) if( !a[i][ vis[j] ] ) break;            if( j == pos )            {                vis[pos] = i;                if( dfs( i, pos+1 ) ) return 1;            }        }    }    if( pos > ans )    {            for( i = 0; i < pos; i++ )                group[i] = vis[i];            ans = pos;            return 1;    }    return 0;}void maxclique(){    ans=-1;    for(int i=n;i>0;i--)    {        vis[0]=i;        dfs(i,1);        cnt[i]=ans;    }}int main(){    int t;    scanf("%d", &t);    while(t--)    {        memset(a, 0, sizeof(a));        scanf("%d", &n);        for(int i = 1; i <= n-1; i++)        {            for(int j = 1; j <= n-i; j++)            {                scanf("%d", &a[i][i+j]);                a[i+j][i] = a[i][i+j];            }        }        int ans1, ans2;        maxclique();        ans1 = ans;        for(int i = 1; i <= n; i++)            for(int j = 1; j <= n; j++)                a[i][j] = !a[i][j];        maxclique();        ans2 = ans;        if(ans1 >= 3 || ans2 >= 3) puts("Bad Team!");        else puts("Great Team!");    }    return 0;}


hdu 6153 &&1004 A Secret


队友过得,我还没学会,正解好像是扩展KMP?也可能是他瞎搞的

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;typedef long long ll;const int maxn = 2e6+10;const int mod = 1e9+7;char str[maxn], str1[maxn], str2[maxn];int len, len3;int nt[maxn], nt3[maxn];ll res[maxn], res3[maxn];void getNext1(){    nt[0] = -1;    int i = 0, j = -1;    while (i <= len)    {        if (j == -1 || str[i] == str[j])            nt[++i] = ++j;        else            j = nt[j];    }}void getNext2(){    nt3[0] = -1;    int i = 0, j = -1;    while (i <= len3)    {        if (j == -1 || str2[i] == str2[j])            nt3[++i] = ++j;        else            j = nt3[j];    }}int main(){    int t;    cin >> t;    while(t--)    {        memset(res, 0, sizeof(res));        memset(res3, 0, sizeof(res3));        memset(nt, 0, sizeof(nt));        memset(nt3, 0, sizeof(nt3));        scanf(" %s %s", str1, str2);        int len1 = strlen(str1);        int len2 = strlen(str2);        for(int i = 0; i < len1/2; i++)            swap(str1[i], str1[len1-i-1]);        for(int i = 0; i < len2; i++)            str[len2-i-1] = str2[i];        str[len2] = '#';        for(int i = len2+1; i < len1+len2+1; i++)            str[i] = str1[i-len2-1];        str[len1+len2+1] = 0;        len = len1+len2+1;        len3 = len2;//        cout << str << endl;        getNext1();        for(int i = 0; i < len2/2; i++)            swap(str2[i], str2[len2-i-1]);        getNext2();//        cout << str << endl;        ll ans = 0;//        int len = len1+len2+1;        for(int i = len; i >= 1; i--)        {            res[i]++;            res[nt[i]] += res[i];        }        for(int i = len3; i >= 1; i--)        {            res3[i]++;            res3[nt3[i]] += res3[i];        }//        cout << str << ' ' << str2 << endl;//        for(int i = 1; i <= len2; i++)//            cout << res[i] << ' ' << res3[i] << endl;        for(ll i = 1; i <= len2; i++)        {//            cout << i << ' ' << res[i] << endl;            ans = (ans+(res[i]-res3[i])*i)%mod;        }        printf("%lld\n", ans);    }    return 0;}

hdu 6154 &&1005 CaoHaha's staff


正解找规律. 但是我队找规律比较菜啊....


我是用了二分做的...


当然这个题目数据在大点 可能就要二分了吧。。


首先我看到题目的时候...好久队友给我讲明白了题意,我看求最小,立马套二分啊,诶 ?满足单调性.即走k步可以凑出的面积 k+1 步一定也可以啊.

好,那么就像怎么check,这个check其实感觉就好找到的规律差不多了,首先我要想使面积最大,我肯定优先走对角线,因为横着和斜着斜着每次增加 根2的长度.那么对于相同的步数的话,我肯定要是长宽越接近凑出的面积尽可能的大. 那么我先考虑步数为偶数的情况,对于二分到的步数先均分给四个边,因为是偶数,%4一定是2或0了,如果余2 那么我就可以使两个对边长度在增加1 ,这时的面积为 ch *ku *2. 然后我发现对于步数比他多1的奇数来说,他所能得到的面积正是在原来的四边形上在多扩展一个等腰梯形,且步数正好多1.所以我check就判断了奇数和偶数来check了,

至于为什么是一定多一步的,从最后一个样例5为7可以看出来为什么,然后多画几个结论就得到了.


#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;const int maxn = 1e5 + 10;typedef long long ll;ll n;int check(ll x){    ll res = x;    if(x & 1)    res --;    ll len = res / 4;    ll ch ,ku;    ch = ku = len;    if(res % 4)    ch++;    ll s = 0;    if(x % 2 == 0)    {        s = ch * ku * 2;    }    else    {        double ss = 0.5 * (2*ch - 1);     //    cout<<x<<' '<<ss<<endl;        s = ch * ku * 2 +  (ll)ss;        //cout<<s<<endl;    }    if(s >= n)    return 1;    return 0;}int  main(){    int t;    cin>>t;    while(t--)    {        scanf("%lld",&n);        ll l = 0,r = 2*1e9,mid,ans;        while(l <= r)        {            mid = (l + r) >> 1;            if(check(mid))            r = mid - 1,ans = mid;            else            l = mid + 1;        }            //check(7);//        puts("");//        check(6);        printf("%lld\n",ans);    }    return 0;}


hdu 6156 && 1007 Palindrome Function



2 -36 进制中 (L,R ) 回文数有多少个

让你求(l,r)满足条件的数有多少啊..这不很明显数位dp,算了复杂度,足够了.枚举每种进制,剩下的求法和10进制回文数有多少一样了.


我这里dp【i】【j】【k】【f】表示的是k进制下,串的起点是i,终点是j, 是否已经是回文串了.f 为0 表示否 1 表示 是


PS: 这里需要注意的就是前导0的问题,由于前导0的存在使得回文串的长度是不固定的,所以这里就设法解决前导0就好,另外需要开个中间数组记录一下前面填过的数,来判断回文



#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;const int maxn = 1e5 + 10;typedef long long ll;ll dp[50][50][50][5];// dp【i】【j】【k】【f】表示的是k进制下,串的起点是i,终点是j,// 是否已经是回文串了. f 为0 表示否 1 表示 是 int num[50],temp[50];//temp 中间数组 ,用来判断回文 ll dfs(int start,int cur,int state,int fp,int base)//start 字符串起点,也用来确定第一个非前导0的位置.cur 当前处理到第几位//state 是否是回文串.// base 进制 {    if(cur<0)        return state;    if(!fp&&dp[start][cur][base][state]!=-1)        return dp[start][cur][base][state];    int fpmax = fp ? num[cur] : (base-1);    ll ret = 0;    for(int i = 0;i <= fpmax;i++)    {        temp[cur] = i;//确定该位的值         if(start == cur&&i == 0)// 前导0             ret+=dfs(start-1,cur-1,state,fp && i == fpmax,base);        else if(state&&cur<(start+1)/2)//小于一半了,说明要开始判断是否回文了             ret+=dfs(start,cur-1,temp[start-cur]==i,fp&&i==fpmax,base);        else//未构成回文串就继续处理下一位.             ret+=dfs(start,cur-1,state,fp&&i==fpmax,base);    }    if(!fp)         dp[start][cur][base][state]=ret;    return ret;}ll solve(ll n,int k){    int len=0;    while(n)    {        num[len++]=n%k;        n/=k;    }    num[len]=0;    return dfs(len-1,len-1,1,1,k);}int  main(){    int _;    cin>>_;    ll L,R;    int l,r;    ll ans1,ans2,ans,ans3;    int t=1;    memset(dp,-1,sizeof dp);    while(_--)    {        ans = 0;        scanf("%lld %lld %d %d",&L,&R,&l,&r);        for(int i = l;i <= r;i++)        {             ans1 = solve(L-1,i);             ans2 = solve(R,i);             ans3 = ans2 - ans1;            ans += ans3*i + (R - L + 1 - ans3);        }         printf("Case #%d: %lld\n",t++,ans);    }    return 0;}



原创粉丝点击