1001
题意:
给定m,求最大的k满足10^k<2^m
分析:
显然kmax=log10(2^m-1), 但m太大,直接计算2^m-1不现实,log10(2^m)计算很方便,
Log10 (2^m)=m*log10(2),我们发现只有当x(x=2^m)末位为0时,log10(2^m)!=log10(2^m-1),但x作为2的幂,末位必不为0,所以log10(2^m)=log10(2^m-1),那么ans=m*log10(2)。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<iostream>
#include<algorithm>
#define LL unsigned long long
#define debug puts("Infinity is awesome!")
#define mm(a, b) memset(a, b, sizeof(a))
#define rep(a, b, c) for(int a=b;a<c;a++)
#define rerep(a, b, c) for(int a=b;a>=c;a--)
#define reset(a, b) memset(a, b, sizeof(a))
using namespace std;
const int Inf=1e9;
const int MOD=1e9+7;
int m;
int main(){
int cas=0;
while(~scanf("%d", &m)){
double ans=m*log(2)/log(10);
printf("Case #%d: %d\n", ++cas, (LL)ans);
}
return 0;
}
1002
题意:
给定n个字符串,找出一种从’a’-’z’到0-25的映射,使得所有字符串之和最大,但映射必须满足字符串不会出现前导0
分析:
统计所有字符串中各字符的出现次数,不同位置赋予不同权值,按权值给字符排序,最后权值和大的字符赋予大的映射值,前导0的问题,记录下所有首字符,按权值从小到大对字符进行遍历,找到第一个非首字符,将其映射值赋成0,其余字符按权值大小赋映射值大小即可。
3 Submits
第一次:没有对权值进行进位处理
第二次:数组未清零
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<iostream>
#include<algorithm>
#define LL unsigned long long
#define debug puts("Infinity is awesome!")
#define mm(a, b) memset(a, b, sizeof(a))
#define rep(a, b, c) for(int a=b;a<c;a++)
#define rerep(a, b, c) for(int a=b;a>=c;a--)
#define reset(a, b) memset(a, b, sizeof(a))
using namespace std;
const int Inf=1e9;
const LL MOD=1e9+7;
const int maxn=1e6+100;
const int maxl=1e5+100;
int m;
char s[maxn];
int cnt[26][maxl];
int l[maxl], r[maxl];
int a[26], vis[26], ishead[26];
int mp[26];
int maxlen;
bool cmp(int a,int b){
if(vis[a]!=vis[b]) return vis[a]<vis[b];
if(vis[a]==vis[b]&&!vis[a]) return true;
for(int i=maxlen-1;i>=0;i--)
if(cnt[a][i]!=cnt[b][i])
return cnt[a][i]<cnt[b][i];
return true;
}
int main(){
int cas=0;
int n;
while(~scanf("%d", &n)){
int sp=0;
maxlen=0;
mm(vis, 0); mm(ishead, 0);
mm(cnt, 0);
for(int i=0;i<n;i++){
scanf("%s",s+sp);
ishead[s[sp]-'a']=1;
l[i]=sp, r[i]=sp+strlen(s+sp)-1;
maxlen=max(maxlen, (int)strlen(s+sp));
for(int j=l[i];j<=r[i];j++){
cnt[s[j]-'a'][r[i]-j]++;
vis[s[j]-'a']=1;
}
sp=r[i]+1;
}
for(int i=0;i<26;i++){
for(int j=0;j<maxlen;j++)
if(cnt[i][j]>=26){
cnt[i][j+1]+=cnt[i][j]/26;
cnt[i][j]%=26;
}
if(cnt[i][maxlen]) maxlen++;
if(cnt[i][maxlen-1]>=26){
cnt[i][maxlen]+=cnt[i][maxlen-1]/26;
cnt[i][maxlen]%=26;
maxlen++;
}
}
for(int i=0;i<26;i++) a[i]=i;
for(int i=0;i<26;i++)
for(int j=i+1;j<26;j++)
if(!cmp(a[i], a[j])) swap(a[i], a[j]);
if(ishead[a[0]]){
int p;
for(int i=0;i<26;i++)
if(!ishead[a[i]]){
p=i;
break;
}
int tmp=a[p];
for(int i=p;i>0;i--)
a[i]=a[i-1];
a[0]=tmp;
}
for(int i=0;i<26;i++)
mp[a[i]]=i;
// for(int i=0;i<26;i++)
// printf("%c %d\n", 'a'+i, mp[i]);
LL ans=0;
for(int i=0;i<n;i++){
LL tmp=0;
for(int j=l[i];j<=r[i];j++){
tmp=tmp*26%MOD;
int x=s[j]-'a';
tmp=(tmp+mp[x])%MOD;
}
ans=(ans+tmp)%MOD;
}
printf("Case #%d: %lld\n", ++cas, ans);
}
return 0;
}
1011
题意:共有n双袜子,每天早上都选干净区袜子里编号最小的来穿,每天晚上穿过的袜子放入待洗区,当待洗的袜子达到n-1双时会统一洗一次,洗完后会在次日晚上放入干净区。
问第k天穿的袜子的编号?
分析:
观察k的范围,显然O(n)的算法都不能满足要求,那么可能O(1)?这意味着答案是有规律的。稍加分析样例发现,前n天穿的袜子分别是1~n,之后n-1天穿的是1~n-2,n-1,再之后n-1天穿的是1~n-2,n,然后后两者交替出现。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<iostream>
#include<algorithm>
#define LL unsigned long long
#define debug puts("Infinity is awesome!")
#define mm(a, b) memset(a, b, sizeof(a))
#define rep(a, b, c) for(int a=b;a<c;a++)
#define rerep(a, b, c) for(int a=b;a>=c;a--)
#define reset(a, b) memset(a, b, sizeof(a))
using namespace std;
const int Inf=1e9;
const int MOD=1e9+7;
int m;
int main(){
int cas=0;
LL n, k;
while(~scanf("%lld%lld", &n, &k)){
LL ans;
if(k<=n) ans=k;
else{
k-=n;
LL x=k/(n-1), y=k%(n-1);
if((x%2&&!y)||(!x%2&&y)){
if(y) ans=y;
else ans=n-1;
}else{
if(y) ans=y;
else ans=n;
}
}
printf("Case #%d: %d\n", ++cas, ans);
}
return 0;
}
补题:
1003
题意:
定义两个点之间的路径值为这条路径上不同颜色结点的个数,求树上所有路径值之和。
分析:
暂认为n个值对所有路径都是有贡献的,再枚举颜色(1~n),求取不包含这个颜色的路径数,减之,最后可得答案。
dfs处理出所有结点的覆盖范围(L, R),
求取一种颜色c的无贡献值,枚举颜色为c的结点u,在u的子树中依次找L最小的同色结点v,那么在u、v之间的所有结点中任取两点构成的路径都是不含颜色c的。
观察下图,
枚举颜色c=1时,u=1,左子树没有同色,按照上述方法不减,右子树5号的结点同色,那么减去以5号结点为根的树结点个数,右子树9号结点同色,同样减去,那么右子树中无效路径已求得。
但左子树中也存在不包含c=1的路径,可上述过程并没有减去,
解决方法是加一个虚结点0,0只连向1号点,每次枚举颜色c时,将虚结点的颜色也赋为c,那么整棵树也成为了一颗子树,在枚举到虚结点时,左子树的无效路径将被减去。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<iostream>
#include<algorithm>
#define mm(a,b) memset(a, b, sizeof(a))
#define LL long long
using namespace std;
const int maxn=2e5+50;
struct Edge{
int to, next;
};
Edge edges[2*maxn];
int head[maxn], siz[maxn];
int ecnt;
int L[maxn], R[maxn];
int c[maxn], fa[maxn];
vector<int> pos[maxn];
vector<int>::iterator it;
int n;
void Init(){
mm(head, -1);
ecnt=0;
for(int i=1;i<=n;i++) pos[i].clear();
}
void Add_Edge(int u,int v){
edges[ecnt]=Edge{v, head[u]};
head[u]=ecnt++;
}
void Dfs(int u,int f,int &cnt){
L[u]=++cnt; fa[u]=f;
siz[u]=1;
for(int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
if(v==f) continue;
Dfs(v, u, cnt);
siz[u]+=siz[v];
}
R[u]=cnt;
}
bool cmp(const int &a,const int &b){
return L[a]<L[b];
}
int main(){
int cas=0;
int u, v;
while(~scanf("%d", &n)){
Init();
for(int i=1;i<=n;i++){
scanf("%d", &c[i]);
pos[c[i]].push_back(i);
}
for(int i=1;i<=n-1;i++){
scanf("%d%d",&u, &v);
Add_Edge(u, v);
Add_Edge(v, u);
}
Add_Edge(0, 1);
int cnt=0;
Dfs(0, -1, cnt);
LL ans=1LL*n*(n-1)/2*n;
for(int i=1;i<=n;i++){
if(pos[i].size()==0){
ans-=1LL*n*(n-1)/2;
continue;
}
pos[i].push_back(0);
sort(pos[i].begin(), pos[i].end(), cmp);
for(int j=0;j<pos[i].size();j++){
u=pos[i][j];
for(int k=head[u];k!=-1;k=edges[k].next){
int v=edges[k].to;
if(v==fa[u]) continue;
int size=siz[v];
int id=L[v];
while(1){
L[n+1]=id;
it=lower_bound(pos[i].begin(), pos[i].end(), n+1, cmp);
if(it==pos[i].end()||L[*it]>R[v]) break;
size-=siz[*it];
id=R[*it]+1;
}
ans-=1LL*size*(size-1)/2;
}
}
}
printf("Case #%d: %lld\n", ++cas, ans);
}
return 0;
}
1008
题意:
给出一个函数,按照该函数能够构造出前n项的值,m个询问,查询第bi小的值。
分析:
首先m是不大的,其次,bi彼此之间还存在一定的关系,当满足bi!=bj,bi<bk且bj< bk时,bi+bj<=bk,那么最差的情况下b取值为0,1,2,3,5,8…斐波那契…,那么sum(bi)的大小可以估计是O(n)的。
利用STL中nth_element函数,其平均复杂度为O(n),这里的n是指查找的范围长度,不是题目给出的n。我们先查找大的bi,可以做到逐步缩小范围,所以总体复杂度仍是O(n)。
nth_element输入3个参数,起始位置,需要查找的第k小,终止位置。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<iostream>
#include<algorithm>
#define mm(a,b) memset(a, b, sizeof(a))
#define LL long long
using namespace std;
unsigned x, y, z;
unsigned rng61(){
unsigned t;
x^=x<<16;
x^=x>>5;
x^=x<<1;
t=x;
x=y;
y=z;
z=t^x^y;
return z;
}
const int maxp=105;
int pos[maxp], id[maxp];
const int maxn=1e7+50;
unsigned a[maxn], ans[maxp];
bool cmp(const int &a,const int &b){
return pos[a]<pos[b];
}
int main(){
int cas=0;
int n, m;
unsigned A, B, C;
while(~scanf("%d%d%u%u%u",&n, &m, &A, &B, &C)){
x=A, y=B, z=C;
for(int i=0;i<m;i++){
scanf("%d",&pos[i]);
id[i]=i;
}
for(int i=0;i<n;i++){
a[i]=rng61();
}
sort(id, id+m, cmp);
pos[id[m]=m]=n;
for(int i=m-1;i>=0;i--){
if(pos[id[i]]==pos[id[i+1]]){
ans[id[i]]=ans[id[i+1]];
continue;
}
nth_element(a, a+pos[id[i]], a+pos[id[i+1]]);
ans[id[i]]=a[pos[id[i]]];
}
printf("Case #%d: ", ++cas);
for(int i=0;i<m;i++)
printf("%u%c", ans[i], i==m-1?'\n':' ');
}
return 0;
}
1012
题意:
给出n个区间,1~n的排列P满足pi只在区间[Li, Ri]内是最小值,一旦超出这个范围便不再是最小值,这样的排列有多少种?
分析:
首先肯定存在一个区间[1,n], 那么这个区间的编号i把区间[1,n]分成了[1,i-1]和[i+1,n],同理给定区间中也必须存在这两个区间,否则题目是无解的。可以通过递归寻找合法区间。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<list>
#include<numeric>
using namespace std;
#define PI acos(-1.0)
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
template<class T> T f_abs(T a){ return a > 0 ? a : -a; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
// 0x3f3f3f3f3f3f3f3f
// 0x3f3f3f3f
namespace fastIO {
#define BUF_SIZE 100000
//fread -> read
bool IOerror = 0;
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if(p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if(pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
inline void read(int &x) {
char ch;
while(blank(ch = nc()));
if(IOerror)
return;
for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
}
#undef BUF_SIZE
};
using namespace fastIO;
const int maxn=1e6+50;
const LL mod=1e9+7;
struct Node{
int L, R, len, id;
bool operator <(const Node &rhs)const{
if(L==rhs.L) return len>rhs.len;
return L<rhs.L;
}
};
Node nod[maxn];
vector<Node> st[maxn];
LL fac[maxn], inv[maxn];
LL ans;
int BinSearch(int s,int len){
if(st[s].size()==0) return -1;
int l=0, r=st[s].size()-1;
while(l<=r){
int m=(l+r)>>1;
if(st[s][m].len==len) return m;
if(st[s][m].len<len) l=m+1;
else r=m-1;
}
return -1;
}
LL PowMod(LL x,int p){
LL ret=1;
while(p){
if(p&1) ret=ret*x%mod;
p>>=1;
x=x*x%mod;
}
return ret;
}
void PreProcess(){
fac[0]=inv[0]=1;
for(int i=1;i<maxn;i++)
fac[i]=fac[i-1]*i%mod;
inv[maxn-1]=PowMod(fac[maxn-1], mod-2);
for(int i=maxn-2;i>=0;i--)
inv[i]=inv[i+1]*(i+1)%mod;
}
LL Com(int i,int j){
return fac[i]*inv[j]%mod*inv[i-j]%mod;
}
bool flag;
bool Solve(int L,int R){
if(!flag) return false;
if(L>R) return true;
int len=R-L+1;
int pos=BinSearch(L, len);
if(pos==-1) return flag=false;
//printf("%d %d %d\n",L, R, st[L][pos].id);
if(!Solve(L, st[L][pos].id-1)) return flag=false;
if(!Solve(st[L][pos].id+1, R)) return flag=false;
ans=ans*Com(len-1, st[L][pos].id-L)%mod;
return true;
}
int main(){
int cas=0;
int n;
//freopen("1012.in", "r", stdin);
//freopen("a.out", "w", stdout);
//scanf("%d",&T);
PreProcess();
while(read(n),!IOerror){
for(int i=0;i<n;i++){
read(nod[i].L);
st[i+1].clear();
}
for(int i=0;i<n;i++){
read(nod[i].R);
//scanf("%d%d",&nod[i].L, &nod[i].R);
nod[i].len=nod[i].R-nod[i].L+1;
nod[i].id=i+1;
}
sort(nod, nod+n);
for(int i=n-1;i>=0;i--){
st[nod[i].L].push_back(nod[i]);
}
ans=1; flag=true;
if(!Solve(1, n)) ans=0;
printf("Case #%d: %lld\n",++cas, ans);
}
return 0;
}