您的位置:首页 > 其它

牛客练习赛13

2018-03-17 10:51 471 查看
A.幸运数字Ⅰ

定义一个数字为幸运数字当且仅当它的所有数位都是4或者7。

比如说,47、744、4都是幸运数字而5、17、467都不是。

现在,给定一个字符串s,请求出一个字符串,使得:

1、它所代表的整数是一个幸运数字;

2、它非空;

3、它作为s的子串(不是子序列)出现了最多的次数(不能为0次)。

请求出这个串(如果有多解,请输出字典序最小的那一个)。

这题做复杂了,其实只用判断是否4和7的个数就行了

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define CLR(a) memset(a, 0, sizeof(a))
#define DBG(x) cout<<(#x)<<"="<<x<<endl
#define FOR(i, a, b)  for(int i=(a); i<(b); i++)
#define REP(i, a, b)  for(int i=(a); i<=(b); i++)
#define DOWN(i, a, b) for(int i=(a); i>=(b); i--)

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1000000009;
const int N= 1e5 +10;

string str, s, ans;
int tmp;
map<string, int> m;

bool judge() {
int len=s.length();
FOR(i, 0, len) {
if (s[i]!='4'&&s[i]!='7') return false;
}
return true;
}

int main() {
cin>>str;
int len=str.length();
FOR(i, 0, len) {
FOR(j, i, len) {
s="";
REP(k, i, j) s+=str[k];
if (judge()) {
m[s]++;
if (m[s]>tmp||m[s]==tmp&&s<ans) {
tmp=m[s];
ans=s;
}
}
}
}
if (!tmp) cout<<-1<<endl;
else cout<<ans<<endl;
//cout<<1.*clock()/CLOCKS_PER_SEC<<"ms"<<"\n";
return 0;
}


B.幸运数字Ⅱ

定义next(x)为大于等于x的第一个幸运数字。给定l,r,请求出next(l) + next(l + 1) + … + next(r - 1) + next(r)。

简单想一下,就会发现连续的next(i)是一样,所以我们只用预处理一下,再求一下分界点,分段求一下和就好了。

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define CLR(a) memset(a, 0, sizeof(a))
#define DBG(x) cout<<(#x)<<"="<<x<<endl
#define FOR(i, a, b)  for(int i=(a); i<(b); i++)
#define REP(i, a, b)  for(int i=(a); i<=(b); i++)
#define DOWN(i, a, b) for(int i=(a); i>=(b); i--)

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1000000009;
const int N= 1e5 +10;

ll l, r;
vector<ll> a;
ll sum
;

void init() {
a.pb(0);
a.pb(4);
a.pb(7);
int st=1, ed=2;
REP(i, 2, 10) {
ll tmp1=4;
ll tmp2=7;
REP(j, 1, i-1) tmp1*=10;
REP(j, 1, i-1) tmp2*=10;
REP(j, st, ed) a.pb(tmp1+a[j]);
REP(j, st, ed) a.pb(tmp2+a[j]);
st=ed+1;
ed+=(1<<i);
}
sum[1]=16;
FOR(i, 2, a.size()) {
// DBG(a[i]);
sum[i]=sum[i-1]+(a[i]-a[i-1])*a[i];
// DBG(sum[i]);
}
}

ll solve(ll n) {
if (!n) return 0;
int pos=lower_bound(a.begin(), a.end(), n) - a.begin() ;
return sum[pos-1]+(n-a[pos-1])*a[pos];
}

int main() {
init();
cin>>l>>r;
cout<<solve(r)-solve(l-1)<<endl;
//cout<<1.*clock()/CLOCKS_PER_SEC<<"ms"<<"\n";
return 0;
}


C.幸运数字Ⅲ

假设现在有一个数字d,现在想在d上重复k次操作。

假设d有n位,用d1,d2,…,dn表示。

对于每次操作,我们想要找到最小的x (x < n),使得dx=4并且dx+1=7。

如果x为奇数,那么我们把dx和dx+1都变成4;

否则,如果x为偶数,我们把dx和dx+1都变成7;

如果不存在x,那么我们不做任何修改。

现在请问k次操作以后,d会变成什么样子。

简单模拟一下就会发现,477会不断循环。

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define CLR(a) memset(a, 0, sizeof(a))
#define DBG(x) cout<<(#x)<<"="<<x<<endl
#define FOR(i, a, b)  for(int i=(a); i<(b); i++)
#define REP(i, a, b)  for(int i=(a); i<=(b); i++)
#define DOWN(i, a, b) for(int i=(a); i>=(b); i--)

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1000000009;
const int N= 1e5 +10;

char a
;
int pos, flag;
ll n, k;

int main() {
cin>>n>>k;
scanf("%s",a+1);
pos=1;
REP(i, 1, k) {
flag=0;
while(pos<n) {
if (a[pos]=='4'&&a[pos+1]=='7') {
flag=1;
break;
}
pos++;
}
if (flag) {
if (pos%2==1) {
a[pos+1]='4';
}
else {
a[pos]='7';
if (pos>1&&a[pos-1]=='4') {
if ((k-i)%2==1) a[pos]='4';
else a[pos]='7';
break;
}
}
}
else break;
}
printf("%s\n",a+1);
//cout<<1.*clock()/CLOCKS_PER_SEC<<"ms"<<"\n";
return 0;
}


D.幸运数字Ⅳ

现在想知道在1…n的第k小的排列中,有多少个幸运数字所在的位置的序号也是幸运数字。

这道题应该是最好的一道题,首先要复习一下康托展开和逆展开,然后还要处理n太大的情况,当n很大时,排列前面的数都是从1开始按顺序排列,而且我们不能把排列存下来,也不需要存下来,因为排列开头的数,序号和对应序号的数是一样的,预处理一下幸运数字记录一下就好了。

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define CLR(a) memset(a, 0, sizeof(a))
#define DBG(x) cout<<(#x)<<"="<<x<<endl
#define FOR(i, a, b)  for(int i=(a); i<(b); i++)
#define REP(i, a, b)  for(int i=(a); i<=(b); i++)
#define DOWN(i, a, b) for(int i=(a); i>=(b); i--)

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1000000009;
const int N= 1e5 +10;

int n, k, t;
ll f
;
bool vis
;
int ans
;
int cnt;
map<ll, int> MP;

void init() {
f[0]=1;
REP(i, 1, 20) f[i]=f[i-1]*i;
}

bool check(ll n) {
int t;
while(n>0) {
t=n%10;
if (t!=4&&t!=7) return false;
n/=10;
}
return true;
}

void dfs(ll n) {
if (n>1e9) return;
if (n) MP
=1;
dfs(n*10+4);
dfs(n*10+7);
}

int main() {
init();
dfs(0);
int ans2=0;
cin>>n>>k;
// REP(i, 1, 30) DBG(f[i]);
int m=min(15, n);
DOWN(i, m, 1) {
t=(k-1)/f[i-1]+1;
k-=(t-1)*f[i-1];
cnt=0;
REP(j, 1, m) {
if (!vis[j]) cnt++;
if (cnt==t) {
if (MP[n+1-i]&&MP[n-m+j]) ans2++;
vis[j]=true;
break;
}
}
}

// REP(i, 1, n) cout<<ans[i]<<' ';
// cout<<endl;
if (n>m) {
for(auto it=MP.begin();it!=MP.end();it++){
if ((*it).first>0&&(*it).first<=n-m) ans2+=(*it).second;
}
}
cout<<ans2<<endl;
//cout<<1.*clock()/CLOCKS_PER_SEC<<"ms"<<"\n";
return 0;
}


E.乌龟跑步

有一只乌龟,初始在0的位置向右跑。

这只乌龟会依次接到一串指令,指令T表示向后转,指令F表示向前移动一个单位。乌龟不能忽视任何指令。

现在我们要修改其中正好n个指令(一个指令可以被改多次,一次修改定义为把某一个T变成F或把某一个F变成T)。

求这只乌龟在结束的时候离起点的最远距离。(假设乌龟最后的位置为x,我们想要abs(x)最大,输出最大的abs(x))

动态规划,dp[i][j][0]和dp[i][j][1],表示前i个指令,修改了j次,分别面向右边和左边时,最右的位置,相应的还有dp2表示最左的位置。

很关键的一个技巧,状态转移取最大值时,用-1或-INF代表不合法状态;状态转移取最小值时,用INF代表不合法状态,很有用。

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define CLR(a) memset(a, 0, sizeof(a))
#define DBG(x) cout<<(#x)<<"="<<x<<endl
#define FOR(i, a, b)  for(int i=(a); i<(b); i++)
#define REP(i, a, b)  for(int i=(a); i<=(b); i++)
#define DOWN(i, a, b) for(int i=(a); i>=(b); i--)

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1000000009;
const int N= 1e2 +10;

int dp

[2];
int dp2

[2];
int t, n;

void go(int i, int j, int k) {
if (dp[i-1][k][1]!=-INF) dp[i][j][1]=max(dp[i-1][k][1]+1,dp[i][j][1]);
if (dp[i-1][k][0]!=-INF) dp[i][j][0]=max(dp[i-1][k][0]-1,dp[i][j][0]);
}
void turn(int i, int j, int k) {
if (dp[i-1][k][1]!=-INF) dp[i][j][0]=max(dp[i-1][k][1],dp[i][j][0]);
if (dp[i-1][k][0]!=-INF) dp[i][j][1]=max(dp[i-1][k][0],dp[i][j][1]);
}

void go2(int i,int j, int k) {
if (dp2[i-1][k][0]!=INF) dp2[i][j][0]=min(dp2[i-1][k][0]-1,dp2[i][j][0]);
if (dp2[i-1][k][1]!=INF) dp2[i][j][1]=min(dp2[i-1][k][1]+1,dp2[i][j][1]);
}
void turn2(int i, int j, int k) {
if (dp2[i-1][k][1]!=INF) dp2[i][j][0]=min(dp2[i-1][k][1],dp2[i][j][0]);
if (dp2[i-1][k][0]!=INF) dp2[i][j][1]=min(dp2[i-1][k][0],dp2[i][j][1]);
}

int main() {
char a
;
scanf("%s",a+1);
cin>>n;
int len=strlen(a+1);

REP(i, 0, len) {
REP(j, 0, n) {
REP(k, 0, 1) {
dp[i][j][k]=-INF;
}
}
}
memset(dp2, 0x3f, sizeof(dp2));
dp[0][0][1]=0;
dp2[0][0][1]=0;

REP(i, 1, len) {
REP(j, 0, n) {
REP(k, 0, j) {
t=j-k;
if (t%2==1) {
if (a[i]=='T') go(i, j, k);
else turn(i, j, k);
}
else {
if (a[i]=='T') turn(i, j, k);
else go(i, j, k);
}
}
// DBG(dp[i][j][1]);
// DBG(dp[i][j][0]);
// DBG(i);
// DBG(j);
}
}

REP(i, 1, len) {
REP(j, 0, n) {
REP(k, 0, j) {
t=j-k;
if (t%2==1) {
if (a[i]=='T') go2(i, j ,k);
else turn2(i, j, k);
}
else {
if (a[i]=='T') turn2(i, j, k);
else go2(i, j, k);
}
}
// DBG(dp2[i][j][1]);
// DBG(dp2[i][j][0]);
// DBG(i);
// DBG(j);
}
}

int ans=-INF;
if (dp[len]
[0]!=-INF) ans=max(abs(dp[len]
[0]), ans);
if (dp[len]
[1]!=-INF) ans=max(abs(dp[len]
[1]), ans);
if (dp2[len]
[0]!=INF) ans=max(abs(dp2[len]
[0]), ans);
if (dp2[len]
[1]!=INF) ans=max(abs(dp2[len]
[1]), ans);
cout<<ans<<endl;
//cout<<1.*clock()/CLOCKS_PER_SEC<<"ms"<<"\n";
return 0;
}


F.m皇后

在一个n*n的国际象棋棋盘上有m个皇后。

一个皇后可以攻击其他八个方向的皇后(上、下、左、右、左上、右上、左下、右下)。

对于某个皇后,如果某一个方向上有其他皇后,那么这个方向对她就是不安全的。

对于每个皇后,我们都能知道她在几个方向上是不安全的。

现在我们想要求出t0,t1,…,t8,其中ti表示恰有i个方向是”不安全的”的皇后有多少个。

这题只要知道那八种方向如何表示,然后记录最大值和最小值,只要小于最大值,最说明”下”不安全;只要大于最小值,就说明”上”不安全,这里上下可以换成其他的相应的方向,这里做的时候傻了,正着扫了一遍,反着有扫了一遍,其实只用扫一遍就可以了。

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define CLR(a) memset(a, 0, sizeof(a))
#define DBG(x) cout<<(#x)<<"="<<x<<endl
#define FOR(i, a, b)  for(int i=(a); i<(b); i++)
#define REP(i, a, b)  for(int i=(a); i<=(b); i++)
#define DOWN(i, a, b) for(int i=(a); i>=(b); i--)

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1000000009;
const int N= 2e6 +10;

int Cmax
, Cmin
;
int Rmax
, Rmin
;
int D1max
, D1min
;
int D2max
, D2min
;
int ok
[8];
int ans[8];
int r
, c
;
int row, col;
int cnt;

int n, m;

void init() {
REP(i, 1, 2*n) {
Cmax[i]=0, Cmin[i]=INF;
Rmax[i]=0, Rmin[i]=INF;
D1max[i]=0, D1min[i]=INF;
D2max[i]=0, D2min[i]=INF;
}
}

int main() {
scanf("%d %d", &n, &m);
REP(i, 1, m) scanf("%d%d", &r[i], &c[i]);
init();
REP(i, 1, m) {
row=r[i];
col=c[i];
if (row<Cmax[col]) ok[i][0]=1;
if (row>Cmin[col]) ok[i][1]=1;
if (col<Rmax[row]) ok[i][2]=1;
if (col>Rmin[row]) ok[i][3]=1;
if (row<D1max[row-col+n]) ok[i][4]=1;
if (row>D1min[row-col+n]) ok[i][5]=1;
if (row<D2max[row+col-1]) ok[i][6]=1;
if (row>D2min[row+col-1]) ok[i][7]=1;

Cmax[col]=max(Cmax[col],row);//下
Cmin[col]=min(Cmin[col],row);//上
Rmax[row]=max(Rmax[row],col);//右
Rmin[row]=min(Rmin[row],col);//左
D1max[row-col+n]=max(D1max[row-col+n],row);//右下
D1min[row-col+n]=min(D1min[row-col+n],row);//左上
D2max[row+col-1]=max(D2max[row+col-1],row);//左下
D2min[row+col-1]=min(D2min[row+col-1],row);//右上

}

init();
DOWN(i, m, 1) {
row=r[i];
col=c[i];
if (row<Cmax[col]) ok[i][0]=1;
if (row>Cmin[col]) ok[i][1]=1;
if (col<Rmax[row]) ok[i][2]=1;
if (col>Rmin[row]) ok[i][3]=1;
if (row<D1max[row-col+n]) ok[i][4]=1;
if (row>D1min[row-col+n]) ok[i][5]=1;
if (row<D2max[row+col-1]) ok[i][6]=1;
if (row>D2min[row+col-1]) ok[i][7]=1;

Cmax[col]=max(Cmax[col],row);//下
Cmin[col]=min(Cmin[col],row);//上
Rmax[row]=max(Rmax[row],col);//右
Rmin[row]=min(Rmin[row],col);//左
D1max[row-col+n]=max(D1max[row-col+n],row);//右下
D1min[row-col+n]=min(D1min[row-col+n],row);//左上
D2max[row+col-1]=max(D2max[row+col-1],row);//左下
D2min[row+col-1]=min(D2min[row+col-1],row);//右上

}

REP(i, 1, m) {
cnt=0;
FOR(j, 0, 8) {
// cout<<ok[i][j]<<' ';
if (ok[i][j]) cnt++;
}
// cout<<endl;
ans[cnt]++;
}

REP(i, 0, 7) cout<<ans[i]<<' ';
cout<<ans[8]<<endl;
//cout<<1.*clock()/CLOCKS_PER_SEC<<"ms"<<"\n";
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: