暑假补课 浙江理工大学7月月赛 补题ing

开局先看看题,感觉就是能A的就6题,其他几题看都看不懂,卡在了几个弱智的点上

A题给你n个数,固定顺序,要求从中间分为两部分,要求两部分体重和差距最小

还好有序,不然就是dp了

#include
using namespace std;
const int N=1e5+7;
int a[N];
int main()
{
    int n;
    cin>>n;
    int sum=0;
    for(int i=1;i<=n;i++)
        {cin>>a[i];
        sum+=a[i];}
        int sum1=sum;
    sum/=2;
    int num1=0,num2=0;
    for(int i=1;i<=n;i++)
    {
        num1+=a[i];
        num2+=a[i];
        if(num1>=sum)
        {
            num2-=a[i];
            break;
        }
    }
    cout<

我的写法很有点蠢,其实可以很好的优化一下的

B.统计t1,t2之间的约数个数

#include
using namespace std;
int main()
{
    int t1,t2;cin>>t1>>t2;
    if(t1>=t2) swap(t1,t2);
    long long ans=0;
    for(int i=1;i<=t2;i++)
    {
        int num1=t1/i;
        int num2=t2/i;
        if(t1%i!=0)num1++;
            ans+=num2-num1+1;
    }
    cout<

C.

有F个好朋友正在做物理作业,每个朋友要做M个实验,他们的实验数据会保存在data数组里面 前M个数据是第一个人的,接下来M个数据是第二个人的,以此类推
一个序列的中位数是这个序列排序之后位于中间的那个数,如果序列的长度是偶数,中间两个数中较小的那个数就是中位数 {10,40,30,20}的中位数是20
根据实验手册的答案,实验数据的结果应该是goal,他们想要改变一些实验数据使得data数组的中位数为goal
返回以下两个数 
1: 最少需要多少个人进行数据造假 
2: 在最少人作假的前提下,最少需要改变多少个实验数据

 

输入

第一行输入三个正整数F,M,goal, 1 <= FM <=1000, 0 <= goal <= 99 接下来一行输入FM个数表示data数组, 每个元素的范围0 <= data[i] <= 99

 

按题意模拟贪心下即可

 

 

#include
using namespace std;
struct node
{
    int id;
    vectorhave;
    int du;
    bool operator<(node &o)
    {
        return du>o.du;
    }
}a[1007];
int main()
{
   int n,m,goal;
   int f=0;
   cin>>n>>m>>goal;
   int data[1007];
   for(int i=0;i>data[i];
   for(int i=0;imid)
            {
                if(a[i].have[j]goal)
                a[i].du++;
            }
        }
    }
    int ned;
    if(goal>mid)
    {
        ned=lower_bound(data,data+n*m,goal)-data;
        //cout<goal)
            {
                ned=i-1;
                ned=zhong-ned;
                break;
            }
 
        }
    }
 
    int ans2=ned;
    sort(a,a+n);
    //for(int i=0;i=a[i].du)
            ned-=a[i].du;
            else
            {
                ans++;break;
            }
        ans++;
        if(ned<=0)
            break;
    }
    cout<

D.

一个平面直角坐标系上,有一只猫站在原点(0,0), 
对于除原点外的每一个(x,y)(|x| <= N , |y| <= N)的位置上都有一只老鼠

假如猫选择了某个方向出击,那么它可以吃掉这个方向上的所有碰见的老鼠

现在问你有多少个方向上恰好有C只老鼠

 

xoy坐标平面分为八部分,找到y大于x的情况多少种  *8即可

 

 

 

应要求详细解释一下

就是这条线上有多少个老鼠,根据平面直角坐标系对称性可知,第1,2,3,4象限的情况是一样的,所以说只用考虑第一象限,以1234  3这组数据为例子,你会发现当x,y中任意一个大于1234/3(即411)时,是不可能出现三只老鼠情况的(不要和我杠x,y不互质有可能出现,这里讨论的是x,y互质,且这是最小的一组的情况)所以x,y初步确定范围,又发现只要x,y中一个数在1234/3  到1234/4+1(309)中,且x,y互质的话,是满足条件的,x,y在第一象限内是关于y=x对称的,也就是说只用考虑y>x的情况再乘2就可以,然后就得到y区间为309到411,x小于y且x,y互质,这就是欧拉函数(返回比该数小的并且互质的数的个数)返回值了,

 

 

 

 

下面有两个小问题,第一个是特殊情况其实是被一般情况包含了的,所以if那句注释掉,第二个是ans会爆int,过的代码就不贴了,自己改改就可以AC了

#include
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll phi(ll n)   ///求欧拉函数值 返回值为多少个与n互质的数
{
    int ans=n,temp=n;
    for(int i=2;i*i<=temp;i++)
    {
        if(temp%i==0)
        {
            ans-=ans/i;
            while(temp%i== 0) temp/=i;
        }
    }
    if(temp>1) ans-=ans/temp;
    return ans;
}
int main()
{
    int ans=0;
   int len;int num;
   cin>>len>>num;
   if(len%num==0){cout<<8<

F.有n位OI选手准备展开一些一对一的单挑比赛.n是个偶数,每位选手都有自己的主场

517编程委员会决定给n位选手组织一次夏令营,规则如下
1: 夏令营恰好有两轮比赛
2: 每位选手在每轮比赛中恰好参加一次
3: 每两位选手最多在比赛中相遇一次
4: 每位选手都在主客场恰好打了一次比赛

现在你作为517编程委员会的筹划人员,需要计算一下一共有多少种不同的比赛安排方案
由于方案数可能比较大,输出方案数对1e9+7取模的值

 

 

8个人,先选第一场主场的  c84,再乘以4个找客场对手人的全排列   A44,  这样第一场次情况完毕并且已经确定再乘以第二场4个队的错排f(4),就是第二场每个主场的人挑选对手的情况

错排的计算  请自行百度,目前无代码(懒得敲)

#include
using namespace std;
long long a[300005];
const int mod=1e9+7;
int build(int n)
{
    a[1]=0;
    a[2]=1;
    for(int i=3;i<=n/2;i++)
    {
        a[i]=(i-1)*(a[i-1]+a[i-2])%mod;
    }
    return 0;
}
int main()
{
    int n;
    scanf("%d",&n);
    build(n);
    long long s=1;
    for(int i=n/2+1;i<=n;i++)
    {
        s=s*i%mod;
    }
    s=s*a[n/2]%mod;
    printf("%lld\n",s);
    return 0;
}

 

I.最小生成树

裸板子题 ,直接ctrl c+ctrl v即可   在此送上板子一份

克鲁斯科尔算法
时间复杂度(elog2e+elog2n+n^2+n)
#include
using namespace std;
const int N=2e5+7;
int f[N];///f数组存放每个点连的头  一般定义点的值最小的为头
struct node///该结构体用于存边
{
    int begin,end;///起点和终点
    int quan;///存放边的权值
}a[N];
int find(int x)///找头
{
    if(f[x]!=x)
    f[x]=find(f[x]);///递归找头,修改路径,方便下次查找,注意可能爆栈
        return f[x];
}
void join(int x,int y)
{
    int fx=find(x);///找头
    int fy=find(y);
    if(fx>n;
    cout<<"请输入边的数量:"<>m;
    cout<<"请依次输入边的起点终点和权值:"<>a[i].begin>>a[i].end>>a[i].quan;
    sort(a+1,a+m+1,cmp);
    int t=0;///记录边数,当边数为n-1条时,图联通
    for(int i=1;i<=n;i++) f[i]=i;
    int ans=0;///存放最小生成树的权值总和
    for(int i=1;i<=m;i++)
    if(find(a[i].begin)!=find(a[i].end))
    {
        join(a[i].begin,a[i].end);
        ans+=a[i].quan;
        t++;
        if(t==n-1)
            break;
    }
    if(t==n-1)
        cout<<"最小生成树的权值和为:"<

G.

魔法女孩为了保卫地球而对抗女巫对这个世界的破坏.

你是魔法女孩的一员, 你找到了一张古代地图, 上面写有魔法秘籍的练法,可惜这张图有部分缺失了.

地图是一个W宽,H高的网格,行的编号为0到H-1,列的编号为0到W-1,每个网格应该包含一个1到9的数字
现在有些网格损坏了,数字不见了(用'.'表示),现在问你一共有多少种填充网格的方法满足如下条件
1: 对于所有的r 与 c (0 <= r <=  H - n, 0 <= c < W), F[r][c]+F[r+1][c] +...+F[r+n-1][c]必须是一个奇数

2: 对于所有的r 与 c (0 <= r <=  H, 0 <= c <= W-m), F[r][c]+F[r][c+1] +...+F[r][c+m-1]必须是一个奇数

输出填数字的方案数对1e9+7取模.

 

输出   n,m,r,c

输出   情况数

 

虽然我读玩都不知道它想干嘛,不过我大哥A了这题,虽然他不给我代码,但是我可以偷偷登他账号嫖他代码。

 

 

解题思路懂了,对于任意的i,j点  他与     i+r,j     i,j+c     点是同奇偶的情况,也就是说  根据已有的点,我们可以确定某些点的奇偶情况,然后对于剩余的点,我们只需确定  r*c  的小矩形里面奇偶情况即可,因为这里面的点不受其他点的限制,而且确定了这个小矩形里面点的奇偶情况,整张图的情况就确定了,每行每列的和都为奇数,然后就有好多好多种情况,大佬说这边用状压dp解决就可以了,不说了  我去学状压了,

你可能感兴趣的:(算法,比赛)