Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)

场次链接
题目链接
A. Happy Birthday, Polycarp!
t个询问,每个询问给你一个n为上限,询问有多少个小于等于n并且所有位上数字一样的数。
数据范围: 1 ≤ t ≤ 1\leq t \leq 1t 10 4 {\rm 10}^4 104, 1 ≤ n ≤ 1\leq n \leq 1n 10 9 {\rm 10}^9 109
解:枚举所有位为1-9 暴力计数即可
复杂度: O ( 9 ∗ log ⁡ 10 n ) O({9*\log_{10}n}) O9log10n

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void work()
{
    ll n;
    scanf("%lld",&n);
    int ans=0;
    for(int i=1;i<=9;i++){
        ll k=i;
        while(k<=n){
            //printf("%lld\n",k);
            ans++;
            k=k*10+i;
        }
    }
    printf("%d\n",ans);
}
int main()
{
    int T;
    scanf("%d",&T);
    //T=1;
    while(T--){
        work();
    }
}

题目链接
B. Make Them Odd
给你n个数,然后每次可以选择一个偶数,使这n个数中所有等于这个数的数除以二,问最少要做几次才能使所有数都变成奇数。
数据范围: 1 ≤ t ≤ 1\leq t \leq 1t 10 4 {\rm 10}^4 104, 1 ≤ n ≤ 1\leq n \leq 1n 2 ∗ 10 5 2*{\rm 10}^5 2105 1 ≤ s u m ( n ) ≤ 1\leq sum(n) \leq 1sum(n) 2 ∗ 10 5 2*{\rm 10}^5 2105
解:如果两个偶数在不断除二后得到的是同一个奇数,则这两个数中小的那个数可以被大的那个数包含。所以将所有偶数不断除以二,将得到奇数的次数记录,取每一个奇数得到次数的最大值求和。
复杂度: O ( n ∗ log ⁡ n ) O({n*\log n}) Onlogn

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void work()
{
    map<int,int>m;
    set<int>s;
    int n;
    scanf("%d",&n);
    int maxx=0;
    int ans=0;
    for(int i=1;i<=n;i++){
        int a;
        scanf("%d",&a);
        int cnt=0;
        while(a%2==0){
            cnt++;
            a/=2;
        }
        if(cnt>=1){
            m[a]=max(m[a],cnt);
            s.insert(a);
        }
    }
    set<int>::iterator it;
    for(it=s.begin();it!=s.end();it++){
        ans+=m[*it];
    }
    printf("%d\n",ans);
 
}
int main()
{
    int T;
    scanf("%d",&T);
    //T=1;
    while(T--){
        work();
    }
}

题目链接
C. As Simple as One and Two
总共T个询问,每次给你一个字符串,你可以删掉其中的任意个数,要求最后字符串中不含有“one”和“two”,问最少要删几个。
数据范围: 1 ≤ t ≤ 1\leq t \leq 1t 10 4 {\rm 10}^4 104 1 ≤ 1\leq 1字符串长度 ≤ \leq 1.5 ∗ 10 5 1.5*{\rm 10}^5 1.5105 1 ≤ 1\leq 1字符串总长 ≤ \leq 1.5 ∗ 10 6 1.5*{\rm 10}^6 1.5106
解:对于每一个我们找到的“one”和“two”,最简单的方法就是删掉’n’和’w’,但是有一个特殊情况需要考虑:“twone”,当这个情况时,最好的方法是删掉‘o’。模拟即可
复杂度: O ( n ) O(n) O(n)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void work()
{
    char a[2000005];
    scanf("%s",a+1);
    int l=strlen(a+1);
    vector<int>v;
    for(int i=1;i<=l-2;i++){
        if(a[i]=='o'&&a[i+1]=='n'&&a[i+2]=='e'){
            if(v.size()>0&&v[v.size()-1]==i){	//如果我刚删掉了‘o’则不用继续删
                continue;
            }else{
                v.push_back(i+1);
            }
        }
        if(a[i]=='t'&&a[i+1]=='w'&&a[i+2]=='o'){
            if(i<l-2&&a[i+3]=='o')	//如果后面是o那么选择删w,否则删o这样便于twone的判断
                v.push_back(i+1);
            else v.push_back(i+2);
        }
    }
    printf("%d\n",v.size());
    for(int i=0;i<v.size();i++){
        printf("%d ",v[i]);
    }
    printf("\n");
}
int main()
{
    int T;
    scanf("%d",&T);
    //T=1;
    while(T--){
        work();
    }
}

题目链接
D. Let’s Play the Words?
t个询问,每个询问给n个字符串,每个字符串只有0和1两种数,让你对这些字符串进行串联,要求为前一个字符串的最后一个数和后一个字符串的第一个数相同。你可以反转其中的一些字符串,例如’011’反转为’110’。但是要求最后答案中所有字符串均不相同。要求反转次数小于等于n,如果无法满足,输出-1。如果可以满足,输出反转次数和反转的哪些字符串。
数据范围: 1 ≤ t ≤ 1\leq t \leq 1t 10 4 {\rm 10}^4 104, 1 ≤ n ≤ 1\leq n \leq 1n 2 ∗ 10 5 2*{\rm 10}^5 2105 1 ≤ 1\leq 1字符串长度 ≤ \leq 4 ∗ 10 6 4*{\rm 10}^6 4106 1 ≤ s u m ( n ) ≤ 1\leq sum(n) \leq 1sum(n) 2 ∗ 10 5 2*{\rm 10}^5 2105 1 ≤ 1\leq 1字符串总长 ≤ \leq 4 ∗ 10 6 4*{\rm 10}^6 4106
解:将字符串按照首位和末位分为4类。字符串满足01-11-11-……-11-10-01,10-00-00-00-……-00-01这样的循环。如果要满足题目要求,那么01和10的数量差应该小于等于1,那么将多的进行反转(注意反转后是否重复),使得01和10数量差小于等于1。
特判:如果10和01均为0,那么需要11和00其中一个为0才能满足,否则不满足
复杂度: O ( n ) O(n) O(n)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int vis[200005];
map<string,int>m;
vector<int>v[4];
void work()
{
    int n;
    cin>>n;
    m.clear();
    v[0].clear();
    v[1].clear();
    v[2].clear();
    v[3].clear();
    for(int i=1;i<=n;i++){
        string a;
        cin>>a;
        if(a[0]=='0'&&a[a.length()-1]=='0')v[0].push_back(i);
        if(a[0]=='0'&&a[a.length()-1]=='1')v[1].push_back(i);
        if(a[0]=='1'&&a[a.length()-1]=='0')v[2].push_back(i);
        if(a[0]=='1'&&a[a.length()-1]=='1')v[3].push_back(i);
        m[a]=i;
        reverse(a.begin(),a.end());
        if(m[a]){
            vis[m[a]]=1;
            vis[i]=1;
        }else{
            vis[i]=0;
        }
    }
    if(v[1].size()==v[2].size()&&v[1].size()==0){
        if(v[0].size()==0||v[3].size()==0){
            cout<<"0"<<endl;
        }else{
            cout<<"-1"<<endl;
        }
    }else{
        int k;
        int cnt;
        if(v[1].size()>v[2].size()){
            k=1;
            cnt=v[1].size()-v[2].size();
        }else{
            k=2;
            cnt=v[2].size()-v[1].size();
        }
        cnt/=2;
        vector<int>ans;
        for(int i=0;i<v[k].size();i++){
            if(cnt==0){
                break;
            }
            if(vis[v[k][i]]==0){
                ans.push_back(v[k][i]);
                cnt--;
            }
        }
        if(cnt!=0){
            cout<<"-1"<<endl;
        }else{
            cout<<ans.size()<<endl;
            for(int i=0;i<ans.size();i++){
                cout<<ans[i]<<" ";
            }
            cout<<endl;
        }
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    int T;
    cin>>T;
    //T=1;
    while(T--){
        work();
    }
}

题目链接
E. Two Fairs
n个点,m条边,给a,b两点,问有多少组(x,y),x,y之间所有的路径都经过a和b,经过顺序任意。
数据范围: 1 ≤ t ≤ 4 ∗ 10 4 1\leq t \leq 4*{\rm 10}^4 1t4104, 1 ≤ n ≤ 2 ∗ 10 5 1\leq n \leq 2*{\rm 10}^5 1n2105 n − 1 ≤ m ≤ 5 ∗ 10 5 n-1\leq m \leq 5*{\rm 10}^5 n1m5105 1 ≤ s u m ( n ) ≤ 2 ∗ 10 5 1\leq sum(n) \leq 2*{\rm 10}^5 1sum(n)2105 s u m ( m ) ≤ 5 ∗ 10 5 sum(m) \leq 5*{\rm 10}^5 sum(m)5105
解:给a点赋值1,b点赋值2,以a,b为原点跑bfs(注意vis[a]和vis[b]先设为3),bfs完之后,vis值为3的即是可以不同时经过a,b2点就到达的,答案即vis为1的数量*vis为2的数量。
复杂度: O ( n ) O(n) O(n)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node
{
    int v;
    int id;
};
int vis[200005];
vector<int>v[500005];
void work()
{
 
    int n,m,a,b;
    scanf("%d%d%d%d",&n,&m,&a,&b);
    for(int i=1;i<=n;i++){
        vis[i]=0;
        v[i].clear();
    }
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    node k;
    k.v=1;
    k.id=a;
    vis[a]=3;
    queue<node>q;
    q.push(k);
    k.v=2;
    k.id=b;
    vis[b]=3;
    q.push(k);
    while(!q.empty()){
        k=q.front();
        q.pop();
        for(int i=0;i<v[k.id].size();i++){
            //printf("%d\n",vis[v[k.id][i]]);
            if(vis[v[k.id][i]]!=k.v&&vis[v[k.id][i]]!=3){
                vis[v[k.id][i]]+=k.v;
                node nxt;
                nxt.id=v[k.id][i];
                nxt.v=k.v;
                q.push(nxt);
            }
        }
    }
    ll x=0,y=0;
    for(int i=1;i<=n;i++){
        //printf("%d ",vis[i]);
        if(vis[i]==1){
            x++;
        }
        if(vis[i]==2){
            y++;
        }
    }
    //printf("\n");
    printf("%lld\n",x*y);
 
}
int main()
{
    int T;
    scanf("%d",&T);
    //T=1;
    while(T--){
        work();
    }
}

F. Beautiful Rectangle
给n个数,组成一个矩形,要求每行每列没有数字重复,问能组成的面积最大的矩形。
数据范围: 1 ≤ n ≤ 4 ∗ 10 5 1\leq n \leq 4*{\rm 10}^5 1n4105, 1 ≤ a [ i ] ≤ 10 9 1\leq a[i] \leq {\rm 10}^9 1a[i]109
解:首先判断矩阵的大小,枚举列数(即每种数最多几个),判断能组成几行,然后取面积最大值。然后将所有数枚举暴力斜着排列到矩形中。
复杂度: O ( n ∗ log ⁡ n ) O(n*\log n) O(nlogn)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node
{
    int id;
    int sum;
}num[400005];
map<int,int>m;
node ans[400005];
int cnt[400005];
vector<int>v[400005];
int s[400005];
bool cmp(node x,node y)
{
    return x.sum>y.sum;
}
void work()
{
    int n;
    scanf("%d",&n);
    int tot=0;
    for(int i=1;i<=n;i++){
        int a;
        scanf("%d",&a);
        if(m[a]){
            num[m[a]].sum++;
        }else{
            num[++tot].id=a;
            num[tot].sum=1;
            m[a]=tot;
        }
    }
    sort(num+1,num+tot+1,cmp);
    for(int i=1;i<=tot;i++){
        s[i]=num[i].sum;
        s[i]+=s[i-1];
    }
    int tmp=1,ans=0,ansp,ansi;
    for(int i=tot;i>=1;i--){
        while(num[tmp].sum>i)tmp++;
        int tmpp;
        tmpp=tmp*i+n-i-s[tmp-1];
        if(tmpp/i<i)continue;
        if(tmpp/i*i>ans){
            ans=(tmpp/i)*i;
            ansp=tmpp;
            ansi=i;
        }
    }
    int p,q;
    p=ansi;
    q=ans/ansi;
    printf("%d\n",q*p);
    printf("%d %d\n",q,p);
    for(int i=0;i<q;i++){
        v[i].resize(p);
    }
    int x=0,y=0;
    int pi=1,ti=0,xypi=0,xyti=0;
    for(int i=0;i<p*q;i++){
        //printf("??%d %d %d\n",y,x,num[pi].id);
        v[x][y]=num[pi].id;
        y++,x=(x+1)%q;
        xyti++;
        if(xyti==p){
            xyti=y=0;x=++xypi;
        }
        ti++;
        if(ti==min(p,num[pi].sum)){
            pi++;
            ti=0;
        }
    }
    for(int i=0;i<q;i++){
        for(int j=0;j<p;j++){
            printf("%d ",v[i][j]);
        }
        printf("\n");
    }
}
int main()
{
    int T;
    //scanf("%d",&T);
    T=1;
    while(T--){
        work();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值