A. Picking Numbers(水题)
https://www.hackerrank.com/contests/101hack44/challenges/picking-numbers
题目大意:
给你个数组,问至多有几个数,其中两两相差不到1.
题目分析:
反正数组长度才100, O(n2) 随便一搞即可。
#include <bits/stdc++.h>
using namespace std;
#define RE(x) freopen(x,"r",stdin)
#define WR(x) freopen(x,"w",stdout)
#define ms(x,y) memset(x,y,sizeof(x))
#define pb push_back
#define mp make_pair
#define INF 0x3f3f3f3f
#define eps 1e-8
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
typedef vector<ll> vl;
const int M = 1e9 + 7;
const double PI = acos(-1.0);
const int MAXN = 1e5 + 5;
const int MAXM = 1e6 + 5;
int main() {
//RE("in.txt");WR("out.txt");
int n;
int a[105];
cin>>n;
for (int i = 0; i < n; i++)
cin>>a[i];
sort(a,a+n);
int ans=0;
for(int i=0;i<n;i++) {
int temp=1;
for(int j=i+1;j<n;j++) {
if(a[j]-a[i]<=1)
temp++;
}
ans=max(ans,temp);
}
cout<<ans<<endl;
}
B.Alice and Bob’s Silly Game(素数统计)
https://www.hackerrank.com/contests/101hack44/challenges/alice-and-bobs-silly-game
题目大意:
有一个集合{1,2,…n},A和B两人轮流从中选一个素数,删去集合中所有该素数的倍数,无法操作者输。问谁赢?
题目分析:
其实就是统计小于n的素数有多少个,之前沈阳赛区有道题可以统计出1e11的,那么本题的1e5自然不在话下,直接套用hdu 5901题模板即可。
#include <bits/stdc++.h>
using namespace std;
#define RE(x) freopen(x,"r",stdin)
#define WR(x) freopen(x,"w",stdout)
#define ms(x,y) memset(x,y,sizeof(x))
#define pb push_back
#define mp make_pair
#define INF 0x3f3f3f3f
#define eps 1e-8
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
typedef vector<ll> vl;
const int M = 1e9 + 7;
const double PI = acos(-1.0);
const int MAXN = 1e5 + 5;
const int MAXM = 1e6 + 6;
ll f[340000],g[340000],n;
void init(){
ll i,j,m;
for(m=1;m*m<=n;++m)f[m]=n/m-1;
for(i=1;i<=m;++i)g[i]=i-1;
for(i=2;i<=m;++i){
if(g[i]==g[i-1])continue;
for(j=1;j<=min(m-1,n/i/i);++j){
if(i*j<m)f[j]-=f[i*j]-g[i-1];
else f[j]-=g[n/i/j]-g[i-1];
}
for(j=m;j>=i*i;--j)g[j]-=g[j/i]-g[i-1];
}
}
int main(){
int t;
cin>>t;
while(t--){
cin>>n;
init();
if(f[1]&1)
cout<<"Alice"<<endl;
else
{
cout<<"Bob"<<endl;
}
}
return 0;
}
C.Expected Tree Leaves(概率与期望)
https://www.hackerrank.com/contests/101hack44/challenges/expected-tree-leaves
题目大意:
从一个点1开始,每次随机选择一个点,在其后面连一个点,重复n次。
设叶子节点个数的期望为E,求 (E⋅n!) mod (1e9+7 ).
题目分析:
首先证明 E=n/2 :
设点i是叶子节点的概率为
Pi
,则
那么点i是叶子节点,当且仅当i+1到n号点都不跟i相连,其概率为
代入E,得
E=n/2
.
然后就没什么了。
#include <bits/stdc++.h>
using namespace std;
#define RE(x) freopen(x,"r",stdin)
#define WR(x) freopen(x,"w",stdout)
#define ms(x,y) memset(x,y,sizeof(x))
#define pb push_back
#define mp make_pair
#define INF 0x3f3f3f3f
#define eps 1e-8
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
typedef vector<ll> vl;
const int M = 1e9 + 7;
const double PI = acos(-1.0);
const int MAXN = 1e5 + 5;
const int MAXM = 1e6 + 6;
int main() {
//RE("in.txt");WR("out.txt");
ll f[MAXN];
f[1]=1;
for(int i=2;i<=100000;i++) {
f[i]=(f[i-1]*i)%M;
}
ll n;
cin>>n;
ll x=n*(1e9+8)/2;
x=x%M;
cout<<x*f[n]%M<<endl;
}
D.Palindromic Subsets(线段树+组合数计算)
https://www.hackerrank.com/contests/101hack44/challenges/palindromic-subsets
题目大意:
输入n和q,还有一个n长的、由小写字母构成的字符串s,进行如下操作:
* 1 i j t:对s的[i,j]子串的字母循环右移t个(下标从0开始)
* 2 i j:问s的[i,j]子串中,有多少个子串可以重排成回文串(这里没注意,导致本题一直没做出来,蠢死了),下标不同认为是不同的子串
n,q范围均为1e5.
题目分析:
因为是重排,所以子串aab也算是“回文串”,因为可以重排为aba,这点一直没注意到。
因此,我们只需要考虑字母出现的次数,而不用关心字母出现的先后顺序。
对每个[i,j]区间,统计每个字母出现的数量记为数组cnt[0…25],记even[i]表示第i个字母的偶数个子集的数目,odd[i]表示第i个字母的奇数个数的子集的数目。
例如对字符串aaaabbb,则cnt[0]=4,cnt[1]=3.
even[0]=8(0个a有1个,2个a有C(4,2)=6个,4个a有1个)
odd[0]=8(1个a有C(4,1)=4个,3个a有C(4,3)=4个)
同理even[1]=4,odd[1]=4。
根据组合数公式可知,若cnt[i]不为0,则 odd[i]=even[i]=2cnt[i]−1 ,否则 odd[i]=0,even[i]=1 .
接下来讨论答案,首先如果一个数是回文数,那么至多有一个字母出现奇数次.
首先考虑所有字母出现偶数次的情况,那么答案显然就是
even[0]⋅even[1]...⋅even[25]
.
如果有字母出现奇数次,只需让其他的字母出现了偶数次,那么答案就是:
要想处理这个东西,很显然需要跑一下even数组的前缀积和后缀积,然后转化成形如:
接下来就简单了,cnt数组因为具有区间递归的性质,只需用线段树维护即可。因为只有26个字母,因此计算 pre[i]⋅odd[i]⋅suf[i] 的过程时间复杂度为 O(26⋅logn) ,然后线段树查点、更新的时间复杂度为 O(logn) ,故整体的时间复杂度为 O(qlog2n⋅26) ,算一下这个值大约为 6.5×107 ,所以是不会超时的。(个人认为题解给的复杂度错误,因为大数乘方取模的复杂度已经是logn了,而且我这个算法在oj上耗时约为0.8秒,按一般经验oj平台每秒钟处理1e8个数据量来算,数量级也是对的上的)
#include <bits/stdc++.h>
using namespace std;
#define RE(x) freopen(x,"r",stdin)
#define WR(x) freopen(x,"w",stdout)
#define ms(x,y) memset(x,y,sizeof(x))
#define pb push_back
#define mp make_pair
#define INF 0x3f3f3f3f
#define eps 1e-8
#define LEFT idx<<1,begin,mid
#define RIGHT idx<<1|1,mid+1,end
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
typedef vector<ll> vl;
const int M = 1e9 + 7;
const double PI = acos(-1.0);
const int MAXN = 1e5 + 5;
const int MAXM = 1e6 + 6;
int n,q;
char s[123456];
struct node {
int lazy;
int cnt[30];
}segtree[1<<18],id;
ll qmod(ll a,ll b,ll c) {
ll ans=1;
a=a%c;
while(b>0) {
if(b&1)
ans=(ans*a)%c;
b=b/2;
a=(a*a)%c;
}
return ans;
}
node merge(node a,node b) {
node c;
c.lazy=0;
for(int i=0;i<26;i++) {
c.cnt[i]=a.cnt[(i+a.lazy)%26]+b.cnt[(i+b.lazy)%26];
}
return c;
}
void apply(int a,int b) {
segtree[a].lazy+=b;
}
void down(int x) {
if(segtree[x].lazy) {
apply(x*2, segtree[x].lazy);
apply(x*2+1, segtree[x].lazy);
node c;
c.lazy=0;
for(int i=0;i<26;i++)
c.cnt[i]=segtree[x].cnt[(i+segtree[x].lazy)%26];
segtree[x]=c;
}
}
void build(int idx,int begin,int end) {
if(begin==end)
segtree[idx].cnt[s[begin-1]-'a']++;
else {
int mid=(begin+end)/2;
build(LEFT);
build(RIGHT);
segtree[idx]=merge(segtree[idx*2],segtree[idx*2+1]);
}
}
void update(int idx,int begin,int end,int l,int r,int v) {
if(r<begin || end<l)
return;
if(l<=begin && end<=r)
apply(idx,v);
else {
down(idx);
int mid=(begin+end)/2;
update(LEFT,l,r,v);
update(RIGHT,l,r,v);
segtree[idx]=merge(segtree[idx*2],segtree[idx*2+1]);
}
}
node query(int idx,int begin,int end,int l,int r) {
if(r<begin || end<l)
return id;
if(l<=begin && end<=r)
return segtree[idx];
else {
down(idx);
int mid=(begin+end)/2;
node a=query(LEFT,l,r);
node b=query(RIGHT,l,r);
return merge(a,b);
}
}
void shift(int i,int j,int t) {
update(1,1,n,i+1,j+1,(26-(t%26))%26);
}
ll solve(int x,int y) {
ll pre[27],suf[27],even[27],odd[27];
for(int i=0;i<27;i++) {
pre[i]=0;suf[i]=0;even[i]=0;odd[i]=0;
}
node d=query(1,1,n,x+1,y+1);//得到结果节点
for(int i=0;i<26;i++) {
int c=d.cnt[i];
if(c==0) {
even[i]=1;
odd[i]=0;
}
else {
even[i]=odd[i]=qmod(2,c-1,M);//直接用1<<(c-1)肯定会爆ll
}
}
pre[0]=1;suf[26]=1;
for(int i=1;i<=26;i++)
pre[i]=(pre[i-1]*even[i-1])%M;
for(int i=25;i>=0;i--)
suf[i]=(suf[i+1]*even[i])%M;
ll ans=suf[0];//不考虑奇数个字母的出现,答案为(even[0]*...*even[25])%M
for(int i=0;i<26;i++) {
ll temp=(pre[i]*odd[i])%M;
temp=(temp*suf[i+1])%M;
ans=(ans+temp)%M;
}
return ans-1;
}
int main() {
RE("in.txt");WR("out.txt");
cin>>n>>q;
cin>>s;
// cout<<n<<" "<<q<<endl;
// cout<<s<<endl;
build(1,1,n);
while(q--) {
int op,x,y,t;
cin>>op;
if(op==1) {
cin>>x>>y>>t;
shift(x,y,t);
}
else {
cin>>x>>y;
cout<<solve(x,y)<<endl;
}
}
}