CCPC(3)(队内训练)

A. 末日时在做什么?有没有空?可以来拯救吗?

题意:略

思路:总HP最多队伍获胜

void solve()
{
	ve<int> a(6),b(6);
	int sa=0,sb=0;
	fo(i,1,5) cin >> a[i],sa+=a[i];
	fo(i,1,5) cin >> b[i],sb+=b[i];
	if(sa < sb) cout << "Red" << endl;
	else cout << "Blue"<<endl;
}

C. 不归之人与望眼欲穿的人们

题意:已知八个点是否可以构成一个立方体

思路:

八个点两两连接共有28条边

有三种长度1,√2,√3

数量之比为12/12/4

长度的平方之比为1/2/3

int l[N];
void solve()
{
	ve<int> x(9),y(9),z(9);
	
	fo(i,1,8) cin >> x[i] >> y[i] >> z[i];
	int tt = 0;
	fo(i,1,8)
		fo(j,i+1,8)
		l[++tt] = (x[j]-x[i])*(x[j]-x[i]) + (y[j]-y[i])*(y[j]-y[i]) + (z[j] - z[i])*(z[j] - z[i]);                                                                                                                                                                                                                                         
		sort(l+1,l+1+28);
	if(l[1] != 0 and l[13] == l[24] and l[13] == 2 * l[1] and l[25] == 3*l[1] and l[25] == l[28] and l[1] == l[12])
	YES;
	else NO;
}	

E. 世上最幸福的女孩

题意:操作1: n --

操作2:m++

问最少操作多少次,使得 m % n == 0

思路:

当n > m时 操作n - m 次

当n < m 时

设: i \epsilon (1,n)

则当前的m最小为 \lceil m/i \rceil*i, ans =  \lceil m/i \rceil*i - m+n-i

ans = (\lceil m/i \rceil-1)*i+n-m

ans = (\lfloor m+i-1/i \rfloor-1)*i+n-m

ans = \lfloor m-1/i \rfloor*i+n-m

此时分块维护,记录答案即可

void solve()
{
	ll n, m;
	cin >> n >> m;
	if(n > m) {cout << n - m << endl;return;}
		ll ans = 1e10;
		ll r;
		for(ll l = 1; l <= n; l =r+1)
		{
			r = min(n, (m-1)/((m-1)/l));
			ans = min(ans, (m-1)/l*l);
		}
		cout << ans + n - m << endl;
 
}

 F. 人人本着正义之名

题意:操作1:在图上添加点,并和相邻的块联通

操作2:查询这个点的联通块,输出边的数量

思路:

考虑用冰茶几维护

对于操作1,可以将坐标离散化之后丢到冰茶几

对于操作2,维护一下冰茶几内点的数量和邻边的个数,输出sz*6-2*rl

ll p[N];
ll sz[N], rl[N];
int dx[] = {-1,-1,0,0,1,1};
int dy[] = {0,1,-1,1,0,-1};
ll find(ll x){return x == p[x] ? x : p[x] = find(p[x]);}
ll tt = 0;
map<PII,ll> mp;
void solve()
{
	int sg;
	cin >> sg;
		fo(i,0,sg) p[i] = i;
	fo(i,1,sg)
	{
		ll op,x,y;
		cin >> op >> x >> y;
		if(op == 1)
		{
			PII t = {x,y};
			++tt;
			mp[t] = tt;
			sz[tt] = 1;
			rl[tt] = 0;
			fo(i,0,5)
			{
				ll nx = dx[i] + x, ny = dy[i] + y;
				PII nt = {nx,ny};
				if(!mp.count(nt)) continue;
				ll pa = find(mp[nt]);
				if(pa != tt)
				{
					p[pa] = tt;
					rl[tt] += rl[pa]+1;
					sz[tt] += sz[pa];
				}
				else rl[tt] ++;
			}
		}
		else 
		{
			PII t = {x,y};
			if(!mp.count(t)) cout << 6 << endl;
			else 
			{
				ll pa = find(mp[t]);
				cout << sz[pa]*6-rl[pa]*2<<endl;;
			}
		}
	}
 
}

H. 即便看不到未来

题意:给三个绳结,告诉六个蓝色点处,是否编号大的圆在上,回答存在多少张方案,可以使3个环拆开

思路:

共有8种操作:以下表示剪开哪个圆,0表示不操作

1|2|3|1 2|1 3|2 3|1 2 3|0

对于一对点,如果上下不同,则表示存在一个结 jie

jie == 1 剪开两个圆其中一个即可,共有6种方案

jie == 2 要么剪开中间的圆,要么两边的都剪掉,5种方案

jie == 3 剪开三个圆中的两个,4种方案

jie == 0 若1在2上,2在3上,3在1上,则剪掉其中一个即可,有7种方案

否则不需要操作,有8种方案

int p[6][6];
int ck[6][6];
void solve()
{
// 1, 2, 3, 1 2, 1 3, 2 3, 1 2 3; 0  // 8
// 0 8
// 1 6
// 2 (3,1 2, 1 2 3, 1 3, 1 2)
// 3 (1 2, 1 3, 2 3, 1 2 3 )
// 1->2 2->3 3->1 7
fo(i,0,1) fo(j,1,3)
{
	string s;
	cin >> s;
	p[j][i] = s == "true";
}
int jie = 0;
fo(i,1,3) if(p[i][0] != p[i][1]) jie ++;
if(jie == 1)
{
	cout << 6 << endl;
}
else if(jie == 2) cout << 5 << endl;
else if(jie == 3) cout << 4 << endl;
else if(jie == 0)
{
	fo(i,1,3) fo(j,i+1,3)
	{
		int u;
		if(i == 1 and j == 2) u = 1;
		if(i == 1 and j == 3) u = 2;
		if(i == 2 and j == 3) u = 3;
		if(p[u][0] == p[u][1])
		{
			if(p[u][0] == 1) ck[j][i] = 1;
			else ck[i][j] = -1;
		}
	}
	fo(i,1,3)
		fo(j,1,3)
		{
			if(i == j) continue;
			fo(k,1,3)
			{
				if(i == k or j == k) continue;
				if(ck[i][j] == ck[j][k] and ck[k][i] == ck[j][k])
				{
					cout << 7 << endl;
					return;
				}
			}
		}
		cout << 8 << endl;
    }	
}

I. 此时此刻的光辉

题意:图上有n个点,每个节点上(除了1)都有无限份价值为v的财宝,一个人可以从节点1出发到每个节点上拿,每次只能拿一份,请问t=1~T的时间内,最多能拿价值多少的财宝

思路:

从节点1开始,将到某个节点取财宝所花费的时间作为消耗,于是只需要跑一遍从1开始的最短路,最后做一个完全背包即可

int a[N];
ve<int> g[N];
int ds[N];
bool st[N];
int f[N];
void solve()
{
	int n, m, T;
	cin >> n >> m >> T;
	fo(i,2,n) cin >> a[i];
	fo(i,1,m)
	{
		int u, v;
		cin >> u >> v;// fuck ep:刚开始忘记输入,调了很久
		if(u == v) continue;
		g[u].pb(v);
		g[v].pb(u);
	}
	priority_queue<PII, ve<PII> ,greater<PII> > q;
	fo(i,1,n) ds[i] = inf;
	q.push({0,1});
	ds[1] = 0;
	while(!q.empty())
	{
		auto t = q.top();
		q.pop();
		int u = t.se, w = t.fi;
		if(st[u]) continue;
		st[u] = 1;
		//out(g[u][0]);
		for(auto v : g[u])
		{
			if(ds[v] > w + 1)
			{
				ds[v] = w + 1;
				q.push({ds[v],v});
			}
		}
	}
	fo(i,1,n)
		fo(j,ds[i]*2,T)
		f[j] = max(f[j], f[j - ds[i]*2] + a[i]);
		cout << 0 <<" ";
		fo(i,2,T) cout <<f[i] << " ";
}

J. 盼君勿忘 

题意:给一个字符串T和一份代码,问在匹配时是否存在一个字符串S使答案错误

思路:

nxt数组大于0时会出错,这个代码只会回跳到1的位置

int nxt[N];
void solve()
{
	int n;
	string t;
	cin >> n >> t;
	nxt[0] = -1;
	int i = 0, j = -1;
	while(i < n)
	{
		if(j == -1 or t[i] == t[j]) nxt[++i] = ++j;
		else j = nxt[j];
	}
	int len = nxt[n];
	bool ok = 0;
	fo(i,0,n) if(nxt[i] > 0) ok = 1;
	if(ok) cout << "Wrong Answer" << endl;
	else cout << "Correct"<<endl;
}

K. 等这场战争结束之后 

题意:

A给B x分

B给A y分

x > y, A+10分

x < y, B+10分

思路:

两人是对等的,期望为0

solve()
{
    int n;
    cin >> n;
    cout << 0 << endl;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值