1. 程式人生 > 其它 >《Codeforces Round #757 (Div. 2)》

《Codeforces Round #757 (Div. 2)》

A:貪心一下就行

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 1e6 + 5;
const LL Mod = 998244353;
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline 
long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) {
if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } int a[105]; void solve() { int n,L,r,k;scanf("%d %d %d %d",&n,&L,&r,&k); for(int i = 1;i <= n;++i) scanf("%d",&a[i]); sort(a + 1,a + n + 1); int ans = 0; for(int i = 1;i <= n;++i) {
if(a[i] >= L && a[i] <= r && k >= a[i]) ans++,k -= a[i]; } printf("%d\n",ans); } int main() { int ca;scanf("%d",&ca); while(ca--) { solve(); } // system("pause"); return 0; }
View Code

B:也是貪心

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<int,int> pii;
const int N = 2e5 + 5;
const int M = 1e6 + 5;
const LL Mod = 998244353;
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline long long ADD(long long x,long long y) {
    if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
    return (x + y) % Mod;
}
inline long long MUL(long long x,long long y) {
    if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
    return x * y % Mod;
}
inline long long DEC(long long x,long long y) {
    if(x - y < 0) return (x - y + Mod) % Mod;
    return (x - y) % Mod;
}

int a[N],pos[N];
struct Node{int id,x;}p[N];
bool cmp(Node a,Node b) {return a.x < b.x;}
void solve() {
    int n;scanf("%d",&n);
    for(int i = 1;i <= n;++i) scanf("%d",&p[i].x),p[i].id = i;
    sort(p + 1,p + n + 1,cmp);
    int L = -1,r = 1;
    pos[0] = 0;
    LL sum = 0;
    for(int i = n;i >= 1;--i) {
        if(abs(L) <= r) pos[p[i].id] = L,sum += 2LL * p[i].x * abs(L),--L;
        else pos[p[i].id] = r,sum += 2LL * p[i].x * r,r++;
    }
    printf("%lld\n",sum);
    for(int i = 0;i <= n;++i) printf("%d%c",pos[i],i == n ? '\n' : ' ');

}   
int main() {
    int ca;scanf("%d",&ca);
    while(ca--) {
        solve();
    }
    //system("pause");
    return 0;
}
View Code

C:這題的話其實和構造出來的陣列沒太大關係,甚至不需要構造就可以算。

這裡離線隨便構造了一個數組,然後dp計了一下異或和。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<int,int> pii;
const int N = 2e5 + 5;
const int M = 1e6 + 5;
const LL Mod = 1e9 + 7;
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline long long ADD(long long x,long long y) {
    if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
    return (x + y) % Mod;
}
inline long long MUL(long long x,long long y) {
    if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
    return x * y % Mod;
}
inline long long DEC(long long x,long long y) {
    if(x - y < 0) return (x - y + Mod) % Mod;
    return (x - y) % Mod;
}

struct Node{int L,r,w;}p[N];
vector<pii> vec[N];
int val[N],bit[30],r[30];
LL dp[N][30][2];
void solve() {
    int n,m;scanf("%d %d",&n,&m);
    for(int i = 1;i <= n;++i) {
        vec[i].clear(),val[i] = 0;
        for(int j = 0;j < 30;++j)
            for(int k = 0;k < 2;++k) dp[i][j][k] = 0;
    }
    for(int i = 0;i < 30;++i) r[i] = 0;
    for(int i = 1;i <= m;++i) {
        scanf("%d %d %d",&p[i].L,&p[i].r,&p[i].w);
        vec[p[i].L].push_back(pii{p[i].r,p[i].w});
    }
    for(int i = 1;i <= n;++i) {
        if(vec[i].size() == 0) {
            for(int j = 0;j < 30;++j) {
                if(r[j] != 0) val[i] |= (1 << j),r[j] = 0;
            }
        }   
        else {
            for(int j = 0;j < 30;++j) bit[j] = 1;
            for(auto v : vec[i]) {
                for(int j = 0;j < 30;++j) {
                    int g = (v.second >> j) & 1;
                    if(g == 0) bit[j] = 0;
                }
            }
            for(int j = 0;j < 30;++j) {
                if(bit[j] == 1) {
                    val[i] |= (1 << j); 
                    r[j] = 0;
                }
            }
            for(auto v : vec[i]) {
                for(int j = 0;j < 30;++j) {
                    int g = (v.second >> j) & 1;
                    if(g == 1 && bit[j] == 0) {
                        if(r[j] == 0) r[j] = v.first;
                        else r[j] = min(r[j],v.first);
                    }
                }
            }
        }
    }
    //for(int i = 1;i <= n;++i) printf("v %d\n",val[i]);
    LL ans = 0;
    for(int i = 1;i <= n;++i) {
        for(int j = 0;j < 30;++j) {
            int g = (val[i] >> j) & 1;
            dp[i][j][g] = ADD(dp[i][j][g],1); 
            for(int k = 0;k < 2;++k) {
                dp[i][j][k ^ g] = ADD(dp[i][j][k ^ g],dp[i - 1][j][k]); 
            }
            ans = ADD(ans,(1LL << j) * dp[i][j][1] % Mod);
            for(int k = 0;k < 2;++k) dp[i][j][k] = ADD(dp[i][j][k],dp[i - 1][j][k]);
        }
    }
    printf("%lld\n",ans);

}   
int main() {
    int ca;scanf("%d",&ca);
    while(ca--) {
        solve();
    }
  //  system("pause");
    return 0;
}
View Code

D1:這裡預處理的時候塞了個vector,就被卡常數了。

cnt[i] - 表示i的倍數的個數。

那麼就有dp[j] = max(dp[j],dp[i] + cnt[j] * (j - i))

就是說一開始所有i的倍數都當成gcd = i的代價來算,這時候序列尾有cnt[j]個抬升到gcd = j,那麼對於單個抬升增加的代價就是(j - i)。

很顯然j的倍數也就是i的倍數。複雜度nlogn

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 5;
const int M = 5e6 + 5;
const LL Mod = 1e9 + 7;
#define INF 1e9
#define IN_INF 0x3f3f3f
#define dbg(ax) cout << "now this num is " << ax << endl;

int a[N],cnt[M];//cnt[i] - i的倍數
LL dp[M];//當前gcd = i的最大值
void solve() { 
    int n;scanf("%d",&n);    
    for(int i = 1;i <= n;++i) scanf("%d",&a[i]),cnt[a[i]]++;
    for(int i = 1;i < M;++i) 
        for(int j = i + i;j < M;j += i) cnt[i] += cnt[j];
    for(int i = 1;i < M;++i) dp[i] = 1LL * cnt[i] * i;
    LL ans = 0;
    for(int i = 1;i < M;++i) {
        for(int j = i + i;j < M;j += i) {
            dp[j] = max(dp[j],dp[i] + 1LL * cnt[j] * (j - i));
        }
        ans = max(ans,dp[i]);
    }
    printf("%lld\n",ans);
}   
int main() {
    solve();
   // system("pause");
    return 0;
}
View Code

D2:只有a的範圍增大了。

我們考慮對D1的程式碼進行優化。

對於cnt計數部分,我們用狄利克雷字尾和優化一下即可。

對於後序的dp計數,很顯然有結論dp[j] >= dp[i] {i | j},那麼對於中間還可以增加倍數的情況,顯然不是最優轉移。

所以我們每次只需要轉移一個素數倍即可。複雜度就壓到了nloglogn

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 5;
const int M = 2e7 + 5;
const LL Mod = 1e9 + 7;
#define INF 1e9
#define IN_INF 0x3f3f3f
#define dbg(ax) cout << "now this num is " << ax << endl;

int a[N],cnt[M];//cnt[i] - i的倍數
LL dp[M];//當前gcd = i的最大值
bool vis[M];
int prime[M],tot = 0;
void init() {
    for(int i = 2;i < M;++i) {
        if(!vis[i]) prime[++tot] = i;
        for(int j = 1;j <= tot && prime[j] * i < M;++j) {
            vis[prime[j] * i] = 1;
            if(i % prime[j] == 0) continue;
        }
    }
}
void solve() { 
    init();
    int n;scanf("%d",&n);    
    for(int i = 1;i <= n;++i) scanf("%d",&a[i]),cnt[a[i]]++;
     for(int i = 1;i <= tot && prime[i] < M;++i) {
        for(int j = (M - 1) / prime[i];j;--j) {
            cnt[j] += cnt[j * prime[i]];
        }
    }
    for(int i = 1;i < M;++i) dp[i] = 1LL * cnt[i] * i;
    LL ans = 0;
    for(int i = 1;i < M;++i) {
        for(int j = 1;j <= tot && prime[j] * i < M;++j) {
            dp[prime[j] * i] = max(dp[prime[j] * i],dp[i] + 1LL * cnt[prime[j] * i] * (prime[j] * i - i));
        }
        ans = max(ans,dp[i]);
    }
    printf("%lld\n",ans);
}   
int main() {
    solve();
   // system("pause");
    return 0;
}
View Code

E:這題題意有點奇奇怪怪,解法好像是動態開點的線段樹。