2017-10-1 清北刷题冲刺班a.m
位运算1
(bit)
Time Limit:1000ms Memory Limit:128MB
题目描述
LYK拥有一个十进制的数N。它赋予了N一个新的意义:将N每一位都拆开来后再加起来就是N所拥有的价值。例如数字123拥有6的价值,数字999拥有27的价值。
假设数字N的价值是K,LYK想找到一个价值是K-1的数字,当然这个答案实在太多了,LYK想使得这个价值为K-1的数字尽可能大。
输入格式(bit.in)
一个数N。
输出格式(bit.out)
一个数表示答案。你需要输出一个非负整数,且这个数不包含前导0。
输入样例1
199
输出样例1
198
输入样例2
1000
输出样例2
0
对于20%的数据n<=10
对于40%的数据n<=100
对于60%的数据n<=1000
对于100%的数据1<=n<=100000。
#include<iostream> #include<cstdio> using namespace std; #define maxn 10 int n,bit[maxn],len; int main(){ freopen("bit.in","r",stdin);freopen("bit.out","w",stdout); scanf("%d",&n); while(n){ bit[++len]=n%10; n/=10; } int now=1; while(bit[now]==0)now++; bit[now]--; while(bit[len]==0&&len>=1)len--; if(len==0)printf("0"); else for(int j=len;j>=1;j--)printf("%d",bit[j]); fclose(stdin);fclose(stdout); return 0; }
火柴棒
(stick)
Time Limit:1000ms Memory Limit:128MB
题目描述
众所周知的是,火柴棒可以拼成各种各样的数字。具体可以看下图:
通过2根火柴棒可以拼出数字“1”,通过5根火柴棒可以拼出数字“2”,以此类推。
现在LYK拥有k根火柴棒,它想将这k根火柴棒恰好用完,并且想知道能拼出的最小和最大的数分别是多少。
输入格式(stick.in)
一个数k。
输出格式(stick.out)
两个数,表示最小的数和最大的数。注意这两个数字不能有前导0。
输入样例
15
输出样例
108 7111111
数据范围
对于30%的数据k<=10。
对于60%的数据k<=20。
对于100%的数据1<k<=100。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int now,anslen=0x7fffffff,ans[101],sum[10]; bool anspre; struct node{ int num,cost,cnt; }q[10]; void dfs(int len,int res){ if(len>anslen)return; if(res==0){ bool flag=0; if(anslen>len)flag=1; if(q[6].cnt==len)return; anslen=len; int lennow=0,ansnow[101]; for(int i=1;i<=7;i++)sum[i]=q[i].cnt; //for(int i=1;i<=7;i++)cout<<sum[i]<<" "; for(int i=2;i<=7;i++){ if(sum[i]){ lennow=lennow+1; ansnow[lennow]=q[i].num,sum[i]--; break; } } for(int i=1;i<=7;i++) while(sum[i]){ lennow=lennow+1; ansnow[lennow]=q[i].num,sum[i]--; } for(int i=1;i<=lennow;i++){ if(ans[i]>ansnow[i]){ flag=1;break; } } if(!anspre)flag=1; //cout<<anslen<<' ';cout<<endl; if(flag==1){ for(int i=1;i<=anslen;i++)ans[i]=ansnow[i]; anspre=1; } //for(int i=1;i<=anslen;i++)cout<<ansnow[i];cout<<endl; return; } for(int i=1;i<=7;i++){ if(res-q[i].cost>=0){ q[i].cnt++; dfs(len+1,res-q[i].cost); q[i].cnt--; } } } bool cmp(node x,node y){ return x.num<y.num; } int main(){ //freopen("Cola.txt","r",stdin); freopen("stick.in","r",stdin);freopen("stick.out","w",stdout); q[1].num=0,q[1].cost=6; q[2].num=1,q[2].cost=2; q[3].num=2,q[3].cost=5; q[4].num=4,q[4].cost=4; q[5].num=6,q[5].cost=6; q[6].num=7,q[6].cost=3; q[7].num=8,q[7].cost=7; scanf("%d",&now); dfs(0,now); for(int i=1;i<=anslen;i++)printf("%d",ans[i]); printf(" "); if(now%2==1){ int num=(now-3)/2; printf("7"); for(int i=1;i<=num;i++)printf("1"); } else { int num=now/2; for(int i=1;i<=num;i++)printf("1"); } fclose(stdin);fclose(stdout); return 0; }
/* 最大值直接特判一下,最小值用dp解决 dp[i]表示i根火柴能拼出的最小的数字,枚举该数字末尾的一位是几 */ #include <cmath> #include <cstdio> #include <cstdlib> #include <iostream> #include <algorithm> #include <string> #include <cstring> #include <map> #include <vector> #include <set> using namespace std; long long dp[105]; int f[15],n; int main() { freopen("stick.in","r",stdin); freopen("stick.out","w",stdout); f[1]=2; f[2]=5; f[3]=5; f[4]=4; f[5]=5; f[6]=6; f[7]=3; f[8]=7; f[9]=6; f[0]=6; dp[2]=1; dp[3]=7; dp[4]=4; dp[5]=2; dp[6]=6;dp[7]=8; for (int i=8; i<=100; i++) { dp[i]=dp[i-f[0]]*10; for (int j=0; j<=9; j++) if (dp[i-f[j]]!=0) dp[i]=min(dp[i],dp[i-f[j]]*10+j); } cin>>n; cout<<dp[n]<<' '; if (n%2==1) {cout<<7; n-=3;} while (n){cout<<1; n-=2;} return 0; }
听音乐
(music)
Time Limit:1000ms Memory Limit:128MB
题目描述
LYK喜欢听音乐,总共有n首音乐,有m个时刻,每个时刻LYK会听其中一首音乐,第i个时刻会听第ai首音乐。它给自己定了一个规定,就是从听音乐开始,听的每连续n首音乐都是互不相同的。例如当n=3时,从听歌开始,123321就是一个合法的顺序(此时LYK听了两轮歌,分别是123和321,每一轮的歌都是互不相同的),而121323就是一个不合法的顺序(LYK也听了两轮歌,第一轮中121存在听了两次相同的歌)。我们现在只截取其中一个片段,也就是说并不知道LYK之前已经听了什么歌。因此121323也仍然可以是一个合法的顺序,因为LYK之前可能听过3,然后再听121323,此时LYK听了三轮歌,分别是312,132和3。
现在LYK将告诉你这m个时刻它听的是哪首歌。你需要求出LYK在听这m首歌之前可能听过的歌的不同方案总数(我们认为方案不同当且仅当之前听过的歌的数量不同)。LYK向你保证它之前听过的歌的数量是在0~n-1之间的。因此你输出的答案也应当是0~n中的某个整数(答案是0表示LYK记错了,没有一个合法的方案)。
输入格式(music.in)
第一行两个数n,m。
第二行m个数表示ai。
输出格式(music.out)
一个数表示答案。
输入样例1
4 10
3 4 4 1 3 2 1 2 3 4
输出样例1
1
样例解释1:LYK之前一定只听过2首歌(12或者21),这样可以分成3部分分别是34,4132,1234,每一部分都没有出现相同的歌。对于其它情况均不满足条件。
输入样例2
6 6
6 5 4 3 2 1
输出样例2
6
样例解释2:LYK之前听过0~5首歌的任意几首都是有可能满足条件的。
数据范围
对于50%的数据n,m<=1000。
对于100%的数据1<=n,m<=100000,1<=ai<=n。
其中均匀分布着n<m以及n>=m的情况。
提示:
LYK知道这个题目很长,但为了便于理解已经加了很多注释了……建议没看懂的同学们再重新看一遍……
#include<iostream> #include<cstdio> #define maxn 100010 using namespace std; int n,m,a[maxn],ans; bool vis[maxn]; int main(){ //freopen("Cola.txt","r",stdin); freopen("music.in","r",stdin);freopen("music.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++)scanf("%d",&a[i]); for(int i=0;i<n;i++){//枚举之前听过的歌的数量 bool flag=0; for(int j=1;j<=n-i;j++){ if(vis[a[j]]){ flag=1; break; } vis[a[j]]=1; } for(int j=1;j<=n-i;j++)vis[a[j]]=0; if(flag)continue; for(int j=n-i+1;j<=m;j+=n){//区间起点 for(int k=j,l=1;k<=m&&l<=n;k++,l++){ if(vis[a[k]]){ flag=1; break; } vis[a[k]]=1; } for(int k=j,l=1;k<=m,l<=n;k++,l++)vis[a[k]]=0; if(flag)break; } if(!flag)ans++; } printf("%d",ans); fclose(stdin);fclose(stdout); return 0; }
#include<iostream> #include<cstdio> #include<cstdlib> #define maxn 100010 using namespace std; int t[maxn],v1[maxn],v2[maxn],a[maxn]; int n,m,sum,ans; bool OK(int x){ int i; for(i=x-n+1;i>=1;i-=n) if(!v2[i])return false; i+=n; if(i-1>0&&!v1[i-1])return false; return true; } int main(){ freopen("music.in","r",stdin);freopen("music.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++)t[i]=0;sum=0; for(int i=1;i<=min(n,m);i++){ t[a[i]]++; if(t[a[i]]==2)sum++; if(!sum)v1[i]=1; else v1[i]=0; } if(!sum)v2[1]=1;else v2[1]=0; for(int i=n+1;i<=m;i++){ t[a[i]]++; if(t[a[i]]==2)sum++; t[a[i-n]]--; if(t[a[i-n]]==1)sum--; if(!sum)v2[i-n+1]=1; else v2[i-n+1]=0; } for(int j=1;j<=n;j++)t[j]=0;sum=0; int j; for(j=m;j>=1;j--){ t[a[j]]++; if(t[a[j]]>=2)break; } for(int i=m;i>max(0,m-n);i--){ if(j<=i) if(OK(i))ans++; } if(ans)printf("%d\n",((n>=m&&ans==m)?n:ans)); else printf("0"); return 0; }