問題蟲洞——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;
}