cf 1526 (大概算是补题报告

A 简单构造

假设我们现在填的位置是a[x],a[x+1],a[x+2],那么我们只需要保证a[x]和a[x+2]相邻即可保证a[x+1]!=(a[x+1]+a[x+2])/2,因此,我们可以将数在奇数位从大到小隔一位放进去,再从偶数位从小到大放进去。

#include<bits/stdc++.h>
using namespace std;
const int maxn=50+7;
queue<int>q;
int a[maxn];
int main()
{
    int t;scanf("%d",&t);
    while(t--){
        int n;scanf("%d",&n);
        for(int i=1;i<=2*n;i++){
            scanf("%d",&a[i]);
        }
        sort(a+1,a+1+2*n);
        int l=1,r=2*n;
        for(int i=1;i<=2*n;i++){
            if(i%2==1){
                q.push(a[l++]);
            }else{
                q.push(a[r--]);
            }
        }
        bool flag=false;
        while(!q.empty()){
            if(flag)cout<<" ";
            cout<<q.front();q.pop();
            flag=true;
        }cout<<endl;
    }
    return 0;
}

B 贪心?

观察易发现,有偶数个1的数字都可以用11代替,而奇数个的相当于每多少个数可以加多少个余数,比如111就相当于有10个11就能够选择加或者不加一个1,而11111这种比111大的奇数个1的数字一定可以由11和111组和替代。因此只需要计算x/11 和x%11,x%11的部分每个数都由10个11来解决,比较大小即可。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t;scanf("%d",&t);
    while(t--){
        int n;scanf("%d",&n);
        int t1=n/110;
        int t2=n%11;
        if(t1>=t2)cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

C1&C2 贪心/DP?

首先是贪心的做法,带反悔的贪心,我一直吃,吃到不能吃的最后一个毒我就把我之前最毒的吐出来换成现在的毒,此时一定最优。考虑当前位,我已经把毒性最小的和无毒的全吃了,再吃必死。
其次是DP,只会C1的DP,这就非常显而易见,DP[i][j]表示到第i个药吃了j瓶的最大生命值。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
priority_queue<ll>pq;
int main()
{
    int n;scanf("%d",&n);
    ll nownum=0;int cnt=0;
    for(int i=1;i<=n;i++){
        ll tmp;scanf("%lld",&tmp);
        if(nownum+tmp<0){
            if(pq.empty())continue;
            if(pq.top()+tmp>0)nownum=nownum+pq.top()+tmp,pq.pop(),pq.push(-tmp);
        }else{
            if(tmp<0)pq.push(-tmp);
            nownum+=tmp,cnt++;
        }
    }
    cout<<cnt<<endl;
    return 0;
}

D 神秘之构造/对于逆序对的理解?

这题不是十分清晰。他们说结论是答案里面所有字符连在一起。(或许可以打表猜?

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
char inp[maxn];
int a[maxn],b[maxn],tot[maxn];
long long cnt;
void merge(int l,int mid,int r){
    int i=l,j=mid+1;
    for(int k=l;k<=r;k++){
        if(j>r||i<=mid&&a[i]<=a[j])b[k]=a[i++];
        else b[k]=a[j++],cnt+=mid-i+1;
    }
    for(int k=l;k<=r;k++)a[k]=b[k];
}
void merge_sort(int l,int  r){

    int mid=(l+r)>>1;
    if(l==r)return;
    merge_sort(l,mid);
    merge_sort(mid+1,r);
    merge(l,mid,r);
}
map<char,int>mp;
vector<int>v[4];
int pem[4]={0,1,2,3};
int outp[maxn];
signed main()
{
    mp['A']=0;mp['N']=1;mp['O']=2;mp['T']=3;
    int t;scanf("%lld",&t);
    while(t--){
        for(int i=0;i<4;i++)v[i].clear();
        scanf("%s",inp+1);
        memset(tot,0,sizeof(tot));
        int len=strlen(inp+1);
        for(int i=1;i<=len;i++){
            v[mp[inp[i]]].push_back(i);
            tot[mp[inp[i]]]++;
        }
        long long ans=0;
        pem[0]=0;pem[1]=1;pem[2]=2;pem[3]=3;
        do{
            int ttot=0;cnt=0;
            for(int i=0;i<4;i++)
                for(auto x:v[pem[i]])a[++ttot]=x;

            merge_sort(1,len);

            ttot=0;
            if(cnt>ans){
                ans=cnt;
                for(int i=0;i<4;i++){
                    //cout<<"!"<<tot[pem[i]];
                    for(int j=0;j<tot[pem[i]];j++)outp[++ttot]=pem[i];
                }//cout<<endl;
            }
        }while(next_permutation(pem,pem+4));
        if(ans!=0){
            for(int i=1;i<=len;i++){
                switch (outp[i]) {
                    case 0:cout<<"A";break;
                    case 1:cout<<"N";break;
                    case 2:cout<<"O";break;
                    case 3:cout<<"T";
                }
            }cout<<endl;
        }else{
            //cout<<"rep"<<endl;
            for(int i=1;i<=len;i++)cout<<inp[i];cout<<endl;
        }

    }
    return 0;
}

E 组和数学+对后缀数组的一点点理解

首先已知若rank[i]>rank[j],则s[i]<=s[j],若rank[i+1]<rank[j+1],则s[i]<s[j];
然后在sa数组中顺序扫下去即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
const int mod=998244353;
int sa[maxn],rnk[maxn];
ll f[(maxn<<1)+7];
ll powmod(ll a,ll b){
    ll ret=1;
    for(;b;b>>=1){
        if(b&1)ret=(ret*a)%mod;
        a=a*a%mod;
    }
    return ret;
}
void init(){
    f[0]=1,f[1]=1;
    for(ll i=2;i<=2*maxn;i++){
        f[i]=(f[i-1]*i)%mod;
    }
}
ll c(ll n,ll m){
    if(n<m)return 0;
    ll ret=f[n];
    ret=ret*powmod(f[m],mod-2)%mod;
    ret=ret*powmod(f[n-m],mod-2)%mod;
    //cout<<powmod(f[m],mod-2)<<","<<powmod(f[n-m],mod-2)<<endl;
    return ret;
}
int main()
{
    init();
    int n,k;scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%d",&sa[i]);
        rnk[sa[i]]=i;
    }
    int cnt=0;
    for(int i=2;i<=n;i++){
        if(rnk[sa[i-1]+1]>rnk[sa[i]+1])cnt++;
    }
    //cout<<"!"<<cnt<<endl;
    //cout<<"?"<<n+k-cnt-1<<","<<n<<endl;
    cout<<c(n+k-cnt-1,n)<<endl;
    return 0;
}

F 3000分的交互题,我直接跑路

posted @ 2021-07-10 16:11  a_night  阅读(57)  评论(0)    收藏  举报