2020牛客国庆DYA6

B.Guest Student
题目:
链接:https://ac.nowcoder.com/acm/contest/7854/B
来源:牛客网

Berland State University invites people from all over the world as guest students. You can come to the capital of Berland and study with the best teachers in the country.
Berland State University works every day of the week, but classes for guest students are held on the following schedule. You know the sequence of seven integers a1, a2, …, a7 (ai = 0 or ai = 1):
a1 = 1 if and only if there are classes for guest students on Sundays;
a2 = 1 if and only if there are classes for guest students on Mondays;

a7 = 1 if and only if there are classes for guest students on Saturdays.
The classes for guest students are held in at least one day of a week.
You want to visit the capital of Berland and spend the minimum number of days in it to study k days as a guest student in Berland State University. Write a program to find the length of the shortest continuous period of days to stay in the capital to study exactly k days as a guest student.

题意:
一个礼拜七天,给出每天可以得到的数字,要么是0要么是1.先给出N,是你想要得到的1的个数,问要得到N个1最少需要多少天。

思路:
这道题我分为14天以内和14天之外来考虑的。因为大于14天的话,大于的部分都需要完整的7天才能得到。那14天之内的话,是不需要完整的7天的,因为它可以从任意的一天开始。

代码:

#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
const double N = 1e6+10;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
const inline int read(){
    int k = 0, f = 1; char c = getchar();
    for(;!isdigit(c); c = getchar())
        if(c == '-') f = -1;
    for(;isdigit(c); c = getchar())
        k = k * 10 + c - '0';
    return k * f;
}
#define ll long long
#define CL(a,b) memset(a,b,sizeof(a))
#define MAXN 100010
int a[60];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
    	int k;
	    scanf("%d",&k);
	    int num = 0;
	    int flag = 0;
	    int n = 0;
	    for(int i = 1 ; i <= 7 ; i++)
	    {
	    	scanf("%d",&a[i]);
	    	if(a[i] == 1 && flag == 0)
	    	{
	    		num = i;
	    		flag = 1;
			}
			if(a[i] == 1)
			{
				n++;
			}
		}
		for(int i = 8 ; i <= 30 ; i++)
		{
			a[i] = a[i-7];
		}
		long long int res = 0;
//		cout << k << "**" << n << endl;
		if(k <= 2*n)
		{
			res = 99999999;
			for(int i = 1 ; i <= 7 ; i++)
			{
				int z = 0;
				int z2 = k;
				for(int j = i ; j <= 30 ; j++)
				{
					z++;
					if(a[j] == 1)
					{
						z2--;
					}
					if(z2 == 0)
					{
						break;
					}
				}
				if(z < res)
				{
					res = z;
				}
			}
			printf("%lld\n",res);
		}
		else
		{
//			cout << k << " " << n << endl;
			if((k-2*n)%n==0)
			{
				res = (k-2*n)/n*7;
				k = 2*n;
			}
			else
			{
				res = (k-n)/n*7;
				k = (k-n)%n+n;
			}
//			cout << res << endl;
			int res2 = 999999;
			for(int i = 1 ; i <= 7 ; i++)
			{
				int z = 0;
				int z2 = k;
				for(int j = i ; j <= 30 ; j++)
				{
					z++;
					if(a[j] == 1)
					{
						z2--;
					}
					if(z2 == 0)
					{
						break;
					}
				}
				if(res2 >= z)
				{
					res2 = z;
				}
			}
			printf("%lld\n",res+res2);
		}
	}
	return 0;
}

F.Lazyland
题目:

链接:https://ac.nowcoder.com/acm/contest/7854/F
来源:牛客网

The kingdom of Lazyland is the home to n idlers. These idlers are incredibly lazy and create many problems to their ruler, the mighty King of Lazyland.
Today k important jobs for the kingdom (k ≤ n) should be performed. Every job should be done by one person and every person can do at most one job. The King allowed every idler to choose one job they wanted to do and the i-th idler has chosen the job ai.
Unfortunately, some jobs may not be chosen by anyone, so the King has to persuade some idlers to choose another job. The King knows that it takes bi minutes to persuade the i-th idler. He asked his minister of labour to calculate the minimum total time he needs to spend persuading the idlers to get all the jobs done. Can you help him?

题意:
有n个人,k个任务,每个人都有任务,都有劝说其完成其他任务的时间。你需要让所有的K个任务都完成,没被选的任务可以劝说其他人来完成。问完成所有任务需要最少的劝说时间是多少。

思路:
只需要记录每个任务有多少个人选择了,然后按照劝说时间从小到大排序,直接从头遍历一遍即可。

代码:

#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
const double N = 1e6+10;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
const inline int read(){
    int k = 0, f = 1; char c = getchar();
    for(;!isdigit(c); c = getchar())
        if(c == '-') f = -1;
    for(;isdigit(c); c = getchar())
        k = k * 10 + c - '0';
    return k * f;
}
#define ll long long
#define CL(a,b) memset(a,b,sizeof(a))
#define MAXN 100010
struct node
{
	long long int x;
	long long int y;
}a[MAXN];
long long int b[MAXN] = {0};
bool cmp(node x1,node x2)
{
	return x1.y < x2.y;
}
int main()
{
    long long int n , k;
    scanf("%lld %lld",&n,&k);
    long long int res = 0;
    long long int num = 0;
    for(int i = 0 ; i < n ; i++)
    {
    	scanf("%lld",&a[i].x);
    	if(b[a[i].x] == 0)
    	{
    		num++;
		}
    	b[a[i].x]++;
	}
	for(int i = 0 ; i < n ; i++)
	{
		scanf("%lld",&a[i].y);
	}
	sort(a,a+n,cmp);
//	for(int i = 0 ; i < n ; i++)
//	{
//		cout << a[i].x << "  " << a[i].y << endl;
//	}
	if(num == k)
	{
		printf("0\n");
	}
	else
	{
		num = k-num;
		for(int i = 0 ; i < n ; i++)
		{
			if(num==0)
			{
				break;
			}
			if(b[a[i].x]>1)
			{
				res = res + a[i].y;
				b[a[i].x]--;
				num--;
				continue;
			}
		}
		printf("%lld\n",res);
	}
    return 0;
}

I.Box
题目:

链接:https://ac.nowcoder.com/acm/contest/7854/I
来源:牛客网

Bella is working in a factory that produces boxes. All boxes are in a shape of rectangular parallelepipeds. A net of the corresponding parallelepiped is cut out of a flat rectangular piece of cardboard of size w ×h. This net is a polygon with sides parallel to the sides of the rectangle of the cardboard. The net is bent along several lines and is connected along the edges of the resulting parallelepiped to form a box. The net is bent only along the edges of the resulting box.

题意:
给出a,b,c,你想要得到的立方体的长宽高;给出w,h,你有的平面纸张的大小,问你是否可以剪下一张纸来拼接成你想要得到的立方体。

思路:
从他给出的11种展开图可以看出,在长宽高都是1的情况下,只有三种纸张可以满足条件,就是43,34,2*5.三种情况中找出三个展开图,在长宽高改变的情况下,对应的纸张的w和h也在改变。对应的a,b,c有六种排列,每种排列对应三种展开图,直接暴力枚举就行了。

代码:

#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
const double N = 1e6+10;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
const inline int read(){
    int k = 0, f = 1; char c = getchar();
    for(;!isdigit(c); c = getchar())
        if(c == '-') f = -1;
    for(;isdigit(c); c = getchar())
        k = k * 10 + c - '0';
    return k * f;
}
#define ll long long
#define CL(a,b) memset(a,b,sizeof(a))
#define MAXN 100010
int a[MAXN];
int main()
{
    int aa,bb,cc;
    int x , y;
    int w , h;
    cin >> a[1] >> a[2] >> a[3];
    cin >> w >> h;
    int flag = 0;
    aa = a[1];
    bb = a[2];
    cc = a[3];
    x = aa+aa+cc+cc;
    y = bb+cc+cc;
    if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	x = aa+bb+cc;
	y = aa+2*bb+cc;
	if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	x = aa+cc;
	y = aa+3*bb+cc;
	if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	aa = a[1];
    bb = a[3];
    cc = a[2];
    x = aa+aa+cc+cc;
    y = bb+cc+cc;
    if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	x = aa+bb+cc;
	y = aa+2*bb+cc;
	if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	x = aa+cc;
	y = aa+3*bb+cc;
	if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	aa = a[2];
    bb = a[1];
    cc = a[3];
    x = aa+aa+cc+cc;
    y = bb+cc+cc;
    if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	x = aa+bb+cc;
	y = aa+2*bb+cc;
	if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	x = aa+cc;
	y = aa+3*bb+cc;
	if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	aa = a[2];
    bb = a[3];
    cc = a[1];
    x = aa+aa+cc+cc;
    y = bb+cc+cc;
    if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	x = aa+bb+cc;
	y = aa+2*bb+cc;
	if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	x = aa+cc;
	y = aa+3*bb+cc;
	if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	aa = a[3];
    bb = a[1];
    cc = a[2];
    x = aa+aa+cc+cc;
    y = bb+cc+cc;
    if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	x = aa+bb+cc;
	y = aa+2*bb+cc;
	if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	x = aa+cc;
	y = aa+3*bb+cc;
	if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	aa = a[3];
    bb = a[2];
    cc = a[1];
    x = aa+aa+cc+cc;
    y = bb+cc+cc;
    if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	x = aa+bb+cc;
	y = aa+2*bb+cc;
	if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	x = aa+cc;
	y = aa+3*bb+cc;
	if(x<=w&&y<=h||x<=h&&y<=w)
    {
    	flag = 1;
	}
	if(flag == 1)
	{
		cout << "Yes" << endl;
	}
	else
	{
		cout << "No" << endl;
	}
	return 0;
}

菜的一批的我只写出了三道题。
下面是补题:
A.Fractions
题目!:

链接:https://ac.nowcoder.com/acm/contest/7854/A
来源:牛客网

You are given a positive integer n.
Find a sequence of fractions ai / bi, i = 1…k (where ai and bi are positive integers) for some k such that:

题意:
给一个n,让你构建一个序列,使序列满足题目中给出的3个条件

思路:
来自dalao的证明
https://blog.csdn.net/qq_43235540/article/details/107830058?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

在这里插入图片描述
代码:

#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
const double N = 1e6+10;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
const inline int read(){
    int k = 0, f = 1; char c = getchar();
    for(;!isdigit(c); c = getchar())
        if(c == '-') f = -1;
    for(;isdigit(c); c = getchar())
        k = k * 10 + c - '0';
    return k * f;
}
#define ll long long
#define CL(a,b) memset(a,b,sizeof(a))
#define MAXN 100010
int exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0)
	{
		x=1;
		y=0;
		return a;
	}
    int r=exgcd(b,a%b,x,y);
    int tem=x;
    x=y;
    y=tem-a/b*y;
    return r;
}
int a[MAXN];
int main()
{
    int n;
    scanf("%d",&n);
    int fac=0,nn=n,size=0;
    for(int i=2;i*i<=nn;++i)
    {
        if(nn%i==0) {
            int tem = 1;
            while (nn % i == 0) {
                nn /= i;
                tem *= i;
            }
            if (!fac)fac = tem;   //只要找到一个就行
            size++;
        }
    }
    if(nn>1)size++;
    if(size<=1)puts("NO");
    else 
	{
        puts("YES");
        puts("2");

        int a=fac,b=n/fac,c=n-1;       //此处开始套公式,ax+by=c  ,最小正整数解x=x*c%( b/gcd(a,b))
        ll x,y;                     // 一定要用long long,不然在使用exgcd的时候会wa
        int gcd=exgcd(a,b,x,y);
        int mod=b/gcd;
        x=(x*c/gcd %mod+mod)%mod;    //防止负数
        y=(c-a*x)/b;
        printf("%d %d\n%d %d\n",x,n/a,y,n/b);
    }
	return 0;
}

J.Connections
题目:

链接:https://ac.nowcoder.com/acm/contest/7854/J
来源:牛客网

Hard times are coming to Byteland. Quantum computing is becoming mainstream and Qubitland is going to occupy Byteland. The main problem is that Byteland does not have enough money for this war, so the King of Byteland Byteman 0x0B had decided to reform its road system to reduce expenses.
Byteland has n cities that are connected by m one-way roads and it is possible to get from any city to any other city using these roads. No two roads intersect outside of the cities and no other roads exist. By the way, roads are one-way because every road has a halfway barrier that may be passed in one direction only. These barriers are intended to force enemies to waste their time if they choose the wrong way.
The idea of the upcoming road reform is to abandon some roads so that exactly 2n roads remain. Advisers of the King think that it should be enough to keep the ability to get from any city to any other city. (Maybe even less is enough? They do not know for sure.) The problem is how to choose roads to abandon. Everyone in Byteland knows that you are the only one who can solve this problem.

题意:
给出所有的单向道路,现在想要每两个点之间都可达,删除一些边,使只剩下2*n条边,问可以删掉哪些道路。

思路:
来自dalao的想法,做的时候虽然与之有些许交集,但错过了。
进行两边dfs,第一遍从任意一个点pos跑,跑到不能跑为止。第二遍所有边再建反向边(重新开一个图),再对pos点dfs,这样等价于除pos点以外的所有点向pos点跑。那些被访问过的边就是必须边,剩下的就是把那些不需要的删掉,直到满足要求为止。

因为题目保证有解,那么dfs一遍一定是一棵树,每一遍将被记录下n-1条边,因此两次后最多记录下2*n-2条边。

代码:


#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
const double N = 1e6+10;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
const inline int read(){
    int k = 0, f = 1; char c = getchar();
    for(;!isdigit(c); c = getchar())
        if(c == '-') f = -1;
    for(;isdigit(c); c = getchar())
        k = k * 10 + c - '0';
    return k * f;
}
#define ll long long
#define CL(a,b) memset(a,b,sizeof(a))
#define MAXN 100010

struct jj
{
    int u,v,next;
}w[100000],w1[100000];
int h[50000],h1[50000],visw[100000],vis[50000],numw,numw1;
void insert(int u,int v)
{
    w[numw].u=u;
    w[numw].v=v;
    w[numw].next=h[u];
    h[u]=numw++;
    w1[numw1].v=u;
    w1[numw1].next=h1[v];
    h1[v]=numw1++;
}
void dfs(int t)
{
    int i;
    for(i=h[t];i!=-1;i=w[i].next)
    {
        if(vis[w[i].v]==0)
        {
            vis[w[i].v]=1;
            visw[i]=1;
            dfs(w[i].v);
        }
    }
}
void dfs1(int t)
{
    int i;
    for(i=h1[t];i!=-1;i=w1[i].next)
    {
        if(vis[w1[i].v]==0)
        {
            vis[w1[i].v]=1;
            visw[i]=1;
            dfs1(w1[i].v);
        }
    }
}
int main()
{
    int t,x,y,i,i1,num,n,m;
	scanf("%d",&t);
	while(t--)
    {
        memset(h,-1,sizeof(h));
        memset(h1,-1,sizeof(h1));
        memset(visw,0,sizeof(visw));    //visw数组是记录哪些边被访问过,哪些没有被访问过
        numw=0;
        numw1=0;
        scanf("%d %d",&n,&m);
        for(i=1;m>=i;i++)
        {
            scanf("%d %d",&x,&y);
            insert(x-1,y-1);
        }
        memset(vis,0,sizeof(vis));
        dfs(0);
        memset(vis,0,sizeof(vis));
        dfs1(0);
        num=m;
        for(i=0;m>i&&num!=2*n;i++)
        {
            if(visw[i]==0)
            {
                num--;
                printf("%d %d\n",w[i].u+1,w[i].v+1);
            }
        }
    }
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值