A.Reachable Numbers

 

题意:

  给定操作f(x):将x加1,删去得到的数的所有末尾0,如f(10099)=10099+1=10100→1010→101现在给定一个数n,对n进行无限次该操作,输出过程中能得到的所有数的数量。

输入:一个正整数n(n1e9

输出:操作过程中得到的所有数数量

限制:1s,256M 

样例:

input

1098

output

20

 

样例解释:1098在操作过程中得到的数有:1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,1098,1099。共20个。

 

 

思路:思考一下发现第一次得到重复的数时就没必要继续操作下去了,接下来的数将会是之前都出现过的。根据这种不重复特性联想到set,每次操作将得到的数插入set,插入之前用find检测一下,如果已经出现过,停止操作,输出set里元素的数量。

  这题数据很水,最好不要用很多特判。。(亲手叉了某瓜的奇怪特判)

 代码:

#include<bits/stdc++.h>
#define FastIO ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<b;i++)
#define repp(i,a,b) for(ll i=a;i<=b;i++)
#define rep1(i,a,b) for(ll i=a;i>=b;i--)
#define mem(gv) memset(gv,0,sizeof(gv))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define QAQ 0
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pLL;
const int mod=1e9+7;
const int maxn=2e5+2;

ll n,cnt=1;
set<int>s;
int main(){
    FastIO
    cin>>n;
    ll t=n;
    s.insert(t);
    while(1){
        t++;
        while(t%10==0){
            t/=10;
        }
        if(s.find(t)!=s.end()) break;
        s.insert(t);
    }
//    for(auto x:s) cout<<x<<" ";
    cout<<s.size();
    return QAQ;
}

 

B. Long Number

题意:

  给定一个十进制数M(挺长的),同时给出一个映射:数字1到9分别对应一个1到9中的数(如1对应3,3对应5)。你可以不做任何操作或进行一次下面的操作:选择M的一段非空连续子区间(包括全集),将这些位置上的数全部变成它们的映射。你需要使最后得到的数尽可能大。

输入:第一行:一个正整数n(n≤2e5),n为十进制数的长度;

   第二行:n个连续的数字,代表这个十进制数;

   第三行:9个数,第i个数代表数字i的映射,即它所对应的数。

输出:最后得到的尽可能大的数。

限制:2s,256M

样例:

input

4
1337
1 2 5 4 6 6 3 1 9

output

1557

样例解释:选择33所在的区间,由于3对应5,变为55。

 

思路:我们称映射的数字比原数字大为有利,比原数字小为不利。从最高位搜,到第一个有利的位置停,以这个位置为起点向后取区间,直到碰到第一个不利的位置停止。(中间的注释是一开始没看见可以不操作写的。。)

代码:

#include<bits/stdc++.h>
#define FastIO ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<b;i++)
#define repp(i,a,b) for(ll i=a;i<=b;i++)
#define rep1(i,a,b) for(ll i=a;i>=b;i--)
#define mem(gv) memset(gv,0,sizeof(gv))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define QAQ 0
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pLL;
const int mod=1e9+7;
const int maxn=2e5+2;

int n;
char s[maxn],t;
map<int,int>m;
int main(){
    FastIO
    cin>>n>>s;
    repp(i,'1','9'){
        cin>>t;
        m[i]=t;
    }
    int l=strlen(s),p=0;
    while(p<l){
        if(m[s[p]]>s[p]) break;
        p++;
    }
    if(p==l){
    /*    p=0;
        while(p<l){
            if(m[s[p]]==s[p]){
                break;
            }
            p++;
        }
        if(p==l){
            s[l-1]=m[s[l-1]];
        }    */;
    }
    else{
        while(p<l){
            if(m[s[p]]>=s[p]){
                s[p]=m[s[p]];
                p++;
            }
            else break;
        }
    }
    cout<<s;
    return QAQ;
}

 

C1. Increasing Subsequence (easy version)

题意:

  给定一个序列,里面的数各不相同,可以从最左边或最右边取数字,要求取出的数字(按取出的顺序放)形成一个严格递增序列,求这个递增序列的最大长度,并按顺序输出整个操作过程,从左边取数输出字母L,从右边取数输出字母R。

输入:第一行,一个正整数n(n≤2e5),表示给出序列的长度;

   第二行,n个数,表示给出的序列。

输出:第一行,递增序列的最大长度;

   第二行,操作过程,由L和R组成的字符串。

限制:2s,256M

样例:

input

5

2 1 5 4 3

output

4

LRRR

样例解释:左边取一次,取出2,右边连取三次,取出3,4,5。

 

思路:没什么好说的。。每个数都不同就很简单,每次比较最左边和最右边两个数的大小,取较小的那个即可,直到无法操作。

代码:

#include<bits/stdc++.h>
#define FastIO ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<b;i++)
#define repp(i,a,b) for(ll i=a;i<=b;i++)
#define rep1(i,a,b) for(ll i=a;i>=b;i--)
#define mem(gv) memset(gv,0,sizeof(gv))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define QAQ 0
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pLL;
const int mod=1e9+7;
const int maxn=2e5+2;

int n,p,q,st;
int a[maxn];
vector<char>ans;
int main(){
    scanf("%d",&n);
    repp(i,1,n){
        scanf("%d",&a[i]);
    }
    if(n==1){
        cout<<1<<endl<<'L'<<endl;
        return QAQ;
    }
    
    if(a[1]>a[n]){
        st=a[n];
        p=1;
        q=n-1;
        ans.pb('R');
    }
    else{
        st=a[1];
        p=2;
        q=n;
        ans.pb('L');
    }
    
    while(p<=q){
        if(a[p]<st&&a[q]<st){
            break;
        }
        else if(a[p]<st&&a[q]>st){
            st=a[q];
            q--;
            ans.pb('R');
        }
        else if(a[p]>st&&a[q]<st){
            st=a[p];
            p++;
            ans.pb('L');
        }
        else{
            if(a[p]>a[q]){
                st=a[q];
                q--;
                ans.pb('R');
            }
            else{
                st=a[p];
                p++;
                ans.pb('L');
            }
        }
    }
    cout<<(int)ans.size()<<endl;
    for(auto x:ans){
        cout<<x;
    }
    return QAQ;
}

 

C2. Increasing Subsequence (hard version)

题意:

  跟C1不同的地方只有一个——给出的序列里的数可重复。

输入输出限制与C1相同。

样例:

input

5

1 2 4 3 2

output

4

LRRR

样例解释:取一次左边的1。然后左右都是2了,此时取左边的2接下来就只能取4,结束。所以选择右边的2,能取3,4。

 

思路:按C1的思路取,显然碰到两边相同的情况后我们只能选择全在左取或全在右取,判断一下哪边能取到更多的数就好。

   由于听嘤哥讲差分印象深刻,满脑子差分,顺序倒序预处理存了一下最初序列的两个差分数组,碰到相同的时候看哪边正数多。。(其实一样)

   打的时候图方便复制了C1代码外加了一堆特判,写出100多行=w=这里借用了某瓜的代码~

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define sys system("pause")
#define scan(n) scanf("%I64d", &(n))
#define scann(n, m) scanf("%I64d%I64d", &(n), &(m))
#define prin(n) printf("%I64d", (n))
#define scannn(a, b, c) scanf("%I64d%I64d%I64d", &(a), &(b), &(c))
#define ff first
#define ss second
#define mp make_pair
#define pb push_back
#define pii pair<int, int>
#define mem(a) memset(a, 0, sizeof(a))
#define prinspace printf("\n")
#define fo(i, a, b) for (int i = (a); i <= (b); i++)
#define ro(i, a, b) for (int i = (a); i >= (b); i--)
const int maxn = 2e5 + 100;
const int inf = 0x3f3f3f3f;
int a[maxn],n;
vector<char>ans;
int32_t main(){
    scan(n);
    fo(i,1,n)scan(a[i]);
    int l=1,r=n,lst=0;//wanna a[]>lst--->do
    for(int i=1;i<=n&&l<=r;i++){
        if(a[l]>lst&&a[r]>lst){
            if(a[l]<a[r]){ans.pb('L'),lst=a[l],l++;}
            else if(a[l]>a[r]){ans.pb('R'),lst=a[r],r--;}
        }
        if(a[l]<=lst&&a[r]>lst){
            ans.pb('R'), lst = a[r], r--;
        }
        if(a[l]>lst&&a[r]<=lst){
            ans.pb('L'), lst = a[l], l++;
        }
        if(a[l]==a[r]&&a[l]>lst){
            int x=l,y=r,cnt1=1,cnt2=1;
            while(a[x]<a[x+1]&&x+1<=r)cnt1++,x++;
            while(a[y]<a[y-1]&&y-1>=l)cnt2++,y--;
            if(cnt1>=cnt2)
                fo(i,1,cnt1)ans.pb('L');
            else   fo(i,1,cnt2)ans.pb('R');
            break;
        }
    }
    int t=ans.size();
    prin(t);printf("\n");
    fo(i,0,t-1)printf("%c",ans[i]);
    //sys;
    return 0;
}

/*15
37504 79054 80071 95721 135743 164345
189260 190810 191657 196168 200000 200000 190810 190018 185437
11
LLLLLLRLRRR
*/

 

D. N Problems During K Days

题意:

  写作业😭,有n条题目,写k天,但是你有拖延症,必须刚好在第k天写完。同时,每天又不能一题都不写。除第一天外,每天写的题目都必须比前一天至少多1题,而不能大于前一天的2倍,即a[i]<a[i+1]≤2a[i]。如果能满足上述要求,输出YES,以及任何一个可能的序列(按顺序输出每天写了多少题),否则输出NO。

输入:一个正整数n(n≤1e9),你的作业数;一个正整数k(k≤1e5),你写作业的天数。

输出:如果有,第一行输出YES,第二行输出每天做了多少题;如果没有,输出NO。

限制:1s,256M

样例:

input

26 6

output

YES

1 2 4 5 6 8

 

input

8 3

output

NO

样例解释:样例1中26条题目写6天,按1,2,4,5,6,8的数量写就能用6天刚好写完。

     样例2无法满足题目条件(可以试试)。

 

思路:它看起来是一道数学题........实际上它果然是一道数学贪贪贪。根据题目中给出的大于+1和小于2倍的范围限制,我们可以联想到先给每一天依次做1,2,3,4……的公差为1的等差数列的题,作为基座,然后往上不断放题目。很容易看出如果题目数量连建基座都不够,可以直接输出NO。

   考虑继续贪,我们为什么一定要让首项为1呢?所以,平衡地增加基座高度,保持为公差1的等差数列,直到剩下的题目不足以再令所有项+1。例如,10题做3天,这3天的基座就为2,3,4,我们手中剩下1条题目没有放。此时不难发现没放的题目数一定小于天数。为了保证满足题目的升序要求,我们从最后一天开始添加题,直到某一天不能再加(等于上一天的2倍),前往上一天。同时用一个sum记录已经放了多少题目,如果仍剩余却无法再放题,输出NO。

   在最后的贪心阶段中,其实后放的题是会让已经贪完的后一天能继续放题的……但我们手中剩余的题数相对于天数太少,仔细想想这种影响其实是不必考虑的。(个人推算=-=这样NO的情况好像很少,而且数据一大根本不会NO)

代码:

#include<bits/stdc++.h>
#define FastIO ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<b;i++)
#define repp(i,a,b) for(ll i=a;i<=b;i++)
#define rep1(i,a,b) for(ll i=a;i>=b;i--)
#define mem(gv) memset(gv,0,sizeof(gv))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define QAQ 0
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pLL;
const int mod=1e9+7;
const int maxn=2e5+2;

ll n,k,t,base,sum; 
ll a[maxn];
void die(){
    cout<<"NO";
    exit(0);
}

int main(){
    FastIO
    cin>>n>>k;
    base=(k+1)*k/2;
    if(base>n) die();
    t=(n-base)/k;
    repp(i,1,k){
        a[i]=i+t;
        sum+=a[i];
    }
    rep1(i,k,1){
        while(sum<n && a[i]<2*a[i-1]){
            a[i]++;
            sum++;
        }
    }
    if(sum!=n) die();
    cout<<"YES"<<endl;
    repp(i,1,k) cout<<a[i]<<" ";
    return QAQ;
}

 

E. Minimum Array

题意:两个数组a和b,元素个数都为n,数组c中元素的计算规则为第i个元素ci=(ai+bi)%n。按顺序写出数组c中元素。你可以任意调换b数组中元素位置,需要使最后写出来的数字序列字典序最小。

输入:第一行:一个正整数n(n≤2e5);

   第二行:数组a中的元素(均为小于n的自然数);

   第三行:数组b中的元素(均为小于n的自然数)。

输出:数组c中的元素。(字典序最小)

限制:2s,256M

 

样例:

input

4

0 1 2 1

3 2 1 1

output

1 0 0 2

样例解释:将b数组变为1,3,2,1,这样按规则计算出的数组c元素的序列字典序最小。

 

思路:解法很容易想到……比D要容易想到得多,数组a不会动,优先让数组c靠前的元素最小,而根据模的运算规则,数组a中的元素ai的最佳匹配对象是(n-ai)%n,这样c中对应元素就是0。。如果不存在最佳匹配,令最佳数不断加1、模n,直到b中有这样的数存在。这样保证了c的靠前的元素尽量小,也就是字典序最小。

   不熟悉STL的话实现起来有点烦,太暴力了又会T。。实际上用multiset存放数组b,每次lowerbound找想要的数就好,没找到就把迭代器移回开头再lowerbound(0)一下。找到之后删掉这个数。

   要用set自带的lowerbound.....枯了,std的好慢。

代码:

#include<bits/stdc++.h>
#define FastIO ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<b;i++)
#define repp(i,a,b) for(ll i=a;i<=b;i++)
#define rep1(i,a,b) for(ll i=a;i>=b;i--)
#define mem(gv) memset(gv,0,sizeof(gv))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define QAQ 0
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pLL;
const int mod=1e9+7;
const int maxn=2e5+2;

int n,a[maxn],b; 
multiset<int>s;
int main(){
    scanf("%d",&n);
    rep(i,0,n) scanf("%d",&a[i]);
    rep(i,0,n) {
        scanf("%d",&b);
        s.insert(b);
    }
//    for(auto x:s) cout<<x<<endl;
    rep(i,0,n){
        int t=(n-a[i])%n;
        multiset<int>::iterator it=s.lower_bound(t);
        if(it==s.end()){
            it=s.lower_bound(0);
        }
        printf("%d ",(a[i]+*it)%n);
        s.erase(it);
    }
    return QAQ;
}

 

F. Maximum Balanced Circle

题意:

  一堆人排队,每个人有一个身高,现在你来从里面拉出一些人围成一圈,使相邻的两个人身高差小于等于1。你需要使这个圈的人数尽可能大。

输入:第一行:一个正整数n(n≤2e5),表示人数;

   第二行:n个正整数ai(ai≤2e5),表示每个人的身高。

输出:第一行:围成圈的人的个数(尽可能大)。

   第二行:起点和方向(顺、逆)任意选,依次输出圈内各个人的身高。

限制:2s,256M

样例:

input

7

4 3 5 1 2 2 1

output

5

2 1 1 2 3 

样例解释:0.0其实也不需要解释叭,拉出5个人(3,1,2,2,1)围成了满足条件的一个圈。

 

思路:又排队!拿到手先sort贪一波,在纸上画画就会发现想贪出一个环,中间的身高必须得有两个人以上……环嘛,一路排上去,还得一路降回去,比如1,2,3,4,3,2,1,显然中间的身高2和3没有两个人的话就无法连接上两头的1和4了。从而得出两头的身高只要有小于等于1个人就好。

   这个时候发现sort有点不合适了QAQ,这种初步涉及统计重复数量的排序(而题目数据也不大)可以直接上计数排序,显然我们是需要找到一个区间(两头≤1人,中间≥2人),开起两个指针l,r一路跑过去就完事了。

代码:

#include<bits/stdc++.h>
#define FastIO ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<b;i++)
#define repp(i,a,b) for(ll i=a;i<=b;i++)
#define rep1(i,a,b) for(ll i=a;i>=b;i--)
#define miaojie1
#ifdef miaojie
  #define dbg(args...) do {cout << #args << " : "; err(args);} while (0)
#else
  #define dbg(...)
#endif
void err() {std::cout << std::endl;}
template<typename T, typename...Args>
void err(T a, Args...args){std::cout << a << ' '; err(args...);}
#define de(x) cout<<"x="<<x<<endl
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define QAQ 0
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pLL;
const int mod=1e9+7;
const int maxn=2e5+2;

int n,l,r,L,R,cnt,ans,x;
int a[maxn];

int main(){
    scanf("%d",&n);
    repp(i,1,n){
        scanf("%d",&x);
        a[x]++;
    }
    l=1;
    r=1;
    while(r<=maxn){
        if(a[r]>=2){
            cnt=cnt+a[r];
            r++;
        }
        else{
            cnt=cnt+a[r];
            if(cnt>ans){
                ans=cnt;
                L=l;
                R=r;
            }
            cnt=a[r];
            l=r;
            r++;
        }
    }
    dbg(L,R);
    printf("%d\n",ans);
    repp(i,L,R){
        repp(j,1,a[i]/2){
            printf("%d ",i);
        }
    }
    rep1(i,R,L){
        repp(j,1,(a[i]+1)/2){
            printf("%d ",i);
        }
    }
    return QAQ;
}

 

G. Inverse of Rows and Columns

题意:

  给出一个n×m的矩阵,矩阵仅由0和1组成,你可以对该矩阵做任意次操作,每次操作将某一行或某一列的所有元素翻转(0变成1,1变成0),最后需要得出一个非降序矩阵。(非降序矩阵:在一行中按顺序写出矩阵的每一行元素,所有元素排成一个非降序序列)

输入:第一行:两个正整数n,m(n,m≤200)代表行、列数;

   下面n行每行m个数字,表示原矩阵。

输出:如果存在答案,第一行输出YES;第二行由共n个0或1组成的一个字符串,表示每一行是否被操作过。第三行与第二行类似,共m个0或1,表示每一列是否被操作过。(操作过为1)否则输出NO。

限制:2s,256M

样例:

input

2 2

1 1

0 1

output

YES

00

10

样例解释:2×2的矩阵,按顺序写下为1,1,0,1。仅翻转第一列,矩阵变为0,1,1,1,为非降序。

 

思路:想一想最后得到的结果情况只有nm+1种,而本题数据量真的小0.0,暴力枚举On²m²居然可以过。。

  枚举最后得到的矩阵,与原矩阵对应异或,就得到中间矩阵M。M中的1代表这个位置的元素被翻转过,而0代表没有翻转。我们只需要证明M能够通过若干次题目中的操作得到。用数组x、y记录某行、某列是否被翻转,而x、y以第一列、第一行的元素为标准来验证其他元素。

  具体点说,将M中第一列的元素直接赋给x,代表行的翻转情况(根据对称性不必考虑完全与该数组相反的翻转情况,因此可以直接赋值)。将M中第一行的元素直接赋给y,代表列的反转情况,这个时候每个元素需要多异或一个x[1],即考虑第一行翻转对它们的影响。之后遍历其他行列,第i行第j列的元素是否翻转就要看第i行和第j列是否翻转,也就是x[i]和y[j]的值,而不难发现x[i]^y[j]就是该元素的翻转情况。将x[i]^y[j]与M中对应的值对比一下,若不同说明这种无法通过题目操作得到,即无法得到目标矩阵。

代码:

 

#include<bits/stdc++.h>
#define FastIO ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<b;i++)
#define repp(i,a,b) for(ll i=a;i<=b;i++)
#define rep1(i,a,b) for(ll i=a;i>=b;i--)
#define mem(gv) memset(gv,0,sizeof(gv))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define QAQ 0
#define miaojie
#ifdef miaojie
  #define dbg(args...) do {cout << #args << " : "; err(args);} while (0)
#else
  #define dbg(...)
#endif
void err() {std::cout << std::endl;}
template<typename T, typename...Args>
void err(T a, Args...args){std::cout << a << ' '; err(args...);}

using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pLL;
const int mod=1e9+7;
const int maxn=2e5+2;

int n,m;
int a[202][202],b[202][202],x[202],y[202];

bool jd(){
    repp(i,1,n){
        x[i]=a[i][1]^b[i][1];
    //    cout<<x[i]<<endl;
    }
    repp(i,1,m){
        y[i]=a[1][i]^b[1][i]^x[1];
    //    cout<<y[i]<<endl;
    }
    bool f=0;
    repp(i,2,n){
        repp(j,2,m){
            if(a[i][j]^b[i][j]!=x[i]^y[j]){
                f=1;
                break;
            }
        }
        if(f) break;
    }
    if(!f) return true;
    else return false;
}

int main(){
    scanf("%d%d",&n,&m);
    repp(i,1,n){
        repp(j,1,m){
            scanf("%d",&a[i][j]);
            b[i][j]=1;
        }
    }
    repp(i,1,n){
        repp(j,1,m){
            if(jd()){
                printf("YES\n");
                repp(i,1,n){
                    printf("%d",x[i]); 
                }
                printf("\n");
                repp(i,1,m){
                    printf("%d",y[i]);
                }
                return QAQ;
            }
            b[i][j]=0;
        }
    }
    printf("NO\n");
    return QAQ;
}

 

posted on 2019-05-02 11:10  喵杰  阅读(352)  评论(0编辑  收藏  举报