牛客练习赛13
2018-03-17 10:51
471 查看
A.幸运数字Ⅰ
定义一个数字为幸运数字当且仅当它的所有数位都是4或者7。
比如说,47、744、4都是幸运数字而5、17、467都不是。
现在,给定一个字符串s,请求出一个字符串,使得:
1、它所代表的整数是一个幸运数字;
2、它非空;
3、它作为s的子串(不是子序列)出现了最多的次数(不能为0次)。
请求出这个串(如果有多解,请输出字典序最小的那一个)。
这题做复杂了,其实只用判断是否4和7的个数就行了
B.幸运数字Ⅱ
定义next(x)为大于等于x的第一个幸运数字。给定l,r,请求出next(l) + next(l + 1) + … + next(r - 1) + next(r)。
简单想一下,就会发现连续的next(i)是一样,所以我们只用预处理一下,再求一下分界点,分段求一下和就好了。
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会不断循环。
D.幸运数字Ⅳ
现在想知道在1…n的第k小的排列中,有多少个幸运数字所在的位置的序号也是幸运数字。
这道题应该是最好的一道题,首先要复习一下康托展开和逆展开,然后还要处理n太大的情况,当n很大时,排列前面的数都是从1开始按顺序排列,而且我们不能把排列存下来,也不需要存下来,因为排列开头的数,序号和对应序号的数是一样的,预处理一下幸运数字记录一下就好了。
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代表不合法状态,很有用。
F.m皇后
在一个n*n的国际象棋棋盘上有m个皇后。
一个皇后可以攻击其他八个方向的皇后(上、下、左、右、左上、右上、左下、右下)。
对于某个皇后,如果某一个方向上有其他皇后,那么这个方向对她就是不安全的。
对于每个皇后,我们都能知道她在几个方向上是不安全的。
现在我们想要求出t0,t1,…,t8,其中ti表示恰有i个方向是”不安全的”的皇后有多少个。
这题只要知道那八种方向如何表示,然后记录最大值和最小值,只要小于最大值,最说明”下”不安全;只要大于最小值,就说明”上”不安全,这里上下可以换成其他的相应的方向,这里做的时候傻了,正着扫了一遍,反着有扫了一遍,其实只用扫一遍就可以了。
定义一个数字为幸运数字当且仅当它的所有数位都是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; }
相关文章推荐
- 牛客练习赛13
- 牛客网 牛客练习赛13 - 幸运数字Ⅱ
- 牛客练习赛13-D-幸运数字Ⅳ(康托展开 & 逆康托展开)
- 牛客练习赛13-B,幸运数字2
- 牛客练习赛13 A 幸运数字Ⅰ 【暴力】
- 牛客练习赛13-E-乌龟跑步(DP)
- 牛客练习赛13--幸运数字I II III
- 牛客练习赛13题目题解
- 牛客练习赛13 B 幸运数字Ⅱ 【暴力】【二分】
- 牛客练习赛13-D:幸运数字Ⅳ(思维)
- 牛客练习赛13 幸运数字Ⅱ(BFS,DFS,二分,思路)
- 牛客练习赛13 D 题 幸运数字IV 【康拓逆展开 + 思维】
- 牛客练习赛13-C题幸运数字III
- 牛客练习赛13 A-幸运数字I
- 牛客练习赛13 A B C F【二分+思维】
- 牛客练习赛13 B-幸运数字II
- 牛客练习赛13 --d(逆康拓展开)
- 牛客练习赛13 --E(dp)
- 牛客练习赛13 D 幸运数字Ⅳ[康拓展开逆运算]
- 牛客练习赛13 幸运数系列