題目鏈接:https://codeforces.com/contest/1252
水題
#include<bits/stdc++.h>
using namespace std;
const int mx = 1e5+5;
struct node{
int id,x;
bool operator<(const node &a)const{
return x>a.x;
}
}a[mx];
int ans[mx];
int main(){
int n;
scanf("%d",&n);
for(int i = 1; i <= n; i++)
scanf("%d",&a[i].x),a[i].id = i;
sort(a+1,a+n+1);
for(int i = 1; i <= n; i++)
ans[a[i].id] = i;
for(int i = 1; i <= n; i++)
printf("%d%c",ans[i],i==n?'\n':' ');
return 0;
}
樹形DP
0:以u節點爲根節點的樹,並且u最後不能是鏈的端點的個數
1:u的子樹且u不是鏈的端點的個數
2:u可以做鏈的端點,後面也可以改變不做鏈端點的方案數
#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mid (l+r>>1)
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int mx = 1e5 + 10;
int n,m;
ll dp[mx][3];
vector <int> g[mx];
void dfs_dp(int u,int f) {
ll pre_1 = 1;
ll all_cnt = 1;
for (int i=0;i<g[u].size();i++) {
int v = g[u][i];
if (v == f) continue;
dfs_dp(v,u);
dp[u][1] = dp[u][1] * (dp[v][1] + dp[v][2]) % mod; // u不是端點
dp[u][1] = (dp[u][1] + (dp[v][0] + dp[v][2]) * (dp[u][0] + dp[u][2])) % mod;
// 是端點但要和其他點連接不讓u是鏈的端點
dp[u][0] = dp[u][0] * (dp[v][1] + dp[v][2]) % mod; //不做連接點
dp[u][0] = (dp[u][0] + dp[u][2] * dp[v][2]) % mod;
ll mul = (all_cnt - pre_1 + mod) % mod;
dp[u][0] = (dp[u][0] + (dp[v][0] + dp[v][2])*mul) % mod;
// 是端點,但後面u可以作爲端點也可以不做
dp[u][2] = (dp[u][2] * dp[v][1] + (dp[v][0] + dp[v][2]) * pre_1) %mod;
pre_1 = pre_1 * dp[v][1] % mod;
all_cnt = all_cnt * (dp[v][1] + dp[v][2]) %mod;
}
dp[u][2] = (dp[u][2] + pre_1) % mod;
}
int main(){
scanf("%d",&n);
int u1,v1;
for (int i=1;i<n;i++){
scanf("%d%d",&u1,&v1);
g[u1].push_back(v1);
g[v1].push_back(u1);
}
dfs_dp(1,0);
ll ans = dp[1][1] + dp[1][2];
printf("%lld\n",ans%mod);
return 0;
}
從行上來看和0/1表示奇偶來看,行要麼是一樣的要麼是互斥的。要想連通一定是在連續的一樣的行中。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int n, m;
int R[maxn], C[maxn];
int lr[maxn], rr[maxn];
int lc[maxn], rc[maxn];
void solve() {
for(int i=2; i<=n; i++) {
lr[i] = (R[i]%2 == R[i-1]%2) ? lr[i-1] : i;
lc[i] = (C[i]%2 == C[i-1]%2) ? lc[i-1] : i;
}
for(int i=n-1; i>=1; i--) {
rr[i] = (R[i]%2 == R[i+1]%2) ? rr[i+1] : i;
rc[i] = (C[i]%2 == C[i+1]%2) ? rc[i+1] : i;
}
}
bool ok(int x1, int y1, int x2, int y2) {
if((R[x1]+C[y1]) %2 == 1) return false;
if((R[x2]+C[y2]) %2 == 1) return false;
if(x2<lr[x1] || rr[x1]<x2) return false;
if(y2<lc[y1] || rc[y1]<y2) return false;
return true;
}
int main() {
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) {
scanf("%d", &R[i]);
lr[i] = rr[i] = i;
}
for(int i=1; i<=n; i++) {
scanf("%d", &C[i]);
lc[i] = rc[i] = i;
}
solve();
while(m--) {
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
if(ok(x1, y1, x2, y2)) printf("YES\n");
else printf("NO\n");
}
}
待做
從後往前推每個位置的可以有解的取值範圍,然後最後在從前往後去最小
#include <bits/stdc++.h>
using namespace std;
const int mx = 1e5 + 10;
int n,L,R,K;
int a[mx];
int up[mx],down[mx];
int main() {
scanf("%d%d%d%d",&n,&L,&R,&K);
for (int i=1;i<=n;i++) {
scanf("%d",a+i);
}
up[n] = R, down[n] = L;
for (int i=n-1;i>=1;i--) {
if (a[i]==a[i+1])
up[i] = up[i+1],down[i] = down[i+1];
else if (a[i] > a[i+1]) {
up[i] = min(R,up[i+1]+K);
down[i] = down[i+1] + 1;
} else {
up[i] = up[i+1] - 1;
down[i] = max(L,down[i+1]-K);
}
if (up[i] < L || down[i] > R || down[i] > up[i])
return 0*puts("-1");
}
int now = down[1];
printf("%d ",now);
for (int i=2;i<=n;i++) {
if (a[i] > a[i-1]) {
now = max(down[i],now+1);
} else if (a[i] < a[i-1]){
now = max(down[i],now-K);
}
printf("%d ",now);
}
return 0;
}
Hash+求重心,主要注意的是一個樹最多有兩個重心
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mx = 4e3 + 10;
const ull base = 1e4 + 7;
int n;
vector <int> g[mx],root;
int siz[mx],son[mx];
int msiz,first_rt;
void dfs_siz(int u,int f) {
siz[u] = 1;
for (int v:g[u]) {
if (v == f) continue;
dfs_siz(v,u);
siz[u] += siz[v];
}
}
void get_root(int u,int f,int tot) {
int fsiz = tot - siz[u];
for (int v: g[u]) if (f != v) {
fsiz = max(fsiz,siz[v]);
get_root(v,u,tot);
}
if (msiz > fsiz) {
root.clear();
root.push_back(u);
msiz = fsiz;
} else if (msiz == fsiz)
root.push_back(u);
}
ull dfs_hash(int u,int f,int d) {
ull ans = 0;
for (int v:g[u]) {
if (v == f || v == first_rt) continue;
ans += dfs_hash(v,u,d+1);
}
return ans * base + d;
}
bool check(ull hash_val) {
for (int tr : root) {
if (hash_val == dfs_hash(tr,0,1))
return 1;
}
return 0;
}
int main() {
scanf("%d",&n);
int u,v;
for (int i=1;i<n;i++) {
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
first_rt = -1;
msiz = 1e7;
dfs_siz(1,0);
get_root(1,0,siz[1]);
first_rt = root[0];
int ans = 0;
ull hash_val;
bool ok = 0;
for (int i : g[first_rt]){
msiz = 1e7;
root.clear();
dfs_siz(i,first_rt);
get_root(i,first_rt,siz[i]);
if (!ok) {
hash_val = dfs_hash(root[0],0,1);
ok = 1;
}
else if (!check(hash_val)) return 0*puts("-1");
ans++;
}
printf("%d\n",ans);
return 0;
}
只需要考慮比第一個數大還是小,如果是大的話,第一個人的名次肯定越來越小,一個值比第一個人大,肯定會影響整個後綴,所以就是後綴區間更新維護一下區間最值就好了
#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mid (l+r>>1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mx = 1e5 + 10;
int a[mx];
vector <int> g[mx];
int n,m,q,self_val,rk;
int Min[mx<<2],lazy[mx<<2];
void build(int l,int r,int rt) {
if (l == r) {
Min[rt] = rk - (int)g[l].size() - 1;
return ;
}
build(lson);
build(rson);
Min[rt] = min(Min[rt<<1],Min[rt<<1|1]);
}
void push_up(int rt) {
if (lazy[rt]) {
Min[rt<<1] += lazy[rt];
Min[rt<<1|1] += lazy[rt];
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
lazy[rt] = 0;
}
}
void update(int l,int r,int rt,int M,int v) {
if (M > r) return ;
if (M <= l) {
Min[rt] += v;
lazy[rt] += v;
return ;
}
push_up(rt);
if (M <= mid) update(lson,M,v);
update(rson,M,v);
Min[rt] = min(Min[rt<<1],Min[rt<<1|1]);
}
int main() {
scanf("%d%d%d",&n,&m,&q);
scanf("%d",&self_val);
rk = n;
for (int i=2;i<=n;i++) {
scanf("%d",a+i);
if (a[i] > self_val) rk--;
}
for (int i=1;i<=m;i++) {
int c,u;
scanf("%d",&c);
for (int j=0;j<c;j++) {
scanf("%d",&u);
g[i].push_back(u);
}
}
build(1,m,1);
for (int i=1;i<m;i++) {
for (int j : g[i]) if (j > self_val)
update(1,m,1,i+1,-1);
}
int c,id,v;
while (q--) {
scanf("%d%d%d",&c,&id,&v);id--;
if (g[c][id] > self_val && v < self_val)
update(1,m,1,c+1,1);
if (g[c][id] < self_val && v > self_val)
update(1,m,1,c+1,-1);
g[c][id] = v;
puts(Min[1]>=0?"1":"0");
}
return 0;
}
排個序,枚舉長度最小值的情況去貪心寬的最大值
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e5+5;
set<ll>st;
struct point{
ll x,y;
bool operator<(const point &a)const{
return x>a.x;
}
}a[mx];
int main(){
int n;
scanf("%d",&n);
ll ans = 0;
for(int i = 1; i <= n; i++){
scanf("%lld%lld",&a[i].x,&a[i].y);
if(a[i].x>a[i].y)
swap(a[i].x,a[i].y);
ans = max(a[i].x*a[i].y,ans);
}
sort(a+1,a+n+1);
for(int i = 1; i <= n; i++){
ll x = a[i].x;
auto it = st.lower_bound(a[i].y);
if(it!=st.end())
ans = max(ans,2*a[i].x*a[i].y);
else if(it!=st.begin()){
it--;
ans = max(ans,2*a[i].x*(*it));
}
st.insert(a[i].y);
}
if(ans&1)
printf("%lld.5\n",ans/2);
else
printf("%lld.0\n",ans/2);
return 0;
}
待做
隊友做的
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf = 1e15;
const int mx = 1e5+10;
const int N = 105;
ll dp[N][N][N][2];
char str[mx];
vector<int>s;
int n,m,a,b,c;
ll calc(int n,int i,int j,int k){
if(dp[n][i][j][k]<0) return -1;
if(i>m) return 1ll*c*j+1ll*m*a+b*dp[n][i][j][k];
ll sum = 1ll*c*j+1ll*i*a;
ll x = dp[n][i][j][k];
ll y = min(1ll*(m-i)/2,dp[n][i][j][k]);
ll ans = max(dp[n][i][j][k]*b+sum,(dp[n][i][j][k]-y)*b+sum+1ll*y*2*a);
if(y*2+i<m&&y<dp[n][i][j][k])
ans = max(ans,(dp[n][i][j][k]-y-1)*b+sum+1ll*y*2*a+a);
return ans;
}
int main(){
// freopen("in", "r", stdin);
scanf("%d%d%d%d%d",&n,&m,&a,&b,&c);
s.clear();
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
for(int k = 0; k < N; k++)
dp[i][j][k][0] = dp[i][j][k][1] = -inf;
dp[0][0][0][0] = 0;
scanf("%s",str+1);
s.push_back(0);
for(int i = 1; i <= n; i++)
if(str[i]=='#')
s.push_back(i);
s.push_back(n+1);
for(int i = 0; i < s.size()-1; i++){
int len = s[i+1]-s[i]-1;
for(int j = 0; j < N-1; j++)
for(int k = 0; k < N-1; k++){
if(dp[i][j][k][0]>=0){
dp[i+1][j+len%2][k][0] = max(dp[i][j][k][0]+len/2,dp[i+1][j+len%2][k][0]);
if(len>=1&&str[s[i+1]+1]=='.')
dp[i+1][j+(len-1)%2][k+1][1] = max(dp[i][j][k][0]+(len-1)/2,dp[i+1][j+(len-1)%2][k+1][1]);
}
if(dp[i][j][k][1]>=0){
if(len>=1)
dp[i+1][j+(len-1)%2][k][0] = max(dp[i][j][k][1]+(len-1)/2,dp[i+1][j+(len-1)%2][k][0]);
if(len>=2&&str[s[i+1]+1]=='.')
dp[i+1][j+len%2][k+1][1] = max(dp[i][j][k][1]+(len-2)/2,dp[i+1][j+len%2][k+1][1]);
}
}
}
ll ans = 0;
int n = s.size()-1;
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
ans = max(ans,calc(n,i,j,0));
printf("%lld\n",ans);
return 0;
}
矩陣合併線段樹,異或就是矩陣倒置
#include<bits/stdc++.h>
using namespace std;
#define ls 2*rt
#define rs 2*rt+1
#define lson ls,l,mid
#define rson rs,mid+1,r
const int mx = 1e5+5;
const int mod = 1e9+7;
typedef long long ll;
char str[mx];
struct mat{
ll x[2][2];
friend mat operator*(mat a,mat b){
mat c;
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++){
c.x[i][j] = 0;
for(int k = 0; k < 2; k++)
c.x[i][j] = (c.x[i][j]+a.x[i][k]*b.x[k][j]%mod)%mod;
}
return c;
}
};
struct node{
mat a;
ll lazy;
}sum[mx<<2];
void change(mat &a){
swap(a.x[0][0],a.x[0][1]);
swap(a.x[1][0],a.x[1][1]);
swap(a.x[0][0],a.x[1][0]);
swap(a.x[0][1],a.x[1][1]);
}
void push_up(int rt){
sum[rt].a = sum[ls].a*sum[rs].a;
}
void push_down(int rt){
if(sum[rt].lazy){
change(sum[rs].a);
change(sum[ls].a);
sum[rs].lazy ^= 1;
sum[ls].lazy ^= 1;
sum[rt].lazy = 0;
}
}
void built(int rt,int l,int r){
sum[rt].lazy = 0;
if(l==r){
if(str[l]=='A'){
sum[rt].a.x[0][0] = 1;
sum[rt].a.x[0][1] = 0;
sum[rt].a.x[1][1] = 1;
sum[rt].a.x[1][0] = 1;
}
else{
sum[rt].a.x[0][0] = 1;
sum[rt].a.x[0][1] = 1;
sum[rt].a.x[1][0] = 0;
sum[rt].a.x[1][1] = 1;
}
return;
}
int mid = (l+r)/2;
built(lson);
built(rson);
push_up(rt);
}
void update(int rt,int l,int r,int L,int R){
if(l==L&&R==r){
change(sum[rt].a);
sum[rt].lazy ^= 1;
return;
}
int mid = (l+r)/2;
push_down(rt);
if(L>mid) update(rson,L,R);
else if(R<=mid) update(lson,L,R);
else update(lson,L,mid),update(rson,mid+1,R);
push_up(rt);
}
mat query(int rt,int l,int r,int L,int R){
if(l==L&&r==R){
return sum[rt].a;
}
int mid = (l+r)/2;
push_down(rt);
if(L>mid) return query(rson,L,R);
else if(R<=mid) return query(lson,L,R);
else return query(lson,L,mid)*query(rson,mid+1,R);
}
int main(){
int n,q;
scanf("%d%d",&n,&q);
scanf("%s",str+1);
built(1,1,n);
while(q--){
int op;
scanf("%d",&op);
if(op==1){
int L,R;
scanf("%d%d",&L,&R);
update(1,1,n,L,R);
}
else{
int L,R;
ll a,b;
scanf("%d%d",&L,&R);
scanf("%lld%lld",&a,&b);
mat ans = query(1,1,n,L,R);
mat x = {a,b,0,0};
ans = x*ans;
printf("%lld %lld\n",ans.x[0][0],ans.x[0][1]);
}
}
return 0;
}
待做