A题:暴力然后排序用string比较就好。
B题:找规律?可能emm
首先第i次加i,记前缀和为sum,要两个数字相等,至少sum>=两个数字的差。
我们进一步思考,当sum!=差的时候,记sum-dis=x。
如果x是偶数,x/=2,然后该数字x一定是出现在sum里面的数字,我们将x分给大的数字,那么大数字增加x,小数字减小x,就可以相等了。
当x是奇数,我们没有办法相等,继续加上i+1,i+2…直到奇偶一样。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int t;
const int N = 1e5+10;
int n = 1e5;
int a, b;
ll sum[N];
void init()
{
upd(i, 1, 1e5)
{
sum[i] = sum[i - 1] + i*1ll;
}
sort(sum, sum + n);
}
int main()
{
t = read();
while (t--)
{
init();
a = read(), b = read();
int dis = abs(b - a);
int temp = lower_bound(sum, sum + n, dis) - sum;
while ((sum[temp] % 2) != (dis % 2))temp++;
printf("%d\n", temp);
}
return 0;
}
C题暴力模拟。
开一个map记录从n到1的后缀和的差,指的是,第i个位置,蓝莓和草莓的差值。
然后再从n+1的位置开始遍历。
差值的维护:
记n+1的位置蓝莓有x个,草莓y个。
一共有蓝莓n个,草莓m个。
记需要从n个里面删掉,o个蓝莓,p个草莓。
所以 n-o-x==m-y-p,移项得到,n-m=o-p+(x-y)
维护该差值即可。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int t, n;
const int N = 2e5 + 10;
int a[N];
int sum1[N];
int sum2[N];
map<int, int>mp;
int main()
{
t = read();
while (t--) {
n = read();
upd(i, 0, 2 * n)sum1[i] = sum2[i] = 0;
mp.clear();
upd(i, 1, 2 * n)
{
a[i] = read();
if (a[i] == 1)
{
sum1[i] = sum1[i - 1] + 1;
sum2[i] = sum2[i-1];
}
else
{
sum2[i] = sum2[i - 1] + 1;
sum1[i] = sum1[i-1];
}
}
int dis = sum2[2 * n] - sum1[2 * n];
if (dis == 0)
{
printf("%d\n", 0); continue;
}
dwd(i, n, 1)
{
int temp = sum1[n] - sum1[i - 1];
int temp2 = sum2[n] - sum2[i - 1];
temp2 -= temp;
//printf("%d ", temp2);
if (!mp[temp2])
{
mp[temp2] = i;
}
}
//cout << endl;
mp[0] = n + 1;
int ans = inf;
if (mp.find(dis)!=mp.end())
{
ans = n-(*mp.find(dis)).second+1;
}
upd(i, n + 1, 2 * n)
{
int temp = sum1[i] - sum1[n];
int temp2 = sum2[i] - sum2[n];
temp2 -= temp;
temp2 = dis - temp2;
//printf("%d ", temp2);
if (mp.find(temp2) != mp.end())
{
int k = (*mp.find(temp2)).second;
ans = min(ans, i - k + 1);
}
}
//cout << endl;
printf("%d\n", ans);
}
return 0;
}
D题
暴力and并查集
首先偏序问题,肯定排序解决一维,达到降维的目的。
我们按照线段的左端点排序。考虑右端点。
我们维护一个set,储存前i-1个的右端点。当前第i个,因为左端点已经被排序,只用考虑右端点,看是否大于set的里面的右端点,有的话加入并查集。
为了使得左端小于右端点,我们将所有右端点小于左端点的全部删掉,动态维护set。(感觉好套路。。cf出了多少道这样的题目了)
最后时间复杂度,虽然看似n^2,但其实我们因为是要建立一棵树,所以并查集不可能添加n-1次以上操作,所以复杂度就是on。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 5e5 + 10;
vector<pir>vec;
set<pir> s;
int n;
int pr[N];
int height[N];
void init()
{
upd(i, 0, n)pr[i] = i, height[i] = 1;
}
int find_pr(int x)
{
return pr[x] == x ?x: pr[x] = find_pr(pr[x]);
}
bool unit(int x,int y)
{
x = find_pr(x);
y = find_pr(y);
if (x == y)return false;
if (height[x] < height[y])swap(x, y);
pr[y] = x;
height[x] += height[y];
return true;
}
int main()
{
n = read();
up(i, 0, n)
{
int x, y;
x = read(), y = read();
vec.push_back(make_pair(x, y));
}
init();
sort(vec.begin(), vec.end());
int cnt = 0;
bool flag = 0;
up(i, 0, n)
{
while (!s.empty() && s.begin()->first < vec[i].first)s.erase(s.begin());
for (auto k : s)
{
if (k.first > vec[i].second)break;
if(unit(k.second, i+1))
cnt++;
else flag = 1;
}
if (cnt > n - 1) {
flag = 1;
}
if (flag == 1)break;
s.insert(make_pair(vec[i].second,i + 1));
}
if (cnt != n - 1)flag = 1;
int sum = 0;
upd(i, 1, n)
{
if (pr[i] == i)sum++;
}
if (sum != 1)flag = 1;
if (flag)printf("NO\n");
else printf("YES\n");
return 0;
}
E题:赛后补出,感觉这个构造很漂亮啊。
构造:
针对一个点u,令lf=tot,顺序遍历他的邻接子节点,邻接子节点lf=tot++,
在反向dfs他的邻接子节点即可。
这样就能保证,子节点全部和他相交,精髓在反向遍历,这样他的子节点,一定不相交,并且相容。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 5e5 + 10;
int n;
map<int, int>lf,rt;
vector<int>vec[N];
int tot = 1;
void dfs(int u, int fa)
{
for (auto k : vec[u])
{
if (k == fa)continue;
lf[k] = tot++;
}
rt[u] = tot++;
vector<int>temp(vec[u]);
reverse(temp.begin(), temp.end());
for (auto k : temp)
{
if (k == fa)continue;
dfs(k, u);
}
}
int main()
{
n = read();
int u, v;
up(i, 0, n - 1)
{
u = read(), v = read();
vec[u].push_back(v);
vec[v].push_back(u);
}
lf[1] = tot++;
dfs(1, 0);
upd(i, 1, n)
{
printf("%d %d\n", lf[i], rt[i]);
}
return 0;
}