A题,数学画图题。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;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;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int 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;
int w1,h1,w2,h2;
int main()
{
w1 = read(), h1 = read(), w2 = read(), h2 = read();
cout << h1 * 2 + w1 + 2 + w2 + 2 + h2 * 2+w1-w2 << endl;
return 0;
B题:
给出n个pair,表示两个段的端点,问i与i+1段的重合部分。
这里直接max(fi-1,si-1)<min(fi,si)判断重合部分就行了。
注意判断一些重合的点。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;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;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int 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;
int n;
const int N = 1e4 + 10;
vector<pir >vec;
int main()
{
n = read();
int x, y;
up(i, 0, n)
{
x = read(); y = read();
vec.push_back(make_pair(x, y));
}
ll ans = 1;
int fi = 0;
int se = 0;
up(i, 0, n)
{
if (max(fi, se) <=min(vec[i].first, vec[i].second))
{
ans += -max(fi, se) + min(vec[i].first, vec[i].second)+1;
}
if (fi==se)ans--;
fi = vec[i].first;
se = vec[i].second;
}
cout << ans << endl;
}
C题 乱七八糟构造题
n个人围成一个群,使得相邻两个人的高度差最大值最小。
肯定是这样做最小 矮—高---矮。具体证明看cf官方题解,给出的是哈密顿的证法。(为什么数据量100?)
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;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;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int 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;
int n;
const int N = 105;
int a[N];
int res[N];
int main()
{
int pos = 0;
n = read();
up(i, 0, n)a[i] = read();
sort(a, a + n);
int mid = n / 2-1;
upd(i, 0, mid)
{
res[i] = a[pos++];
res[n - i-1] = a[pos++];
}
if (n & 1)res[mid + 1] = a[n - 1];
up(i, 0, n)cout << res[i] << " ";
return 0;
}
D题:
给出一个矩阵,给出每行分别于每列的大小关系,为是否存在一组这样的大小关系。
对于大小关系的求解,就可以用拓扑排序来解决。
从小的连一条边到大的,然后判断是否有环。
对于等于号我们缩点,用强连通或者上并查集都是可以的。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;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;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int 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;
int n, m;
const int N = 1010;
vector<int >grp[2*N];
int pr[2*N];
int val[2*N];
int in[2 * N];
int ans[2 * N];
int vis[2 * N];
set<int>st[N];
char s[N][N];
int op;
void init()
{
upd(i,1,n+m)
{
pr[i] = i;
val[i] = 1;
}
}
int find(int x)
{
return pr[x] == x ? x : pr[x] = find(pr[x]);
}
void unit(int x, int y)
{
x = find(x), y = find(y);
if (x == y)return;
if (val[x] < val[y])swap(x, y);
pr[y] = x;
val[x] += val[y];
}
int topo_sort()
{
vector<int >vec;
upd(i, 1, n + m)
{
if (in[find(i)] == 0) {
vec.push_back(find(i)); in[find(i)] = -1; ans[find(i)] = 1; vis[find(i)] = true;
}
}
while (!vec.empty())
{
int back = vec.back();
//cout << find(back) << endl;
vis[find(back)] = true;
vec.pop_back();
for (auto k : grp[find(back)])
{
//cout << find(k) << endl;
in[find(k)]--;
if (in[find(k)] == 0)vec.push_back(find(k)), in[find(k)] = -1, ans[find(k)] = ans[find(back)] + 1;
}
}
upd(i, 1, n + m)if (!vis[find(i)])return -1;
return 1;
}
int main()
{
n = read();
m = read();
init();
upd(i, 1, n)
{
cin >> s[i]+1;
bool flag = true;
upd(j,1, m)
{
if (s[i][j] == '=')
{
unit(i, j + n);
}
}
}
upd(i, 1, n)
{
upd(j, 1, m)
{
if (s[i][j] == '<')grp[find(i)].push_back(find(n+j)),in[find(n+j)]++;
else if (s[i][j] == '>')grp[find(n+j)].push_back(find(i)),in[find(i)]++;
}
}
if (topo_sort() == -1) {
cout << "No" << endl;
return 0;
}
cout << "Yes" << endl;
upd(i, 1, n)
cout << ans[find(i)] << " ";
cout << endl;
upd(i, n + 1, n+m)
cout << ans[find(i)] << " ";
return 0;
}
E题 字符串上的dp。
定义字符串的乘法 s*t为 t s[0]t s[1]t s[2] 。。。定义ans为结果串中,连续字母的最长长度。
我们可以发现,一个串的最后结果,只与上一个串有关,而上一个串对答案的贡献只有单个字母,因为被插入了最后一个字符串,所以我们分类讨论一下。
dp[i][j] 表示第i个字符串中,字符j的最长长度。(初始化为1)
然后我们就有假设i+1字符串中,自己就自带了len长度的j个连续字符
dp[i][j]=max(len,dp[i][j])
然后上一个串对于现在这个串之贡献一个,那么我们只需要考虑t的前缀和后缀,因为接在了上个串中。
如果上一个有前缀这个字母的话dp[i][j]=max(prefix+1)有后缀的话(dp[i][j]=max(suffix)
如果t是单串,那么就可以把一段字符给构造出来。而我们这里只需要考虑上一个字符串中最长的该字符就行了。即dp[i-1][j] 的值。
同样第四种情况就是,前缀和后缀一样但不是单串例如aabaa。那么接在a中间时就有
aabaa a aabaa长度更新为prefix+suffix+1.(dp转移状态不够时就多加状态,大多数直奔主题暴力构造dp即可)
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;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;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int 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;
int n;
string s;
const int N = 1e5 + 10;
int dp[N][30];
int main()
{
n = read();
upd(i, 1, n)
{
cin >> s;
int len = s.size();
up(j, 0, 26)
if (dp[i - 1][j])dp[i][j] = 1;
int r = 0, l = 0, pre = 0, suf = 0, flag = 0;
for (; r < len;l=r+1,r=l)
{
int st = s[r] - 'a';
while (r < len&&s[l] == s[r+1])r++;
dp[i][st] = max(dp[i][st], r - l + 1);
if (l == 0)pre = r;
if (r == len - 1)suf = l;
if (l == 0 && r == len - 1)flag = 1;
}
int stp = s[0] - 'a';
int sts = s[len - 1] - 'a';
if (flag&&dp[i-1][stp])dp[i][stp] = max(dp[i][stp], len*(dp[i - 1][stp] + 1) + dp[i - 1][stp]);
if (dp[i - 1][stp])dp[i][stp] = max(dp[i][stp], 1 + pre + 1);
if (dp[i - 1][sts])dp[i][sts] = max(dp[i][sts], 1 + len - suf);
if (stp == sts && dp[i - 1][sts])dp[i][sts] = max(dp[i][sts], 1 + pre + 1 + len - suf);
}
int ans = 0;
up(i, 0, 26)
ans = max(ans, dp[n][i]);
cout << ans << endl;
}
E题
题意:合并区间
很明显就是启发式合并的应用。
(裸的启发式合并)
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;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;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int 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;
int n;
const int N = 15e4 + 10;
int pr[N];
int val[N];
set<int >s[N];
int ans[N];
int pos[N];
void init()
{
upd(i, 1, n)pr[i] = i, val[i] = 1;
upd(i, 1, n)s[i].insert(i);
}
int find(int x)
{
return pr[x] == x ? x : pr[x] = find(pr[x]);
}
void unit(int x, int y)
{
x = find(x);
y = find(y);
if (x == y)return;
if (val[x] < val[y])swap(x, y);
for (auto k : s[y])
{
ans[k] += val[x];
//pos[ans[k]] = k;
s[x].insert(k);
}
s[y].clear();
pr[y] = x;
val[x] += val[y];
}
int main()
{
n = read();
int x, y;
init();
upd(i, 1, n)ans[i] = 1;
up(i, 0, n-1)
{
x = read(), y = read();
x = find(x), y = find(y);
unit(x, y);
}
upd(i, 1, n)
{
pos[ans[i]] = i;
}
upd(i, 1, n)cout << pos[i] <<" ";
return 0;
}