Codeforces Round #672 (Div. 2) AD problem solution

Codeforces Round #672 (Div. 2) AD problem solution

//Write in rating value 1987/2184

Contest link: https://codeforces.com/contest/1420 Question
A,
sorting related, thinking water question

Title means a given length n number of columns, you can ask in n × \ TimesAfter the number of exchanges × (n-1)/2-1, the sequence is sorted according to the value.

I don’t quite understand why some people try to think about
the sorting algorithm based on the original subscript of the sequence. In the worst case, the number of exchanges required is accumulated from 1 to n-1, and the value is n × \ times× (n-1)/2, and the maximum number of operations given by the question is just one less. So in fact, in other words, except for the worst case, all the situations can be sorted by exchange.
So what is the worst case? The worst case is that the original sequence of numbers is strictly monotonically decreasing. Just judge it directly.

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n;
        cin>>n;
        vector<int>num(n);
        for(auto &x:num) cin>>x;
        bool flag=1;
        for(int i=1;i<n;i++) if(num[i]>=num[i-1]) flag=0;
        if(flag) cout<<"NO"<<endl;
        else cout<<"YES"<<endl;
    }
}

B title
calculation, simple conclusion

The question means that given a number sequence num[], ask you how many groups of subscripts i and j satisfy i<j, and num[i]&num[j]>=num[i]^num[j].

The first thing to realize is that the & and operation will not get a value greater than the two values ​​involved in the operation. For a number x, taking x=6 as an example, the binary representation of 6 is 000…000110. For all 0s on the left side, it is impossible to get 1 after the & AND operation with another number, but for ^ For the exclusive OR operation, if the corresponding bit in the binary of another number is 1, the ^ exclusive OR operation will get a bit 1. In this case, the result of the ^ operation will inevitably be greater than the result of the & AND operation, so the left All 0s on the side should also be all 0s in binary.
For the highest 1 of x=6, if the corresponding bit of another number is 1, then the result of the & and operation will be 1, and the result of the ^ exclusive OR operation will be 0, which must meet the requirements of. If the bit corresponding to another number is 0, the result of the & and operation will be 0, and the result of the ^ XOR operation will be 1, which must not meet the requirements.

From this we can draw the conclusion that for the number num[j], it can form a subscript i that meets the requirements of the title, and must satisfy the highest bit 1 of num[i] and the highest bit 1 of num[j]. Therefore, we directly use an array cas[i] to record how many times the number whose highest bit is the i-th bit appears before the subscript j.
The answer can be obtained in O(n) time using the cas array.

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;

ll cas[100],sum[100];

int32_t main()
{
    
    
    IOS;
    cas[0]=1;
    for(ll i=1;;i++)
    {
    
    
        cas[i]=cas[i-1]*2;
        if(cas[i]>1e9) break;
    }
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n;
        cin>>n;
        vector<ll>num(n);
        for(auto &x:num) cin>>x;
        memset(sum,0,sizeof(sum));
        ll ans=0;
        for(int i=0;i<n;i++)
        {
    
    
            int tar=0;
            while(cas[tar]<=num[i]) tar++;
            ans+=sum[tar-1];
            sum[tar-1]++;
        }
        cout<<ans<<endl;
    }
}

C question
C1 can easily see that dp can be written, but because C2 needs to exchange and change the array data, every time the dp is modified O(n), it will inevitably time out. C2 needs to make a conclusion.

The question means that given a sequence of length n, you need to select a part of the subscripts to form a new sequence. The value of the new sequence is defined as all odd subscripts in the new sequence minus all even subscripts. Now ask what the maximum value is.
In the case of C2, there are q more modification operations on the original sequence. Each modification will exchange the two digit positions in the original sequence. For each modification, the maximum value of the sequence that can be formed is output.

In the case of C1, it is easy to see that it can be solved quickly with dp. dp[i][0] represents the maximum value that the first i digits can constitute when the i-th digit is used and the last digit in the new sequence is an odd subscript, dp[i][1] represents the i-th The maximum value that the first i digits can constitute when the last number in the new number sequence is an even subscript.
In the transfer equation, dp[i][0] is divided into two transitions: the i-th digit selection and non-selection. If the i-th digit is not selected, then dp[i][0] starts from dp[i-1][ 0] is transferred, if the i-th digit is selected, dp[i][0] is transferred from dp[i-1][1]+num[i], and the two are taken as max. The transfer of dp[i][1] is the same.

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const ll maxn=3e5+7;

ll dp[maxn][2];
ll num[maxn];
ll n,q;

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        cin>>n>>q;
        for(ll i=0;i<n;i++)
        {
    
    
            cin>>num[i];
            dp[i][0]=dp[i][1]=-llINF;
        }
        dp[0][0]=num[0];dp[0][1]=0;
        for(ll i=1;i<n;i++)
        {
    
    
            dp[i][0]=max(dp[i-1][0],dp[i-1][1]+num[i]);
            dp[i][1]=max(dp[i-1][1],dp[i-1][0]-num[i]);
        }
        cout<<max(dp[n-1][0],dp[n-1][1])<<endl;
    }
}

For C2, there are q swap operations, which will swap the positions of the two numbers in the sequence, and require the largest value to be output after each swap operation. At this point, it is obvious that continuing to use C1's dp solution will time out, so we must think of a solution that is O(1) or O(logn) after each modification.
The words here are summarized and summarized as a rule. Our final optimal choice must be the "peak" and "valley" of the median value of this series. If you prove the way, you can give examples like 1, 4, 3, 2, 7 by yourself. Regarding the interval of 4, 3, and 2, we prove by contradiction that we must choose 4 and 2. Use this proof scheme to prove the conclusion, and the "trough" at the beginning and end of the sequence is not taken.
For each modification and exchange of the numbers of subscripts i and j, the positions that may have an impact (generation or disappearance of crests and troughs) are i-1, i, i+1, j-1, j, j+1, six positions, Perform the inverse calculation on the original peak and valley value of each position, and then recalculate the peak and valley formed after modification. Here we should pay attention to skip directly when i and j are equal, and pay attention to the coincidence of i+1 and j-1.

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const ll maxn=3e5+7;

ll num[maxn];
ll n,q;

ll check(ll i)//返回下标i的位置是波峰还是波谷,决定了这个位置上的数字是增加还是减少到最终结果上
//1代表波峰,-1代表波谷,0代表其他情况,恰好对应了其累加到结果上对应的系数
{
    
    
    if(n==1) return 1;//特判数列只有1个数的情况
    if(i==1)//如果当前位置是开头位置,如果是波峰的话就累加到结果上,其他情况都不取(开头的波谷不取)
    {
    
    
        if(num[1]>num[2]) return 1;//此时判断右侧即可
        else return 0;
    }
    if(i==n)//如果当前位置是末尾位置,如果是波峰的话就累加到结果上,其他情况都不取(末尾的波谷不取)
    {
    
    
        if(num[i]>num[i-1]) return 1;//此时判断左侧即可
        else return 0;
    }
    if(num[i]>num[i-1]&&num[i]>num[i+1]) return 1;//其他情况下如果既大于左边又大于右边则为波峰
    if(num[i]<num[i-1]&&num[i]<num[i+1]) return -1;//其他情况下入股既小于左右又小于右边则为波谷
    return 0;
}

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        cin>>n>>q;
        for(ll i=1;i<=n;i++) cin>>num[i];
        ll ans=0;
        for(ll i=1;i<=n;i++)//直接for一遍,每个数乘以其check对应的系数累加到结果上即可
        {
    
    
            ans+=check(i)*num[i];
        }
        cout<<ans<<endl;
        for(ll i=0;i<q;i++)//q次调换num[l]和num[r]
        {
    
    
            ll l,r;
            cin>>l>>r;
            if(l!=r)//l=r的情况直接跳过
            {
    
    
                if(l>1) ans-=check(l-1)*num[l-1];//l-1的位置如果存在,做逆运算
                if(l<n&&l+1!=r) ans-=check(l+1)*num[l+1];//l+1的位置如果存在,也做逆运算
                //下面同样的对r-1,r+1,l,r四个位置做逆运算
                if(r>1&&r-1>l+1) ans-=check(r-1)*num[r-1];//此处要注意特判r-1的位置与l+1不重合,否则会重复运算,l和r差值小于2的情况下都会有重合
                if(r<n) ans-=check(r+1)*num[r+1];
                ans-=check(l)*num[l];
                ans-=check(r)*num[r];
                swap(num[l],num[r]);//交换后把对应受影响位置的值加回来
                if(l>1) ans+=check(l-1)*num[l-1];
                if(l<n&&l+1!=r) ans+=check(l+1)*num[l+1];
                if(r>1&&r-1>l+1) ans+=check(r-1)*num[r-1];
                if(r<n) ans+=check(r+1)*num[r+1];
                ans+=check(l)*num[l];
                ans+=check(r)*num[r];
            }
            cout<<ans<<endl;
        }
    }
}

Question D
The application of the scan line idea, but this is one-dimensional.

The title means that there are n lights, and each light has a starting time and an ending time. Now you need to ask you about the combination of a small number of k lights, and all of them are on at a certain moment. .

This question is actually a simple application of the idea of ​​a line segment tree scan line. Simply put the start time and the end time in the same array, mark the start time as 1, and mark the end time as -1. According to the order of time, directly for once. When the time marked as 1 is encountered, the total number of lights that can be on at the same time in the current interval is +1, and when the time is marked as -1, it is reduced by 1. Use a num array to record the number of lights that can be turned on at the same time in the current interval. If num>=k, it means that a combination of k lights that meets the requirements can be formed. We use a similar idea to dp. The light just added must be in In this combination of k lights, it will not overlap with the previously calculated part, just add the number of combinations of k-1 from num-1 to the final answer.

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const ll mod=998244353;
const ll maxn=3e5+7;

ll n,k;
struct Node
{
    
    
    ll data,ope;
};

vector<Node>node;

bool cmp(Node a,Node b)
{
    
    
    if(a.data==b.data) return a.ope>b.ope;//注意这里的cmp,时间点相同的时候,要把增加的点放到减少的点前面
    else return a.data<b.data;
};

ll cas[maxn];

ll qpow(ll a,ll p)
{
    
    
    ll ret=1;
    while(p)
    {
    
    
        if(p&1) ret=ret*a%mod;
        a=a*a%mod;
        p>>=1;
    }
    return ret;
}

ll cal(ll num)
{
    
    
    if(num<k) return 0;
    return cas[num-1]*qpow(cas[num-k]*cas[k-1]%mod,mod-2)%mod;//计算在num-1个数中取k-1个的组合数
}

int32_t main()
{
    
    
    IOS;
    cas[0]=cas[1]=1;
    for(ll i=2;i<maxn;i++) cas[i]=cas[i-1]*i%mod;
    cin>>n>>k;
    n<<=1;
    for(ll i=0;i<n;i++)
    {
    
    
        ll x;
        cin>>x;
        node.push_back({
    
    x,(i&1)?-1:1});
    }
    sort(node.begin(),node.end(),cmp);
    ll ans=0,num=0;
    for(ll i=0;i<n;i++)
    {
    
    
        if(node[i].ope==1)
        {
    
    
            num++;
            ans=(ans+cal(num))%mod;
        }
        else num--;
    }
    cout<<ans<<endl;
}

Guess you like

Origin blog.csdn.net/StandNotAlone/article/details/108862525