英文题解:
http://codeforces.com/blog/entry/61127
A - A Criminal 约瑟夫环+枚举
题意:
给出三个整数 X ,L ,N。
X 表示当前人的 编号, L 表示每一个 惩罚选取的最少人数, N 是总人数。惩罚人数只选取一次,也就是选取 L ~ N中的一个数, 其中每个数被选取的概率都相同。 对于每一次惩罚,L个人围成一圈从第一个人开始1,2报数,报到2的人受惩罚,并且推出圈,下一个人报1,直到最后只剩下一个人时停止。相当于约瑟夫环 M = 2 的情况。
求 X 这个人不被惩罚的概率。
思路:
分类讨论,x为偶数:<=l必死,>l 有(x-l)/(n-l+1)几率不死
x为奇数
对于约瑟夫环 M = 2 的情况,有结论 若选取的总人数是 2^k + t, 则最后留下的人的编号是 2*t + 1。
这样,通过 2 * t + 1 这个式子,算出来 X 这个人为最后幸存者 时的 t, 接着枚举 k ,即枚举 2 的次方,算出所有可能的留下的是 X 时 的总人数。然后判断总人数有多少个在 max(L,X)~ N 的范围内,就可以算出 X 这个人存活的概率了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll pow_t[70];
ll gcd(ll a,ll b){
ll r = a % b;
while(r){
a = b; b = r; r = a % b;
}
return b;
}
int main()
{
pow_t[0] = 1;
for(int i = 1;i <= 66;i ++)
pow_t[i] = pow_t[i-1] * 2;
ll x,l,n;
int cas = 1;
int t; scanf("%d",&t);
while(t --){
scanf("%I64d%I64d%I64d",&x,&l,&n);
printf("Case %d: ",cas ++);
if(n == 1){ printf("1/1\n"); continue; }
if(x % 2 == 0 && x <= l){ printf("0/1\n"); continue; }
if(x % 2 == 0){ ll g = gcd(x - l,n - l + 1); printf("%I64d/%I64d\n",(x - l) / g,(n - l + 1) / g); continue; }
ll t = (x - 1) / 2;
ll num[70] = {0}, pn = 0;
for(int i = 0;i <= 66;i ++)
num[pn ++] = pow_t[i] + t;
int cnt = 0;
for(int i = 0;i < pn;i ++){
if(max(l,x) <= num[i] && num[i] <= n)
cnt ++;
}
ll f = cnt;
if(l <= x) f += x - l;
ll g = gcd(f,n - l + 1);
printf("%I64d/%I64d\n",f / g,(n - l + 1) / g);
}
return 0;
}
B - A Leap of faith 树状数组
题意:
你看这个题目它又臭又长
有n个航班从莫斯科飞到大阪,m个航班从丹佛飞到大阪,每个航班告诉你到达大阪的最快和最迟时间,求莫到大和丹到大两个航班在到达大阪的时间范围有交叉的两个航班对数量。在给你q 个更新,有两种操作,1:添加一次从莫斯科到大阪的航班;2:添加一次从丹佛飞到大阪的航班。每次更新后需要输出目前范围交叉的总航班对数
思路:
设ans为所求个数
先把所有时间离散化,用树状数组维护4个量,从莫斯科到大阪的航班起点个数,末点个数,丹佛到大阪的航班起点个数,末点个数,结果遍历m个丹到大阪的航班,每个的贡献就是 小于等于右端点的左端点(莫-大阪)个数-小于左端点的右端点(莫-大阪)个数。
算莫斯科到大阪的航班贡献时同理
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <ctime>
#include <cstdlib>
#include <set>
#include <map>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
const int N=600005;
int cnt=0;
int n[2],st[2][N],ed[2][N],f[N],hh[N],st1[N],ed1[N],tree[4][N];
int lowBit(int t) { //找位置
return t & (t ^ (t-1));
}
void update(int x,int n,int k) {
while(x<=n) {
tree[k][x]++;
x+=lowBit(x);
}
}
int sum(int x,int k) {
int p = 0;
while(x > 0) {
p += tree[k][x];
x -= lowBit(x);
}
return p;
}
int main()
{
int t,ca=0,q;
scanf("%d",&t);
while (t--) {
cnt=0;
for(int k=0;k<=1;k++)
{
scanf("%d",&n[k]);
for(int i=1;i<=n[k];i++)
{
scanf("%d%d",&st[k][i],&ed[k][i]);
f[++cnt]=st[k][i];
f[++cnt]=ed[k][i];
}
}
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%d%d%d",&hh[i],&st1[i],&ed1[i]);
hh[i]--;
f[++cnt]=st1[i];
f[++cnt]=ed1[i];
}
sort(f+1,f+cnt+1);
cnt=unique(f+1,f+1+cnt)-f-1;
for(int i=0;i<=cnt;i++)
for(int j=0;j<4;j++)
tree[j][i]=0;
ll ans=0;
for(int k=0;k<=1;k++)
for(int i=1;i<=n[k];i++)
{
int px=lower_bound(f+1,f+1+cnt,st[k][i])-f;
int py=lower_bound(f+1,f+1+cnt,ed[k][i])-f;
update(px,cnt,k*2);
update(py,cnt,k*2+1);
if(k==1)
{
ans+=sum(py,0)-sum(px-1,1);
}
}
printf("Case %d: %lld\n",++ca,ans);
for(int i=1;i<=q;i++)
{
int px=lower_bound(f+1,f+1+cnt,st1[i])-f;
int py=lower_bound(f+1,f+1+cnt,ed1[i])-f;
update(px,cnt,hh[i]*2);
update(py,cnt,hh[i]*2+1);
ans+=sum(py,(hh[i]^1)*2+0)-sum(px-1,(hh[i]^1)*2+1);
printf("%lld\n",ans);
}
}
return 0;
}
C - BACS, Scoundrel Shopkeeper and Contiguous Sequence 水
水题
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define inf 0x7fffffff
typedef long long ll;
int a[150];
int main(){
int t;
int n,ca=1;
ll m;
scanf("%d",&t);
while(t--)
{
scanf("%lld%d",&m,&n);
ll sum=0;
int flag1=0,flag2=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
if(sum==m) flag1=1;
for(int i=2;i<=n;i++)
{
if(a[i]-a[i-1]==1)
{
flag2=1;
break;
}
}
printf("Case %d: Thank You BACS!!! ",ca++);
if(flag1) printf("Thik ache. ");
else printf("Bojjat dokandar!! ");
if(flag2) printf("Yes\n");
else printf("No\n");
}
}
D - Beauty and The Tree
E - Diverse Group 组合数
水题
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define inf 0x7fffffff
typedef long long ll;
const int N=10000005;
ll mod=1000000007;
ll fac[N];
ll inv[N];
ll pow_m(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1) res=res*a%mod;
b>>=1;
a=a*a%mod;
}
return res;
}
ll Getinv(ll a)
{
return pow_m(a,mod-2);
}
void init()
{
fac[0]=1; fac[1]=1;
for(int i=2;i<=N;i++)
{
fac[i]=fac[i-1]*i%mod;
}
inv[N-1]=Getinv(fac[N-1]);
for(int i=N-2;i>=0;i--)
inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(ll n,ll m)
{
return (fac[n]*inv[n-m]%mod*inv[m]%mod);
}
int main(){
init();
int t;
ll n,m,k;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld",&n,&m,&k);
if(k>n) printf("0\n");
else
{
ll ans=(C(n,k)*pow_m(m,k))%mod;
printf("%lld\n",ans);
}
}
}
F - Football Free Kick
题意:队伍长n,有k个人,以开始在前k 个位置
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
const int maxn=1000+5;
const int inf=0x3f3f3f3f;
map<int,int>mp;
int n,k,q;
int main()
{
int T;
scanf("%d",&T);
int S=T;
while(T--)
{
mp.clear();
scanf("%d%d%d",&n,&k,&q);
int ans;
if(k==n)
ans=0;
else
ans=1;
for(int i=0;i<=k;i++)
{
mp[i]=1;
}
mp[n+1]=1;
printf("Case %d:\n",S-T);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
if(mp[x-1]==1&&mp[x+1]==1)
{
ans++;
}else if((mp[x-1]==1&&mp[x+1]==0)||(mp[x-1]==0&&mp[x+1]==1)){
}else{
ans--;
}
mp[x]=0;
if(mp[y-1]==1&&mp[y+1]==1)
{
ans--;
}else if((mp[y-1]==1&&mp[y+1]==0)||(mp[y-1]==0&&mp[y+1]==1)){
}else{
ans++;
}
mp[y]=1;
printf("%d\n",ans);
}
}
return 0;
}
G - GCD and LCM of 3 numbers
H - Little T2 and Derangements
留坑
I - Marbelous Meena 数学+观察
通过观察,每个桩先除以最大公因数,然后算出他们的和,是2的倍数输出yes,否则输出no
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=100000+5;
const int inf=0x3f3f3f3f;
typedef long long ll;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
int n;
ll a[maxn];
int main()
{
int T;
scanf("%d",&T);
int S=T;
while(T--)
{
scanf("%d",&n);
ll g;
ll sum=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
if(i==1)
g=a[i];
else{
g=gcd(g,a[i]);
}
sum+=a[i];
}
while(sum%2==0&&sum>g)
sum/=2;
if(sum==g)
printf("Case %d: YES\n",S-T);
else
printf("Case %d: NO 1\n",S-T);
}
return 0;
}
J - Non Super Boring Substring 马拉车算法
题意:
给你字符串s,长度大于等于k的回文串为超无聊字串,求非超无聊子串的个数
思路:
先用马拉车算出每个位置回文串的长度,以此来得出r[]数组,i位置最远能到达的位置,这两个位置之间所有的字串都是非超无聊子串。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <ctime>
#include <cstdlib>
#include <set>
#include <map>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
const double eps = 1e-6;//eps用于控制精度
const double pi = acos(-1.0);//pi
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
const int maxn=2e5+10;
string s;
int t,k;
int p[2*maxn];
int r[maxn];
void Manacher(string s)
{
string now;
int len=s.size();
for(int i=0;i<len;i++)
{
now+='%';
now+=s[i];
}
now+='%';
len=now.size();
int pos=0,R=0;
for(int i=0;i<len;i++)
{
if(i<R) p[i]=min(p[2*pos-i],R-i);
else p[i]=1;
while(0<=i-p[i]&&i+p[i]<len&&now[i-p[i]]==now[i+p[i]]) p[i]++;
if(i+p[i]>R)
{
pos=i;
R=i+p[i];
}
}
for(int i=0;i<len;i++)
{
if(p[i]-1<k) continue;;
int ln=((p[i]-1-k)%2)?k+1:k;
int left=(i-ln+1)/2,right=(i+ln-1)/2;
r[left]=min(r[left],right);
}
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
cin>>t;
while(t--)
{
cin>>k>>s;
ll ans=0;
int tmp=s.size();
for(int i=0;i<=tmp;i++) r[i]=inf;
Manacher(s);
for(int i=tmp;i>=0;i--)
{
tmp=min(tmp,r[i]);
r[i]=min(r[i],tmp);
}
ll tans=0;
int pre=0;
for(int i=0;i<s.size();i++)
{
tans=r[i]-i;
ans+=tans*(tans+1)/2;
if(pre>i)
{
tans=pre-i;
ans-=tans*(tans+1)/2;
}
pre=max(pre,r[i]);
}
cout<<ans<<endl;
}
return 0;
}
K - Ray Ray Array
留坑
L - School Reunion 贪心
题意:在一个聚会,校长相见p个人,总共有n个人,每个人会在茶馆呆[si,ti]的时间,问校长最少需要在茶馆呆的时间。
思路:区间贪心
记录每个人的到达时间数组,离开时间数组(从0开始),从小到大排列。
设MIN为最少时间,st数组从p-1开始遍历,与ed[i-(p-1)]比较,因为从i-(p-1)到i之间一定有p个符合的人,更新MIN值就好了
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
typedef long long ll;
const ll INF = (ll)1e18;
ll st[maxn],en[maxn];
ll p,n;
int main(){
int t,Kase=1;
scanf("%d",&t);
while(t--){
scanf("%lld%lld",&n,&p);
for(int i=0;i<n;i++)scanf("%lld %lld",&st[i],&en[i]);
sort(st,st+n);
sort(en,en+n);
ll MIN = INF;
for(int i=p-1;i<n;i++){
ll temp = st[i]-en[i-(p-1)];
if(temp<=0ll){MIN = 0;break;}
else MIN = min(MIN,temp);
}
printf("Case %d: %lld\n",Kase++,MIN);
}
return 0;
}
M - TFF
多项式除法模拟
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=2000+5;
const int inf=0x3f3f3f3f;
int gx[maxn];
int hx[maxn];
int fx[maxn];
int d[maxn];
int n,m,k;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(fx,0,sizeof(fx));
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%d",&gx[i]);
}
scanf("%d",&k);
for(int i=0;i<k;i++)
{
scanf("%d",&hx[i]);
}
for(int i=0;i<m/2;i++)
swap(gx[i],gx[m-i-1]);
for(int i=0;i<k/2;i++)
swap(hx[i],hx[k-i-1]);
for(int j=0;j<k-m+1;j++)
{
//printf("j=%d\n",j);
int xg,xh;
xg=m-1;
xh=k-j-1;
//printf("xg=%d xh=%d hx=%d gx=%d\n",xg,xh,hx[j],gx[i]);
int ans=hx[j]/gx[0];
fx[xh-xg]+=ans;
hx[j]=0;
for(int h=1;h<m;h++)
{
int pos=(k-(m-h-1)-1)-(xh-xg);
//printf("pos=%d\n",pos);
hx[pos]-=ans*gx[h];
}
if(hx[j]!=0)
j++;
}
int n=k-m+1;
printf("%d\n",n);
for(int i=0;i<n-1;i++)
{
printf("%d ",fx[i]);
}
printf("%d\n",fx[n-1]);
}
return 0;
}