wut2018校赛网络赛部分题解

wut2018校赛网络赛部分题解



A

题意就是找出所有的单身狗,然后题目保证了单身狗居多,所以我们并不用考虑现充的影响,他们投票是无效的,意味着我们只需要考虑哪些人的得票数大于一半,就可以了,等于是开一个一维数组保存,最后遍历一遍就行。oj不支持忽略行末空格,所以需要进行处理,不然会导致PE.
代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
int a[10005];
int main()
{
 int n;
 while(~scanf("%d", &n)){
  memset(a, 0, sizeof(a));
  for(int i = 1; i <= n; i++){
   for(int j = 1; j <= n; j++){
    int temp;
    scanf("%d", &temp);
    if(temp){
     a[j]++;
    }
   }
  }
  int p = 1;
  for(int i = 1; i <= n; i++){
   if(a[i] > n / 2){
    if(p){
     printf("%d", i);
     p = 0;
    }
    else{
     printf(" %d", i);
    }
   }
  }
  printf("\n");
 }
 return 0;
}

E

这题主要是给了一些点,点与点之间有无向边,所以可以看作一个在t步之内我们到达其他所有点的种类数之和(有点绕)。那么我们从一个点到另一个点的种类数如果我们规定需要走t步,那么我们可以利用离散中的知识得出,将邻接矩阵的t次方计算出来,然后找到对应的位置,该位置对应的数字就是种类数。那么现在我们需要知道的是t步之内,所以我们需要将从1次方到t次方的矩阵相加起来,因为范围比较大所以我们可以利用快速幂的思想,来二分求解,那么问题我们就转化成了一个二分等比矩阵求和的问题。然后题目规定了起点,我们只需要将所得矩阵的第一行相加,最后输出答案的时候加一即可(因为可以在1处直接抓人)。总体复杂度应该是nlogn,集训队里面有两个神仙用dp+xjr优化过了这题,期待他们的题解。

代码:


#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
using namespace std;
const int maxn = 35;
int mod = 2018, n, m;
struct matrix
{
	int mat[maxn][maxn];
	void init()
	{
		memset(mat,0,sizeof(mat));
		for(int i = 1; i <= maxn; i++)
			mat[i][i] = 1;
	}
}a, res, res1;

matrix matrixAdd(matrix x, matrix y)
{
	matrix tmp;
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++){
			tmp.mat[i][j] = x.mat[i][j] + y.mat[i][j];
			if( tmp.mat[i][j] >= mod )
				tmp.mat[i][j] %= mod;
		}
	return tmp;
}

matrix matrixMul(matrix x, matrix y)
{
	matrix tmp;
	memset(tmp.mat,0,sizeof(tmp.mat));
	for(int i = 1; i <= n; i++){
		for(int k = 1; k <= n; k++){
			if(x.mat[i][k] == 0) continue;
			for(int j = 1; j <= n; j++){
				tmp.mat[i][j] += x.mat[i][k] * y.mat[k][j];
				if(tmp.mat[i][j] >= mod)
					tmp.mat[i][j] %= mod;
			}
		}
	}
	return tmp;
}

matrix Mul(matrix x, int k)
{
	matrix tmp;
	tmp.init();
	while(k){
		if(k & 1)
			tmp = matrixMul(tmp,x);
		x = matrixMul(x,x);
		k >>= 1;
	}
	return tmp;
}

matrix Sum(matrix x, int k)
{
	if(k == 1)
		return x;
	matrix tmp;
	tmp.init();
	tmp = matrixAdd(tmp,Mul(x,k>>1));
	tmp = matrixMul(tmp,Sum(x,k>>1));
	if(k&1)
		tmp = matrixAdd(tmp,Mul(x,k));
	return tmp;
}

void output()
{
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			if(j < n)
				printf("%d ",res1.mat[i][j]);
			else 
				printf("%d\n",res1.mat[i][j]);
		}
	}
}

int main()
{
	while(~scanf("%d %d", &n, &m)){
		int t1, t2;
		for(int i = 1; i <= m; i++){
			scanf("%d %d", &t1, &t2);
			a.mat[t1][t2] = a.mat[t2][t1] = 1;
		}
		for(int i = 1; i <= n; i++){
			a.mat[i][i] = 1;
		}
		int t;
		scanf("%d", &t);
		res = Sum(a, t);
		res1 = Mul(a, t);
		int ans = 0;
		for(int i = 1; i <= n; i++){
				ans += res.mat[1][i];
		}
		ans++;
		ans %= 2018;
		printf("%d\n", ans);
	}
	return 0;
}

F

这个是一个依赖背包裸题,实际上就是路径压缩的并查集+01背包,因为每一个有依赖的物品我们就可以直接看作同一个物品,所以,我们可以先利用并查集处理一下,然后保存的就是我们真实需要处理的物品,之后利用01背包求解即可。

代码:


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <map>
#include <iostream>
using namespace std;
int v[10005];
int c[10005];
int f[10005];
int a[10005];
int ansv[10005];
int ansc[10005];
int ans[10005];
int fa[10005];
int n, m, w;
int find(int x)
{
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}

void unio(int a,int b)
{
    int f1 = find(a);
    int f2 = find(b);
    if(f1 != f2)
        fa[f1] = f2;
}

void init()
{
    for(int i = 1; i <= n; i++)
		fa[i] = i;
}

int main()
{
	while(~scanf("%d %d %d", &n, &m, &w)){
		memset(f, 0, sizeof(f));
		memset(a, 0, sizeof(a));
		memset(ans, 0, sizeof(ans));
		memset(ansv, 0, sizeof(ansv));
		memset(ansc, 0, sizeof(ansc));
		init();
		for(int i = 1; i <= n; i++){
			scanf("%d %d", &v[i], &c[i]);
		}
		for(int i = 0; i < m; i++){
			int t, p;
			scanf("%d %d", &t, &p);
			unio(t, p);
		}
		int cnt=0;
		map<int,int> mp;
		for(int i = 1; i <= n; i++){
		    int res = find(fa[i]);
		    if(!mp.count(res)) mp[res]=++cnt;
			ansc[mp[res]] += c[i];
			ansv[mp[res]] += v[i];
		}
		for(int i = 1;i <= cnt;i++)
			for(int j = w; j >= ansv[i];j--)
				ans[j] = max(ans[j], ans[j - ansv[i]] + ansc[i]);
		printf("%d\n",ans[w]);
	}
	return 0;
}

G

这题本质上就是一个大模拟,看懂代码应该就能写,主要卡点在于位运算可逆,如果知道这一个,那么就可以根据所给代码进行反推,进行一次大模拟。群里之前有人问样例为什么是两个数字,这是因为给的n是2,所以会加密出两个数字。

代码:

#include <stdio.h> 
#include <string.h>
unsigned int data[100005];
char ans[400005];
unsigned int solve[100005];
unsigned int crypto(unsigned int x) {
    return x ^ (x >> 16);
}

int main() {
    int n;
    int iv;
    while (~scanf("%d %d", &n, &iv)) {
        memset(data, 0, sizeof(data));
        memset(ans, 0, sizeof(ans));
        memset(solve, 0, sizeof(solve));
        for (int i = 0; i < n; i++) {
            scanf("%d", &data[i]);
        }
        for (int i = n - 1; i > 0; i--) {
        	solve[i] = crypto(data[i]);
        	solve[i] ^= data[i - 1];
    	}
    	solve[0] = crypto(data[0]);
    	solve[0] ^= iv;
        for (int i = 0; i < n; i++) {
        	for (int j = 0; j < 4; j++) {
            	ans[i * 4 + j] = (solve[i] >> ((3 - j) * 8)) & 127;
        	}
    	}
        printf("%s\n", ans);
    }
    return 0;
}

I

这题是一个dfs的基础进阶题,因为规定了走的步数,所以用bfs找到最短路径的方法就被毙了。那么我们只要一直进行dfs直到t步数的时候一直return就行,如果没有答案,那也就return。但是这题数据范围比较大,所以我们需要在刚开始和dfs的时候进行剪枝,一次是t大于所有可走点,一次是奇偶性不同(剩余时间和离终点的曼哈顿距离),还有一次是剩余时间小于离终点的曼哈顿距离,理论上剪完这三个枝,就可以通过这一题。

代码:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include<queue>
#include<map>
#include<string>
#include<string.h>
#include<vector>
#include<stack>
#include<set>
using namespace std;
bool vis[100][100];
bool res;
int maze[100][100];
int sx = 0, sy = 0, ex = 0, ey = 0;
int n, m, t;
void dfs(int tx, int ty, int tm)
{
	vis[tx][ty] = true;
	if (tm == t && tx == ex && ty == ey)
	{
		res = true;
		vis[tx][ty] = false;
		return;
	}
	if (tm > t || (((t - tm)&1)^((abs(ex - tx) + abs(ey - ty))&1)) || (t-tm<abs(ex - tx) + abs(ey - ty)))
	{
		vis[tx][ty] = false;
		return;
	}
	if (tx - 1 >= 1 && !vis[tx - 1][ty] && maze[tx - 1][ty] != 1)
	{
		dfs(tx - 1, ty, tm + 1);
		if (res)
		{
			vis[tx][ty] = false;
			return;
		}
	}
	if (tx + 1 <= n && !vis[tx + 1][ty] && maze[tx + 1][ty] != 1)
	{
		dfs(tx + 1, ty, tm + 1);
		if (res)
		{
			vis[tx][ty] = false;
			return;
		}
	}
	if (ty - 1 >= 1 && !vis[tx][ty - 1] && maze[tx][ty - 1] != 1)
	{
		dfs(tx, ty - 1, tm + 1);
		if (res)
		{
			vis[tx][ty] = false;
			return;
		}
	}
	if (ty + 1 <= m && !vis[tx][ty + 1] && maze[tx][ty + 1] != 1)
	{
		dfs(tx, ty + 1, tm + 1);
		if (res)
		{
			vis[tx][ty] = false;
			return;
		}
	}
	vis[tx][ty] = false;
}

int main()
{
	while (scanf("%d%d%d", &n, &m, &t) != EOF)
	{
		if (n == 0 && m == 0 && t == 0)
			break;
		char c;
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				scanf(" %c", &c);
				if (c == 'X')
				{
					maze[i][j] = 1;
				}
				else if (c == 'S')
				{
					maze[i][j] = 2;
					sx = i;
					sy = j;
				}
				else if (c == 'D')
				{
					maze[i][j] = 3;
					ex = i;
					ey = j;
				}
				else if (c == '.')
				{
					maze[i][j] = 4;
				}
			}
		}
		if ((sx == 0 && sy == 0) || (ex == 0 && ey == 0) || (t > n*m))
		{
			printf("NO\n");
			continue;
		}
		res = false;
		memset(vis, 0, sizeof(vis));
		dfs(sx, sy, 0);
		if (res)
			printf("YES\n");
		else
			printf("NO\n");
	}

	return 0;
}

J

水题无疑,刚开始没看清楚数据范围眼瞎了,后来直接上大数板子就可以过了,这题就是一个斐波那契的问题,因为可以转化为f(n) = f(n - 1) + f(n - 2),所以就是一个斐波那契加高精的一个裸题。注意不要写成递归,如果数据再大一点就会导致爆栈。整体时间复杂度为O(n),常数主要是在实现大数上。

代码:(板子比较长)

#include <iostream>
#include <vector>
#include <string>
#include <fstream>
using namespace std;
int n, m, k;
struct Wint:vector<int>
{
    Wint(int n=0)
    {
        push_back(n);
        check();
    }
    Wint& check()
    {
        while(!empty()&&!back())pop_back();
        if(empty())return *this;
        for(int i=1; i<size(); ++i)
        {
            (*this)[i]+=(*this)[i-1]/10;
            (*this)[i-1]%=10;
        }
        while(back()>=10)
        {
            push_back(back()/10);
            (*this)[size()-2]%=10;
        }
        return *this;
    }
};
  
istream& operator>>(istream &is,Wint &n)
{
    string s;
    is>>s;
    n.clear();
    for(int i=s.size()-1; i>=0; --i)n.push_back(s[i]-'0');
    return is;
}
  
ostream& operator<<(ostream &os,const Wint &n)
{
    if(n.empty())os<<0;
    for(int i=n.size()-1; i>=0; --i)os<<n[i];
    return os;
}
  
bool operator!=(const Wint &a,const Wint &b)
{
    if(a.size()!=b.size())return 1;
    for(int i=a.size()-1; i>=0; --i)
        if(a[i]!=b[i])return 1;
    return 0;
}
  
bool operator==(const Wint &a,const Wint &b)
{
    return !(a!=b);
}
  
bool operator<(const Wint &a,const Wint &b)
{        
    if(a.size()!=b.size())return a.size()<b.size();
    for(int i=a.size()-1; i>=0; --i)
        if(a[i]!=b[i])return a[i]<b[i];
    return 0;
}
                                        
bool operator>(const Wint &a,const Wint &b)
{
    return b<a;
}
                
bool operator<=(const Wint &a,const Wint &b)
{
    return !(a>b);
}
  
bool operator>=(const Wint &a,const Wint &b)
{
    return !(a<b);
}
                   
Wint& operator+=(Wint &a,const Wint &b)
{          
    if(a.size()<b.size())a.resize(b.size());
    for(int i=0; i!=b.size(); ++i)a[i]+=b[i];
    return a.check();
}
  
Wint operator+(Wint a,const Wint &b)
{
    return a+=b;
}
  
Wint& operator-=(Wint &a,Wint b)
{
    if(a<b)swap(a,b);
    for(int i=0; i!=b.size(); a[i]-=b[i],++i)
        if(a[i]<b[i])
        {
            int j=i+1;
            while(!a[j])++j;
            while(j>i)
            {
                --a[j];
                a[--j]+=10;
            }
        }
    return a.check();
}
  
Wint operator-(Wint a,const Wint &b)
{
    return a-=b;
}
  
Wint operator*(const Wint &a,const Wint &b)
{
    Wint n;
    n.assign(a.size()+b.size()-1,0);
    for(int i=0; i!=a.size(); ++i)
        for(int j=0; j!=b.size(); ++j)
            n[i+j]+=a[i]*b[j];
    return n.check();
}
  
Wint& operator*=(Wint &a,const Wint &b)
{
    return a=a*b;
}
  
Wint divmod(Wint &a,const Wint &b)
{
    Wint ans;
    for(int t=a.size()-b.size(); a>=b; --t)
    {
        Wint d;
        d.assign(t+1,0);
        d.back()=1;
        Wint c=b*d;
        while(a>=c)
        {
            a-=c;
            ans+=d;
        }
    }
    return ans;
}
  
Wint operator/(Wint a,const Wint &b)
{
    return divmod(a,b);
}
  
Wint& operator/=(Wint &a,const Wint &b)
{
    return a=a/b;
}
  
Wint& operator%=(Wint &a,const Wint &b)
{
    divmod(a,b);
    return a;
}
  
Wint operator%(Wint a,const Wint &b)
{
    return a%=b;
}
  
Wint f[30005];
  
void init()
{
	f[0] = 0;
	f[1] = 1;
	f[2] = 2;
	for(int i = 3; i <= 5000; i++){
		f[i] = f[i - 1] + f[i - 2];
	}
}

int main()
{
	int n;
	init();
	while(cin >> n){
		cout << f[n] << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本火锅店点餐系统采用Java语言和Vue技术,框架采用SSM,搭配Mysql数据库,运行在Idea里,采用小程序模式。本火锅店点餐系统提供管理员、用户两种角色的服务。总的功能包括菜品的查询、菜品的购买、餐桌预定和订单管理。本系统可以帮助管理员更新菜品信息和管理订单信息,帮助用户实现在线的点餐方式,并可以实现餐桌预定。本系统采用成熟技术开发可以完成点餐管理的相关工作。 本系统的功能围绕用户、管理员两种权限设计。根据不同权限的不同需求设计出更符合用户要求的功能。本系统中管理员主要负责审核管理用户,发布分享新的菜品,审核用户的订餐信息和餐桌预定信息等,用户可以对需要的菜品进行购买、预定餐桌等。用户可以管理个人资料、查询菜品、在线点餐和预定餐桌、管理订单等,用户的个人资料是由管理员添加用户资料时产生,用户的订单内容由用户在购买菜品时产生,用户预定信息由用户在预定餐桌操作时产生。 本系统的功能设计为管理员、用户两部分。管理员为菜品管理、菜品分类管理、用户管理、订单管理等,用户的功能为查询菜品,在线点餐、预定餐桌、管理个人信息等。 管理员负责用户信息的删除和管理,用户的姓名和手机号都可以由管理员在此功能里看到。管理员可以对菜品的信息进行管理、审核。本功能可以实现菜品的定时更新和审核管理。本功能包括查询餐桌,也可以发布新的餐桌信息。管理员可以查询已预定的餐桌,并进行审核。管理员可以管理公告和系统的轮播图,可以安排活动。管理员可以对个人的资料进行修改和管理,管理员还可以在本功能里修改密码。管理员可以查询用户的订单,并完成菜品的安排。 当用户登录进系统后可以修改自己的资料,可以使自己信息的保持正确性。还可以修改密码。用户可以浏览所有的菜品,可以查看详细的菜品内容,也可以进行菜品的点餐。在本功能里用户可以进行点餐。用户可以浏览没有预定出去的餐桌,选择合适的餐桌可以进行预定。用户可以管理购物车里的菜品。用户可以管理自己的订单,在订单管理界面里也可以进行查询操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值