问题虫洞——A: Who is better?
黑洞内窥:
先求一组同余方程(CRT),然后斐波那契博弈:
思维光年:
题目 == 题解
ACcode:
#include<stdio.h>
#include<iostream>
#include<map>
#include<algorithm>
#include<cstring>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
#define MAXN 1000025
#define INF 0x3f3f3f3f//将近int类型最大数的一半,而且乘2不会爆int
#define MOD 1000000007 // MOD%4 = 3
const double pi = acos(-1.0);
const double eps = 1e-6;
ll b[MAXN], w[MAXN]; //w为除数,b是余数
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
int gcd = exgcd(b, a%b, x, y);
int t = x;
x = y;
y = t - a/b*y;
return gcd;
}
ll China(ll B[], ll W[], ll k) //W为除数,B是余数
{
ll i, a, b, c, d, x, y, t;
for(i=1; i<k; ++i)
{
a = W[i-1], b = W[i];
c = B[i] - B[i-1];
d = exgcd(a, b, x, y);
if(c%d)
return -1;
t = b/d;
x = (x*(c/d)%t+t)%t;
B[i] = B[i-1] + W[i-1]*x;
W[i] = W[i]/d*W[i-1];
}
return B[k-1];
}
ll f[75];
void init()
{
f[1] = 1;
f[2] = 2;
for(int i=3; i<=73; ++i)
f[i] = f[i-1] + f[i-2];
//cout << f[73] << '\n';
}
int main()
{
init();
ll k, ans;
scanf("%lld", &k);
for(int i=0; i<k; ++i)
scanf("%lld %lld", &w[i], &b[i]);
ans = China(b, w, k);
if(ans == -1) puts("Tankernb!");
else
{
int flag = 0;
for(int i=1; i<=73; ++i)
if(ans == f[i])
{
flag = 1;
break;
}
if(flag) puts("Lbnb!");
else puts("Zgxnb!");
}
return 0;
}
问题虫洞——B:so easy
黑洞内窥:
给你n个点m个操作,每次操作可以选择1或2
1:删除x
2:查询x, 若x已被删除,则输出x+1,若x+1也被删除,则继续查找
思维光年:
我不知道为什么,我们队也是用并查集查找,但就是T了,而且还是2001ms,,
后来,,,划重点:
使用map.count()的查找查找复杂度会更低。。。。。
(老实说,用set暴力都可以过,我枯了~~~~~~~我队wa了18发,鬼™知道换成count就过了,一看题解我们都sb了)
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
#include<string>
#include<map>
using namespace std;
map<int,int>q;
int n,m,t,x;
int tofind(int w)
{
if(!q.count(w)) return w;
return q[w] = tofind(q[w]);
}
int main()
{
scanf("%d%d",&n,&m);
while(m--)
{
scanf("%d%d",&t,&x);
if(t == 1) q[x] = tofind(x + 1);
if(t == 2) printf("%d\n",tofind(x));
}
return 0;
}
问题虫洞——E:XKC's basketball team
黑洞内窥:
给出一个序列A,和一个值m,
求比第i个数ai+m还要大的数且这个数尽可能的靠右边,设为j, 若没有则为-1。
输出n个数,每个数代表i与j之间的数.
思维光年:
栈维护+二分查找
(队友嫌线段树麻烦,,,然后就这样被她A掉了。。。)
ACcde:
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
#include<string>
#include<map>
using namespace std;
const int maxn = 1e6 + 10;
int n,m,tot;
int a[maxn],b[maxn],c[maxn],ans[maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n; ++i)
{
scanf("%d",&a[i]);
ans[i] = -1;
}
tot = 0;
for(int i = n;i >= 1; --i)
{
int p = lower_bound(c + 1,c + tot + 1,a[i] + m) - c;
if(p <= tot) ans[i] = b[p] - i - 1;
if(a[i] > c[tot]) b[++tot] = i,c[tot] = a[i];
}
for(int i = 1;i < n; ++i) printf("%d ",ans[i]);
printf("-1\n");
return 0;
}
问题虫洞——G: Center
黑洞内窥:
给你一些点,你需要定一个中心点,
使得你可以尽可能少的添加一些点,
使得添加这些点之后的点集中两两关于这个中心点对称
思维光年:
一开始看到点数只有1000的时候就想着可能是暴力求解,
但是考虑到后面遍历的点数敲不出来,,(还是自己太菜。。)
所以就没有敲,后来发现是大水题。。。。
理性的思考:
有n个点,每个点都与其它所有的点(包括它自己)连线,求所有生成的中点,
然后我们从这些中点当中找出出现次数最多的那个就行,
设它的出现次数为num,则答案就为n-num。
ACcode:
//#include<bits/stdc++.h>
//std::ios::sync_with_stdio(false);
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <math.h>
#include <vector>
#include <cstring>
#include <stdlib.h>
#include <string.h>
using namespace std;
typedef long long ll;
#define MAXN 1000005
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
const ll mod = 998244353;
#define mem(a, b) memset(a, b, sizeof(a))
pair<int, int>point[1005];
map<pair<int, int>, int>mp;
int main()
{
int n, ans = 0;
cin >> n;
for(int i=1; i<=n; ++i)
scanf("%d %d", &point[i].first, &point[i].second);
for(int i=1; i<=n; ++i)
{
for(int j=1; j<=n; ++j)
{
pair<int, int>p; //*2是为了防止小数
p.first = (point[i].first*2+point[j].first*2)/2;
p.second = (point[i].second*2+point[j].second*2)/2;
mp[p]++;
if(mp[p] > ans) ans=mp[p];
}
}
cout << n-ans << '\n';
return 0;
}