TCO2016乱做

目录

模拟&搜索

1A 250pts
1B 250pts
1C 250pts
2A 400pts

贪心

1B 500pts
1C 500pts

三分

1B 1000pts

动态规划

1A 500pts

数学相关

Regional Wildcard 250pts

题目

Round 1A

250pts

题意简述

给你一个形如HH:MM的时刻,问把时针分针倒换之后的时刻是多少。

数据范围

保证时针分针指向的是表盘的数字。

思路

直接模拟即可

代码

#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
class EllysTimeMachine{
    public:
        int h,m,hh,mm;
        string getTime(string t)
        {
            h=(t[0]-'0')*10+(t[1]-'0');
            m=(t[3]-'0')*10+(t[4]-'0');
            hh=(m/5+11)%12+1;
            mm=h*5%60;
            string ret;
            ret+=(hh/10)+'0';
            ret+=(hh%10)+'0';
            ret+=':';
            ret+=(mm/10)+'0';
            ret+=(mm%10)+'0';
            return ret;
        }
};

500pts

题意简述

n 只袜子,并给出每只袜子的大小sizei。现在要让袜子配对,要求至少配出 p 对,使得最大的|sizeusizev|最小,求这个最小值。

数据范围

1n1000 1sizei109

思路

DP。
先排序。
f[i][j] 表示前 i 个匹配j对所需要的最小的最大差距。
f[i][j]=min(max(f[i2][j1],abs(s[i]s[i1])),f[k][j])k[1,i1]
决策是是否和前一个配对。
这样复杂度是 O(n3) 难以通过。
我们可以对后面的 f[k][j] 做一个前缀min,这样复杂度 O(n2)
一开始想成了二分答案二分图匹配= =

代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<algorithm>
using namespace std;
class EllysSocks{
    public:
        int f[1010][1010];
        int mn[1010][1010];
        int n;
        int getDifference(vector<int> s,int p)
        {
            memset(f,0x3f,sizeof(f));
            memset(mn,0x3f,sizeof(mn));
            n=s.size();
            sort(s.begin(),s.end());
            for (int i=1;i<n;i++)
            {
                f[i][0]=mn[i][0]=0;
                for (int j=1;j<=min(p,(i+1)/2);j++)
                {
                    f[i][j]=min(f[i][j],mn[i-1][j]);
                    if (i-2>=1)
                        f[i][j]=min(f[i][j],max(abs(s[i]-s[i-1]),mn[i-2][j-1]));
                    else
                        f[i][j]=min(f[i][j],abs(s[i]-s[i-1]));
                    mn[i][j]=min(mn[i-1][j],f[i][j]);
                }
            }
            return f[n-1][p];
        }
};

Round 1B

250pts

题意简述

给出一个数 n ,每次可以将x变成其各位数字的平方和,如果 x 为质数就退出,问会出现几个不同的数。

数据范围

1n109

思路

略微观察之后会发现经过几次变换之后,数字会在 [1,729] 之间变化,开一个此范围的bool数组记录。
爆搜即可。

代码

#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
class ExploringNumbers{
    public:
        bool vis[1010];
        bool is_prime(int n)
        {
            if (n==1)
                return false;
            for (int i=2;i<=int(sqrt(n));i++)
                if (n%i==0)
                    return false;
            return true;
        }
        int dfs(int x)
        {
            if (is_prime(x))
                return 1;
            if (x<=729)
            {
                if (vis[x])
                    return -1;
                vis[x]=1;
            }
            int tmp=0;
            while (x>0)
                tmp+=(x%10)*(x%10),x/=10;
            tmp=dfs(tmp);
            if (tmp==-1)
                return -1;
            else
                return tmp+1;
        }
        int numberOfSteps(int n)
        {
            memset(vis,0,sizeof(vis));
            return dfs(n);
        }
}

500pts

题意简述

给出 n 个数ai,和一些你所拥有的 [1,9] 数字的个数 di ,你可以用你拥有的数字替换掉数中某些数位的数,使得替换后的数之和最大,求这个和。

数据范围

1n50
1ai106
1di103

思路

贪心。
按位贪心,从最大的数字开始,每次选取尽量多的。

代码

#include<cstdio>
#include<vector>
using namespace std;
class ReplacingDigit{
    public:
        int getMaximumStockWorth(vector<int> s,vector<int> d)
        {
            int fac10[10],f[100][20]={0},num[20]={0},cnt[20]={0};
            int n,sum=0,last;
            fac10[0]=1;
            for (int i=1;i<=6;i++)
                fac10[i]=fac10[i-1]*10;
            n=s.size();
            for (int i=0;i<n;i++)
            {
                int tmp=s[i],di=0;
                while (tmp)
                    f[di][tmp%10]++,tmp/=10,cnt[di]++,di++;
            }
            for (int i=0;i<9;i++)
                num[i+1]=d[i];
            for (int i=9;i>=0;i--)
            {
                last=cnt[i];
                for (int j=9;j>=0;j--)
                {
                    if (last-f[i][j]<=0)
                    {
                        sum+=last*j*fac10[i];
                        break;
                    }
                    last-=f[i][j];
                    sum+=f[i][j]*j*fac10[i];
                    if (last-num[j]<=0)
                    {
                        sum+=last*j*fac10[i];
                        num[j]-=last;
                        break;
                    }
                    last-=num[j];
                    sum+=num[j]*j*fac10[i];
                    num[j]=0;
                }
            }
            return sum;
        }
};

1000pts

题意简述

给出 n 个物品,每个物品有一个限制pi,要求这个物品的能量值必须 pi
再给出 h 个普通产生器,花费x可以使得 hi 产生器对 [li,ri] 范围内的每个物品增加 x 的能量。
还有一个特殊产生器,花费xt可以使得所有物品增加 x 的能量。
求满足所有限制x的最小值。

数据范围

给出种子,数据根据给出的生成方式生成。
1n,h,t105
1lirin
1pi107

思路

三分+贪心。
如果以特殊产生器的 x 为自变量,可以观察到普通产生器的费用是一个斜率单调不降的减函数,而特殊产生器的费用是一个一次函数。那么最终的费用一定是一个单峰函数。
我们可以三分这个x,对于每一个 x 我们可以求出每一个点最右能延伸的哪里(线段覆盖?)。贪心求出它的费用。

代码

#include<cstdlib>
#include<vector>
#include<cstring>
#include<cstdio>
using namespace std;
class SettingShield{
    public:
        struct interval{
            int l,r;
        }L[100010];
        int n,h,t;
        int seq[100010],p[100010],rightmax[100010],tag[100010];
        long long calc(int x)
        {
            for (int i=0;i<n;i++)
                p[i]=max(0,seq[i]-x);
            long long sum=1LL*x*t;
            int used=0;
            for (int i=0;i<n;i++)
            {
                used-=tag[i];
                tag[i]=0;
                p[i]=max(0,p[i]-used);
                sum+=p[i];
                used+=p[i];
                tag[rightmax[i]+1]+=p[i];
            }
            return sum;
        }
        long long getOptimalCost(int _n,int _h,int _t,vector<int> val0,vector<int> a,vector<int> b,vector<int> m)
        {
            n=_n;
            h=_h;
            t=_t;
            int dist;
            seq[0]=val0[0];
            for (int i=1;i<n;i++)
                seq[i]=(1LL*a[0]*seq[i-1]+b[0])%m[0];
            L[0].l=val0[1];
            L[0].r=val0[2];
            for (int i=1;i<h;i++)
            {
                L[i].l=min(1LL*n-1,(1LL*a[1]*L[i-1].l+b[1])%m[1]);
                dist=L[i-1].r-L[i-1].l;
                L[i].r=min(1LL*n-1,L[i].l+(1LL*a[2]*dist+b[2])%m[2]);
            }
            memset(rightmax,0xff,sizeof(rightmax));
            for (int i=0;i<h;i++)
                rightmax[L[i].l]=max(rightmax[L[i].l],L[i].r);
            for (int i=1;i<n;i++)
                if (rightmax[i-1]>=i)
                    rightmax[i]=max(rightmax[i],rightmax[i-1]);
            int l=0,r=1e7+10;
            long long ans=1LL<<60;
            for (int i=0;i<n;i++)
                if (rightmax[i]==-1)
                    l=max(l,seq[i]);
            while (l<=r)
            {
                int mid1=l+(r-l)/3;
                int mid2=l+(r-l)*2/3;
                long long tmp1=calc(mid1),tmp2=calc(mid2);
                if (tmp1>=tmp2)
                {
                    l=mid1+1;
                    ans=min(ans,tmp2);
                }
                else
                {
                    r=mid2-1;
                    ans=min(ans,tmp1);
                }
            }
            return ans;
        }
};

Round 1C

250pts

题意简述

给出n个元素的一个数组 s 。定义这个数组是加法封闭的,当且仅当s[i]+s[j]也存在于这个数组。
特殊地,只含一个元素的数组也是加法封闭的。
判断这个数组是不是加法封闭的。

数据范围

1n50 50si50

思路

一堆特判,没什么可说的。
数据范围这么小,随便做。
时间复杂度 O(n)

代码

#include<vector>
#include<string>
using namespace std;
class SumFullSet{
    public:
        string isSumFullSet(vector<int> s)
        {
            int n=s.size();
            string yes="closed";
            string no="not closed";
            if (n==1)
                return yes;
            int pos=0,neg=0,zer=0;
            int a,b;
            for (int i=0;i<n;i++)
                if (s[i]==0)
                    zer++;
                else if (s[i]>0)
                    pos++,a=s[i];
                else
                    neg++,b=s[i];
            if (pos>1||neg>1)
                return no;
            if (zer)
                if (pos==1&&neg==1&&a==b)
                    return no;
                else
                    return yes;
            else
                return no;
        }
}

500pts

题意简述

给出一个只包含ABC的字符串 s ,要求A出现间隔至少为0B出现间隔至少为 1 C出现间隔至少为2
判断是否可以将 s 重排列,使其合法,若可以,输出任意一种方案,否则输出impossible

数据范围

1len50

思路

贪心。
求出ABC当前剩余字符每种至少需要多长能放下。
每次找合法的长度最大的接到后面。
如果找不到就返回impossible
时间复杂度 O(n)

代码

#include<cstdio>
#include<string>
using namespace std;
class ThreeProgrammers{
    public:
        string validCodeHistory(string st)
        {
            string ret;
            int mx,pos,len;
            int num[3]={0},val[3],last[3]={-3,-3,-3};
            len=st.length();
            for (int i=0;i<len;i++)
                num[st[i]-'A']++;
            for (int i=0;i<3;i++)
                val[i]=(num[i]-1)*(i+1)+1;
            for (int i=0;i<len;i++)
            {
                mx=0,pos=-1;
                for (int j=0;j<3;j++)
                    if (val[j]>mx&&i-last[j]>=j+1)
                        mx=val[j],pos=j;
                if (pos==-1)
                    return string("impossible");
                last[pos]=i;
                val[pos]-=pos+1;
                ret+=pos+'A';
            }
            return ret;
        }
}

1000pts

题意简述

给出三个数 x y k
设字符串s A 的二进制表示。
L=max(1,length(s)k)
[1,x] 中,有多少个 A[1,x] 的二进制表示中,长度不超过 L 的子序列,最大的所代表的十进制数y

数据范围

1x,y1012

思路

代码


Round 2A

400pts

题意简述

给出含有 n 个数的数列a,每个数一定是 2a3b 的形式。进行 n1 操作,每次从数列中选两个数删去,添上它们的gcdlcm,那么这样最后一定会剩下一个数。
问这个数有没有可能是 x

数据范围

1n50
1ai109
1x109

思路

这题太恶心了…解释起来也好麻烦= =
进行一下模型转换,2的系数 a 写在左边,3的系数b写在右边,每个数就相当于是一条连线。
Possible的情况:

  1. 如果原数组本来就有 x ,检查其他数中a的最小值是否 xa b 的最小值是否xb。因为我们可以先对其他所有数都取gcd,最后对这个结果与 x 再取一次gcd,从而得到x
    同理,检查其他数 a b的最大值。
  2. 如果两个数各有一个系数和 x 的系数相等,并且它们同为最小或者同为最大。
    在图中表示为两条线有交叉,并且取值在同侧。
  3. 如果两个数分别有一个系数满足x,但是它们不满足同为最小或者同为最大,但是有第三个数横跨它们… 上图好了…但是只能这个方向交,不能另一个方向…因为我们可以维护两条交叉线段的同侧不变,所以这样是对的…

    其他的情况都是Impossible
    感觉说的好乱…
    时间复杂度 O(n3)

代码

#include<cstdlib>
#include<string>
#include<vector> 
#include<iostream>
using namespace std;
#define INF 0x3f3f3f3f
class LCMGCD{
    public:
        struct data{
            int a,b;
        }d[100],need;
        int n,tmp,mina,minb,maxa,maxb;
        bool ok;
        string isPossible(vector<int> s,int p)
        {
            n=s.size();
            if (n==1)
                if (s[0]==p)
                    return string("Possible");
                else
                    return string("Impossible");
            for (int i=0;i<n;i++)
            {
                tmp=s[i];
                d[i].a=0;
                while (tmp%2==0)
                    tmp/=2,d[i].a++;
                while (tmp%3==0)
                    tmp/=3,d[i].b++;
            }
            tmp=p;
            while (tmp%2==0)
                tmp/=2,need.a++;
            while (tmp%3==0)
                tmp/=3,need.b++;
            mina=minb=INF;
            for (int i=0;i<n;i++)
            {
                if (d[i].a==need.a&&d[i].b==need.b)
                {
                    for (int k=0;k<n;k++)
                        if (k!=i)
                        {
                            mina=min(mina,d[k].a);
                            minb=min(minb,d[k].b);
                            maxa=max(maxa,d[k].a);
                            maxb=max(maxb,d[k].b);
                        }
                    if (mina<=need.a&&minb<=need.b||maxa>=need.a&&maxb>=need.b)
                        return string("Possible");
                }
                for (int j=0;j<n;j++)
                {
                    if (i!=j&&d[i].a==need.a&&d[j].b==need.b)
                    {
                        if (d[i].a>d[j].a&&d[i].b<d[j].b||d[i].a<d[j].a&&d[i].b>d[j].b)
                            return string("Possible");
                        if (d[i].b>d[j].b)
                            for (int k=0;k<n;k++)
                                if (k!=i&&k!=j&&d[k].a>need.a&&d[k].b<need.b)
                                    return ("Possible");
                        if (d[i].b<d[j].b)
                            for (int k=0;k<n;k++)
                                if (k!=i&&k!=j&&d[k].a<need.a&&d[k].b>need.b)
                                    return ("Possible");
                    }
                    if (i!=j&&d[i].b==need.b&&d[j].a==need.a)
                    {
                        if (d[i].a>d[j].a&&d[i].b<d[j].b||d[i].a<d[j].a&&d[i].b>d[j].b)
                            return string("Possible");
                        if (d[i].a<d[j].a)
                            for (int k=0;k<n;k++)
                                if (k!=i&&k!=j&&d[k].a>need.a&&d[k].b<need.b)
                                    return ("Possible");
                        if (d[i].a>d[j].a)
                            for (int k=0;k<n;k++)
                                if (k!=i&&k!=j&&d[k].a<need.a&&d[k].b>need.b)
                                    return ("Possible");
                    }
                }
            }
            return ("Impossible");
        }
};

Regional Wildcard

250pts

题意简述

给出 n 个物品,每个物品有一个价值xi。对于每一个物品你可以选择分给A或分给B或谁都不给。
要求A,B两人每人至少分得一个物品,且两人分得物品的价值和相等,求任意一个方案,或无解。

数据范围

2n1000 1xi106

思路

生日悖论。
p 为从给定从符合离散均匀分布的区间 [1,d] 随机取出 n 个整数, 至少2个数字相同的概率。当 n 的取值在 d 左右时, p0.5 ;当 n 的取值在2n左右时, p 已经非常接近1了。
观察到和的值域为 [1109] ,我们可以利用生日悖论,算出 >105>2n 个和,看其中是否有相同的,出错概率已经非常小了。
为了进一步保证正确性,我们构造尽量多的解。可以取前25个数,算出它的所有子集的和,二进制位记录状态。
无解的情况只可能存在于 n 比较小的情况。
时间复杂度O(225)

代码

#include<cstdio>
#include<vector>
using namespace std;
int ff[25000010];
int final[1010];
bool flag;
int sz;
class DivideJewelry{
    public:
        void dfs(int now,int sum,int tmp,vector<int> &v)
        {
            if (flag)
                return;
            if (ff[sum]&&ff[sum]!=tmp)
            {
                flag=true;
                for (int i=0;i<25;i++)
                    if (!(bool(tmp&(1<<i))^bool(ff[sum]&(1<<i))))
                        final[i]=0;
                    else if (bool(tmp&(1<<i)))
                        final[i]=1;
                    else
                        final[i]=-1;
                return;
            }
            ff[sum]=tmp;
            if (now==sz)
                return;
            dfs(now+1,sum,tmp,v);
            dfs(now+1,sum+v[now],tmp|(1<<now),v);
        }
        vector<int> divide(vector<int> x)
        {
            sz=min(int(x.size()),25);
            dfs(0,0,0,x);
            if (!flag)
            {
                vector<int> ret;
                return ret;
            }
            else
            {
                vector<int> ret(final,final+int(x.size()));
                return ret;
            }
        }
};

500pts

题意简述

请你构造一个点数不超过 20 的无向图,这个无向图的联通子图个数为 k

数据范围

1k65535

思路

ing..

代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用 JavaScript 编写的记忆游戏(附源代码)   项目:JavaScript 记忆游戏(附源代码) 记忆检查游戏是一个使用 HTML5、CSS 和 JavaScript 开发的简单项目。这个游戏是关于测试你的短期 记忆技能。玩这个游戏 时,一系列图像会出现在一个盒子形状的区域中 。玩家必须找到两个相同的图像并单击它们以使它们消失。 如何运行游戏? 记忆游戏项目仅包含 HTML、CSS 和 JavaScript。谈到此游戏的功能,用户必须单击两个相同的图像才能使它们消失。 点击卡片或按下键盘键,通过 2 乘 2 旋转来重建鸟儿对,并发现隐藏在下面的图像! 如果翻开的牌面相同(一对),您就赢了,并且该对牌将从游戏中消失! 否则,卡片会自动翻面朝下,您需要重新尝试! 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox, 以获得更好、更优化的游戏体验。要玩游戏,首先,通过单击 memorygame-index.html 文件在浏览器中打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值