A CodeForces1117C
如果之前不知道风向就不方便作决定,二分刚好就能写。
一道我都能想出来的题
#include
#include
#include
#include
using namespace std;
#define ll long long
int main()
{
//freopen("in.txt", "r", stdin);
ll x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
int n;
scanf("%d", &n);
string wind;
cin >> wind;
ll u = 0, r = 0,d = 0, l = 0;
for (int i = 0; i < n; i++) {
if (wind[i] == 'U')u++;
else if (wind[i] == 'R')r++;
else if (wind[i] == 'L')l++;
else d++;
}
ll left = 1; ll right = 2e14;
ll ans = -1;
while (left <= right) {
ll mid = (left + right) >> 1;
ll c = mid / n;
ll k = mid % n;
ll endx, endy;
endx = x1 + (r - l)*c;
for (int i = 0; i < k; i++) {
if (wind[i] == 'R')endx++;
else if (wind[i] == 'L')endx--;
}
endy = y1 + (u - d)*c;
for (int i = 0; i < k; i++) {
if (wind[i] == 'U')endy++;
else if (wind[i] == 'D')endy--;
}
ll judge = abs(endx - x2) + abs(endy - y2);
if (judge <= mid) {
right = mid - 1;
ans = mid;
}
else left = mid + 1;
}
cout << ans;
}
B codeforces 920E
给出补图,求联通分量个数和大小
以为是并查集+补图求完全K分图,but不是
老老实实的存边搜索,用set存查找删除会更高效。
要从set里面删元素的话先存在一个temp里面再删就好了,直观一些
#include
#include
#include
#include
#include
using namespace std;
set<int> node[200005];
set<int> total;
int tempans = 0;
void dfs(int x) {
tempans++;
set<int>::iterator it;
set<int> temp;
for (it = total.begin(); it != total.end();it++) {
if (node[x].find(*it) == node[x].end()) {
temp.insert(*it);
}
}
for (it = temp.begin(); it != temp.end(); it++)total.erase(*it);
for (it = temp.begin(); it != temp.end(); it++)dfs(*it);
}
int main()
{
//freopen("in.txt", "r", stdin);
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
total.insert(i);
}
while (m--) {
int u, v;
scanf("%d%d", &u, &v);
node[u].insert(v);
node[v].insert(u);
}
vector<int> vec;
for (int i = 1; i <= n; i++) {
if (total.find(i) == total.end())continue;
total.erase(i);
tempans = 0;
dfs(i);
vec.push_back(tempans);
}
sort(vec.begin(), vec.end());
printf("%d\n", vec.size());
for (int i = 0; i < vec.size(); i++) {
printf("%d ", vec[i]);
}
}
C codeforces 920F
应该是很经典的一道线段树?
单点修改,区间求和。优化是维护一个区间的最值,如果是2,那么求的因子也是2,就不用继续往下修改。
先打表求出因子的个数。
#include
#include
#include
#include
using namespace std;
#define ll long long
const int maxn = 3e5+5;
int add[maxn << 2];
ll sum[maxn << 2];
ll maxx[maxn << 2];
int num[1000005];
void init() {//非常耿直的打表
for (int i = 1; i < 1000005; i++) {
for (int j = i; j < 1000005; j += i)num[j]++;
}
}
void pushup(int rt)
{
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
maxx[rt] = max(maxx[rt << 1], maxx[rt << 1 | 1]);
}
void build(int l, int r, int rt)
{
if (l == r)
{
scanf("%lld", &sum[rt]);
maxx[rt] = sum[rt];
return;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushup(rt);
}
void update(int L, int R, int l, int r, int rt)
{
if (maxx[rt] <= 2)return;
if (l==r)
{
sum[rt] = num[sum[rt]];
maxx[rt] = sum[rt];
return;
}
//pushdown(rt, r - l + 1);
int m = (l + r) >> 1;
if (L <= m)update(L, R, l, m, rt << 1);
if (m < R) update(L, R, m + 1, r, rt << 1 | 1);
pushup(rt);
}
ll query(int L, int R, int l, int r, int rt)
{
if (L <= l && r <= R)
return sum[rt];
int m = (l + r) >> 1;
ll ret = 0;
if (L <= m) ret += query(L, R, l, m, rt << 1);
if (m < R) ret += query(L, R, m + 1, r, rt << 1 | 1);
return ret;
}
int main()
{
//freopen("in.txt", "r", stdin);
init();
int n, m;
scanf("%d%d", &n, &m);
build(1, n, 1);
while (m--) {
int op;
scanf("%d", &op);
if (op == 1) {//replace
int l, r;
scanf("%d%d", &l, &r);
update(l, r, 1, n, 1);
}
else {//sum
int l, r;
scanf("%d%d", &l, &r);
printf("%lld\n", query(l, r, 1, n, 1));
}
}
}
D codeforces919D
想到是dp了,但是写的太复杂了。应该是先到终点然后再回溯dp的(也许都是这种套路?)dfs:判环用in数组,剪枝用vis数组,从终点开始更新之前的点。因为是从后往前更新的所以不需要特意求出起点。没剪枝所以就T了Q-Q
这种方法貌似也容易超时??还有一种是用拓扑排序。
无向图用并查集判环,有向图用拓扑排序判环
其实就是一个BFS,然后用in保存入度数,访问到一次入度就减一,不是0就说明还有到它的点,就再加到queue中。是从起点开始一步步更新之后的点。
?我就是想不到Q-Q太菜了
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 3e5 + 5;
int in[maxn];
vector<int> g[maxn];
int n, m;
char s[maxn];
queue<int> que;
int dp[maxn][26];
void bfs() {
for (int i = 1; i <= n; i++) {
if (!in[i]) {
que.push(i);
dp[i][s[i] - 'a']++;
}
}
int cnt = 0;
while (que.size()) {
int u = que.front();
que.pop();
cnt++;
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
in[v]--;
if (in[v]) {
for (int i = 0; i < 26; i++) {
if (s[v] == i + 'a')
dp[v][i] = max(dp[v][i], dp[u][i] + 1);
else
dp[v][i] = max(dp[u][i], dp[v][i]);
}
}
else {
que.push(v);
for (int i = 0; i < 26; i++) {
if (s[v] == i + 'a')
dp[v][i] = max(dp[v][i], dp[u][i] + 1);
else
dp[v][i] = max(dp[u][i], dp[v][i]);
}
}
}
}
if (cnt == n) {
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < 26; j++) {
ans = max(ans, dp[i][j]);
}
}
printf("%d", ans);
}
else {
printf("-1\n");
}
}
int main()
{
//freopen("in.txt", "r", stdin);
memset(in, 0, sizeof(in));
memset(dp, 0, sizeof(dp));
scanf("%d%d", &n, &m);
scanf("%s", s + 1);
while (m--) {
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
in[v]++;
}
bfs();
}
E codeforces917A
看了一下,觉得是dp,是我不会写的dp
…
看了题解,居然是思维题,然后果然是贪心思维题。(其实贪心就是思维吧??)是我不会写的贪心。
是我太菜了
F codeforces917B
不会写…看了题解才知道是dp+博弈,必胜点和必败点
dp[i][j][v]表示先手在i点,后手在j点,上一轮权值为v的胜负情况。
才接触到博弈题=-=是我太菜了
#include
#include
#include
#include
using namespace std;
const int maxn = 105;
const int maxm = 1e5 + 5;
struct edge {
int v, w;
int next;
}e[maxm];
int total = 0;
int head[maxn];
void addedge(int u, int v, int w) {
total++;
e[total].v = v;
e[total].w = w;
e[total].next = head[u];
head[u] = total;
}
int dp[maxn][maxn][30];
//1是必胜 2是必败
int dfs(int i, int j, int prew) {
if (dp[i][j][prew])return dp[i][j][prew];
for (int k = head[i]; k; k = e[k].next) {
int v = e[k].v;
int w = e[k].w;
if (w >= prew) {
if (dfs(j, v, w) == 2) {//如果下一步是必败的情况
return dp[i][j][w] = 1;//这一步一定是必胜的
}
}
}
return dp[i][j][prew] = 2;
}
int main()
{
freopen("in.txt", "r", stdin);
memset(dp, 0, sizeof(dp));
int n, m;
scanf("%d%d", &n, &m);
while (m--) {
int u, v;
char value;
scanf("%d %d %c", &u, &v, &value);
addedge(u, v, value - 'a');
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (dfs(i, j, 0) == 1)printf("A");
else printf("B");
}
printf("\n");
}
}