2017 Chinese Multi-University Training, BeihangU Contest
A Add More Zero
题目链接
题意:用m个二进制位可以表示10^k,给定m,问k最大是多少
思路:换底计算
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
using ll = long long;
int main() {
int n;
int ca = 0;
while (~scanf("%d", &n)) {
int ans;
ans = (int)ceil(1.0*n*log10(2.0))-1;
printf("Case #%d: %d\n", ++ca,ans);
}
}B Balala Power!
题目链接
题意:将一些字母串转换为26进制的数字,每个字母对应一个数字,要求这些字母转换成数后和最大,并且不能包含前导零
思路:大数比较、模拟、进制转换
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<string>
#include<cmath>
#include<stack>
#include<functional>
#include<bitset>
typedef long long ll;
using namespace std;
const int mod = 1e9 + 7;
char a[100005];
int val[30][100005];
struct node{
int no, score, lead;
}rankk[30], t;
bool cmp(node x,node y){
return x.score > y.score;
}
int main(){
int cas=1,n, maxl;
ll sum;
while(scanf("%d",&n)!=EOF){
for(int i=0;i<26;i++){
rankk[i].no = i;
rankk[i].score = 0;
rankk[i].lead = 0;
}
maxl = 0;
memset(val,0,sizeof val);
for(int i=1;i<=n;i++){
scanf("%s",a);
int len=strlen(a);
maxl = max(maxl,len);
for(int j=0;j<len;j++){
val[a[j]-'a'][len - j - 1]++;
}
rankk[a[0] - 'a'].lead++;
}
for(int i=0;i<26;i++){
for(int j=0;j<maxl-1;j++){
val[i][j+1] += val[i][j] / 26;
val[i][j] %= 26;
}
}
for(int i=0;i<25;i++){
for(int j=i + 1;j<26;j++){
for(int k=maxl-1;k >= 0;k--){
if(val[i][k] > val[j][k]){
rankk[i].score++;
break;
}
else if(val[i][k] < val[j][k]){
rankk[j].score++;
break;
}
}
}
}
sum = 0;
sort(rankk,rankk+26,cmp);
if(rankk[25].lead){
for(int i = 24;i >= 0;i--){
if(!rankk[i].lead){
t = rankk[i];
for(int j = i;j < 25;j++){
rankk[j] = rankk[j + 1];
}
rankk[25] = t;
break;
}
}
}
for(int i=0;i<26;i++){
ll res = 1;
for(int j=0;j<maxl;j++){
sum = (sum + res * (25 - i) % mod * val[rankk[i].no][j]) % mod;
res = res * 26 % mod;
//cout << sum << endl;
}
//cout << sum << endl;
}
printf("Case #%d: %I64d\n",cas++,sum);
}
}F Function
题目链接
题意:求一个n的排列A到m的排列B的映射,要求f(i)=b(f(a(i))),求方案数。
思路:由f(i)可以推知f(a(i)),由于是排列到排列的映射,i->a(i)->a(a(i))...最终一定会回到它自身,从而形成一个环。即a的某个长度为x环可以和b中长度为x因子的环构成函数。
Tarjin求强联通,计算即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn], b[maxn];
int vis[maxn];
vector<int>v, G[maxn];
int c[maxn];
int tuan = 0;
void dfs(int x) {
//cout << "dfs: " << x << endl;
tuan++;
if (vis[b[x]] == -1) {
vis[b[x]] = 1;
dfs(b[x]);
}
}
int dfn[maxn], low[maxn], ins[maxn], stk[maxn];
int num = 0, top = 0, cnt = 0;
void tarjan(int x) {
dfn[x] = low[x] = ++num;
stk[++top] = x;
ins[x] = 1;
for (int y : G[x]) {
if (!dfn[y]) {
tarjan(y);
low[x] = min(low[x], low[y]);
}
else if (ins[y]) {
low[x] = min(low[x], dfn[y]);
}
}
if (dfn[x] == low[x]) {
cnt++;
int yy;
do {
yy = stk[top--]; ins[yy] = 0;
c[yy] = cnt;
} while (x != yy);
}
}
unordered_map <int, int>book;
int n, m;
void init() {
num = 0, top = 0, cnt = 0;
for (int i = 0; i <= n; i++) {
c[i] = 0;
G[i].clear();
dfn[i] = 0;
}
book.clear();
v.clear();
}
int main() {
int cas=1;
while (~scanf("%d%d", &n, &m)) {
init();
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
for (int i = 0; i < m; i++) {
scanf("%d", &b[i]);
}
memset(vis, -1, sizeof vis);
for (int i = 0; i < m; i++) {
//cout << "YYY" << endl;
if (vis[i]==-1) {
vis[i] = 1;
tuan = 0;
dfs(i);
v.push_back(tuan);
}
}
for (int i : v) {
// cout << "array b: " << i << endl;
book[i]++;
}
for (int i = 0; i < n; i++) {
G[a[i]].push_back(i);
}
for (int i = 0; i < n; i++) {
if (!dfn[i])tarjan(i);
}
unordered_map<int, int>mp;
int ma = 0;
for (int x = 0; x < n; x++) {
for (int y : G[x]) {
if (c[x] == c[y]) {
mp[c[x]]++;
}
}
}
long long ans = 1;
for (auto p : mp) {
long long res=0;
for (int i = 1; i <= sqrt(p.second); i++) {
if (p.second%i == 0) {
if(book[i])
res += book[i]*i;
if (i == p.second / i)continue;
if(book[p.second/i])
res+= book[p.second/i] * (p.second/i);
}
}
ans*=res;
// cout << " YYY : " << p.first << " " << p.second << endl;
}
printf("Case #%d: ",cas++);
printf("%lld\n", ans);
}
}
/*
3 2
1 0 2
0 1
3 4
2 0 1
0 2 3 1
6 4
2 0 1 0 5 4
0 2 3 1
*/
K KazaQ's Socks
题目链接
题意:一个1-n的序列,每次选一个最小的放进暂存区,当暂存区有n-1个数时,下一次取数后把这n-1个数再放回序列,问第k次取的是多少
思路:模样例,找规律
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll n,m;
void solve(){
if(m<n){
printf("%lld\n",m);
}else{
m-=n;
ll a=m/(n-1);
ll b=m%(n-1);
if(b==0)
a--;
if(a%2==0)
if(b==0)
printf("%lld\n",n-1);
else
printf("%lld\n",b);
else{
if(b==0)
printf("%lld\n",n);
else
printf("%lld\n",b);
}
}
}
int main(){
int cas=1;
while(scanf("%lld%lld",&n,&m)!=EOF){
printf("Case #%d: ",cas++);
solve();
}
}L Limited Permutation
题目链接
题意:对于每个下标给定一个区间[li,ri]表示对于此区间中最小值为pi,且pi为[li,ri]的最小值,li和ri都不能再扩张。求满足的排列种类数
思路:对于1来说,其区间一定为[1,n]。我们根据下标将其分为左右两个区间,组合数+递归计算。但直接递归会爆栈,通过排序区间,在区间上进行dfs。注意不满足情况的输出值为0。
#include <bits/stdc++.h>
#define maxn 1000005
typedef long long ll;
using namespace std;
const int MOD=1000000007;
struct node{
int l,r;
int index;
}q[maxn];
int n;
ll fac[maxn];
ll inv[maxn];
ll invfac[maxn];
void init()
{
fac[1]=1;inv[1]=1;invfac[1]=1;
fac[0]=1;inv[0]=1;invfac[0]=1;
for(int i=2;i<=1000000;i++)
{
fac[i]=fac[i-1]*i%MOD;
inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
invfac[i]=invfac[i-1]*inv[i]%MOD;
}
}
ll C(int n,int m)
{
return fac[n]*invfac[m]%MOD*invfac[n-m]%MOD;
}
bool cmp(node a,node b){
if(a.l==b.l)
return a.r>b.r;
return a.l<b.l;
}
int cnt=1;
ll dfs(int l,int r){
// cout<<l<<' '<<r<<' '<<q[cnt].l<<' '<<q[cnt].r<<endl;
if(l!=q[cnt].l||r!=q[cnt].r) return 0;
int mid=q[cnt].index;
cnt++;
if(l==r) return 1;
ll ans=1;
ans=ans*C(r-l,mid-l)%MOD;
if(l<mid)
ans=ans*dfs(l,mid-1)%MOD;
if(r>mid)
ans=ans*dfs(mid+1,r)%MOD;
return ans%MOD;
}
void input(){
for(int i=1;i<=n;i++){
// q[i].l=i;
scanf("%d",&q[i].l);
}
for(int i=1;i<=n;i++){
// q[i].r=n;
scanf("%d",&q[i].r);
q[i].index=i;
}
}
void solve(){
sort(q+1,q+1+n,cmp);
cnt=1;
ll ans=dfs(1,n)%MOD;
printf("%lld\n",ans);
}
int main(){
init();
int cas=1;
while(scanf("%d",&n)!=EOF){
input();
printf("Case #%d: ",cas++);
solve();
}
}
京公网安备 11010502036488号