Codeforces Round #572 (Div. 2)简要题解

A. Keanu Reeves

分析:01个数相等答案就是1,不相等就是2。

#include "bits/stdc++.h"
using namespace std;
int main(){
    int n;
    string s;
    cin>>n>>s;
    int z=0,o=0;
    for (int i = 0; i < n; ++i) {
        if(s[i]=='1')o++;
        else z++;
    }
    if(z!=o){
        puts("1");
        cout<<s<<endl;
    }
    else {
        puts("2");
        cout<<s[0]<<endl;
        for (int i = 1; i < n; ++i) {
            cout<<s[i];
        }
    }
}

B. Number Circle

分析:排序之后分奇偶放左右,注意特判一下不可能的情况就可以了,证明不写了。

#include "bits/stdc++.h"
using namespace std;
int a[100004];
int main(){
    int n;
    cin>>n;
    for (int i = 0; i < n; ++i) {
        scanf("%d",&a[i]);
    }
    sort(a,a+n);
    if(a[n-1]>=a[n-2]+a[n-3])puts("NO");
    else {
        deque<int>q;
        puts("YES");
        for (int i = 0; i < n; ++i) {
            if(i&1)q.push_back(a[i]);
            else q.push_front(a[i]);
        }
        while (!q.empty()){
            printf("%d ",q.front());
            q.pop_front();
        }
    }
}

C. Candies!

分析:合并操作是相加取模,且所有数<=9,那么答案就是区间合/10。

#include "bits/stdc++.h"
using namespace std;
int a[100004];
int pre[100004];
int main() {
    int n;
    cin >> n;
    pre[0]=0;
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        pre[i]=pre[i-1]+a[i];
    }
    int q;
    cin >> q;
    for (int i = 0; i < q; ++i) {
        int l, r;
        scanf("%d%d", &l, &r);
        printf("%d\n",(pre[r]-pre[l-1])/10);
    }
 
}

D1. Add on a Tree

分析:判断一下是否存在度为2的点就可以了。

#include "bits/stdc++.h"
using namespace std;
const int mod = 1e9+7;
int num[100004];
int main(){
    int n;
    cin>>n;
    for (int i = 0; i < n-1; ++i) {
        int u,v;
        scanf("%d%d",&u,&v);
        num[u]++;
        num[v]++;
    }
    for (int i = 1; i <= n; ++i) {
        if(num[i]==2){
            puts("NO");
            return 0;
        }
    }
    puts("YES");
}

D2. Add on a Tree: Revolution

分析:要将某条边置0且不改变其他边的状态,对于这条边的两个点,分别找出两个叶子节点(如果有的话)x,y,a,b,,然后add(x,a,w/2),add(y,b,w/2),add(x,y,-w/2),add(a,b,-w/2),特判一下这个点本来就是叶子节点的情况就可以了。数据量很小,怎么写都能过。

#include "bits/stdc++.h"
 
using namespace std;
const int mod = 1e9 + 7;
struct node{
    int u,w;
};
bool vis[1004];
vector<node>v[1004];
int ans[1004][1004];
int Find(int u,int pre){
    vis[u]=1;
    if(v[u].size()==1)return u;
    for (int i = 0; i < v[u].size(); ++i) {
        if(v[u][i].u==pre)continue;
        if(vis[v[u][i].u])continue;
        return Find(v[u][i].u,u);
    }
}
void dfs(int u,int pre,int w){
    if(w!=0){
        if(v[u].size()!=1 && v[pre].size()!=1){
            memset(vis,0, sizeof(vis));
            int x = Find(u,pre);
            int y = Find(u,pre);
            int a = Find(pre,u);
            int b = Find(pre,u);
            ans[x][a]+=w/2;
            ans[y][b]+=w/2;
            ans[x][y]-=w/2;
            ans[a][b]-=w/2;
            ans[a][x]+=w/2;
            ans[b][y]+=w/2;
            ans[y][x]-=w/2;
            ans[b][a]-=w/2;
        }
        else if(v[u].size()!=1 && v[pre].size()==1){
            memset(vis,0, sizeof(vis));
            int x = Find(u,pre);
            int y = Find(u,pre);
            ans[pre][x]+=w/2;
            ans[pre][y]+=w/2;
            ans[y][x]-=w/2;
            ans[x][pre]+=w/2;
            ans[y][pre]+=w/2;
            ans[x][y]-=w/2;
        }
        else if(v[u].size()==1 && v[pre].size()!=1){
            memset(vis,0, sizeof(vis));
            int a = Find(pre,u);
            int b = Find(pre,u);
            ans[u][a]+=w/2;
            ans[u][b]+=w/2;
            ans[b][a]-=w/2;
            ans[a][u]+=w/2;
            ans[b][u]+=w/2;
            ans[a][b]-=w/2;
        }
        else if(v[u].size()==1 && v[pre].size()==1){
            memset(vis,0, sizeof(vis));
            ans[u][pre]+=w/2;
            ans[pre][u]+=w/2;
        }
    }
    for (int i = 0; i < v[u].size(); ++i) {
        if(v[u][i].u!=pre)dfs(v[u][i].u,u,v[u][i].w);
    }
}
 
int main() {
    int n;
    cin>>n;
    int x,y,z;
    memset(ans,0, sizeof(ans));
    for (int i = 0; i < n-1; ++i) {
        scanf("%d%d%d",&x,&y,&z);
        v[x].push_back({y,z});
        v[y].push_back({x,z});
    }
    for (int i = 1; i <= n; ++i) {
        if(v[i].size()==2){
            puts("NO");
            return 0;
        }
    }
    puts("YES");
    dfs(1,-1,0);
    int cnt = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j < i; ++j) {
            if(ans[i][j]!=0){
                cnt++;
            }
        }
    }
    cout<<cnt<<endl;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j < i; ++j) {
            if(ans[i][j]!=0){
                printf("%d %d %d\n",i,j,ans[i][j]);
            }
        }
    }
}

E. Count Pairs

分析:化简:

(a_i+a_j)*(a_i^2+a_j^2)

=(a_i-a_j)*(a_i+a_j)*(a_i^2+a_j^2)/(a_i-a_j)

=(a_i^4-a_j^4)/(a_i-a_j)

即变成求

(a_i^4-a_j^4)/(a_i-a_j) \equiv k \bmod p

(a_i^4-a_j^4)/(a_i-a_j)-k\bmod p = 0

((a_i^4-ka_i)-(a_j^4-ka_j))/(a_i-a_j)\bmod p = 0

((a_i^4-ka_i)-(a_j^4-ka_j))\bmod p = 0

然后就可以线性处理了。

#include "bits/stdc++.h"
 
using namespace std;
const int mod = 1e9 + 7;
unordered_map<long long, int> mp;
 
int main() {
    int n, p, k;
    cin >> n >> p >> k;
    long long ans = 0;
    long long x;
    for (int i = 0; i < n; ++i) {
        scanf("%lld", &x);
        long long res = (x * x % p * x % p * x % p - k * x % p + p) % p;
        ans += mp[res]++;
    }
    cout << ans << endl;
}

F. Array Beauty

分析:设f(x)为beauty>=x的长度为k的子序列。

容易得到ans = \sum _{i=1}f(i),即beauty为x的被计算x次。同时,由于a[i]最大只有1e5,那么数组的最大beauty应该为1e5/(k-1),证明略。

对于每个f[i],用dp[i][j]表示前i个取j个,beauty>=x的种类数,就可以在O(nk)的时间内求出。

那么总复杂度为O(maxi*n)

#include "bits/stdc++.h"
using namespace std;
const int mod  = 998244353;
int dp[1004][1004],a[1004];
int main(){
    int n,k;
    cin>>n>>k;
    for (int i = 1; i <= n; ++i) {
        scanf("%d",&a[i]);
    }
    sort(a+1,a+1+n);
    int ans = 0;
    for (int m = 1; m <= 100000/(k-1); ++m) {
        dp[0][0]=1;
        int pos = 0;
        for (int i = 1; i <= n; ++i) {
            while (pos < i && a[i] - a[pos+1] >= m)pos++;
            dp[i][0]=1;
            for (int j = 1; j <= k; ++j) {
                dp[i][j] = (dp[i-1][j] + dp[pos][j-1])%mod;
            }
        }
        ans = (ans + dp[n][k])%mod;
    }
    cout<<ans;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值