http://codeforces.com/blog/entry/61127
题意:
给出三个整数 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
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;
}
题意:
你看这个题目它又臭又长
有n个航班从莫斯科飞到大阪,m个航班从丹佛飞到大阪,每个航班告诉你到达大阪的最快和最迟时间,求莫到大和丹到大两个航班在到达大阪的时间范围有交叉的两个航班对数量。在给你q 个更新,有两种操作,1:添加一次从莫斯科到大阪的航班;2:添加一次从丹佛飞到大阪的航班。每次更新后需要输出目前范围交叉的总航班对数
思路:
设ans为所求个数
先把所有时间离散化,用树状数组维护4个量,从莫斯科到大阪的航班起点个数,末点个数,丹佛到大阪的航班起点个数,末点个数,结果遍历m个丹到大阪的航班,每个的贡献就是 小于等于右端点的左端点(莫-大阪)个数-小于左端点的右端点(莫-大阪)个数。
算莫斯科到大阪的航班贡献时同理
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
水题
#include
#include
#include
#include
#include
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");
}
}
水题
#include
#include
#include
#include
#include
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);
}
}
}
题意:队伍长n,有k个人,以开始在前k 个位置
#include
#include
#include
#include
#include
#include
留坑
通过观察,每个桩先除以最大公因数,然后算出他们的和,是2的倍数输出yes,否则输出no
#include
#include
#include
#include
#include
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;
}
题意:
给你字符串s,长度大于等于k的回文串为超无聊字串,求非超无聊子串的个数
思路:
先用马拉车算出每个位置回文串的长度,以此来得出r[]数组,i位置最远能到达的位置,这两个位置之间所有的字串都是非超无聊子串。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
留坑
题意:在一个聚会,校长相见p个人,总共有n个人,每个人会在茶馆呆[si,ti]的时间,问校长最少需要在茶馆呆的时间。
思路:区间贪心
记录每个人的到达时间数组,离开时间数组(从0开始),从小到大排列。
设MIN为最少时间,st数组从p-1开始遍历,与ed[i-(p-1)]比较,因为从i-(p-1)到i之间一定有p个符合的人,更新MIN值就好了
#include
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
多项式除法模拟
#include
#include
#include
#include
#include
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