2017年ICPC中国大陆区域赛真题(下) vj套题

A - Lovers

 贪心,从男生最大与女生最小开始匹配。

正确性:每个人最多匹配1人,能与最小的可能匹配就匹配,否则也是浪费。

//KX
#include <bits/stdc++.h>
using namespace std;
template<typename T>inline void rd(T&x){
    x=0;int f=1;char ch=getchar();
    while(ch<'0' ||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); }
    while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
    x*=f;
}
typedef long long ll;
typedef double db;
const int M = 1e5+7;
#define ls (o<<2)
#define rs (o<<1|1)
#define pb push_back
int a[M],b[M];
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n,k;
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
		for(int i=1;i<=n;i++)
		scanf("%d",&b[i]);
		sort(a+1,a+1+n);
		sort(b+1,b+1+n);
		int l=1,r=n,cnt=0;
		while(l<=n&&r>=1)
		{
			if(a[l]+b[r]>=k)
			{
				cnt++;
				l++,r--;
			}
			else
				l++;
		}
		printf("%d\n",cnt);
	}
  	return 0;
}

B - God of Gamblers

 由于赢钱概率相同,无论怎么押 ,赢完的概率波动总是与本金成正比。

不知道结论可以猜一发。。n/(m+n).

 

凯利定理表示:最优押钱数是0。。所以不要赌博

题面描述的策略看似是一个必胜策略。因为输了后,押2倍,只要赢一次,就可以把所有输的钱赢回来。

但是 忽略了本金有限这个问题,具体说明看看下面这个大佬的bolg。还是蛮有意思的

https://blog.csdn.net/wusecaiyun/article/details/49161437

//KX
#include <bits/stdc++.h>
using namespace std;
int main()
{
	double n,m;
	while(cin>>n>>m)
		printf("%.5f\n",n/(n+m));
  	return 0;
}

C - Arrangement for Contests

 贪心+线段树即可。

从左往右取比赛。能取尽量取,取完区间减去最小值。

维护下最小值的位置,或者直接暴力判1e5次,其实差不多速度。

//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 1e5+7;
#define ls (o<<1)
#define rs (o<<1|1)
ll a[M];
ll mn[M<<2],tg[M<<2];
void bd(int o,int l,int r)
{
	tg[o]=0;
	if(l==r)
	{
		mn[o]=a[l];
		return ; 
	}
	int m=(l+r)/2;
	bd(ls,l,m);
	bd(rs,m+1,r);
	mn[o]=min(mn[ls],mn[rs]);
}
void pd(int o)
{
	if(tg[o]==0)return ;
	tg[ls]+=tg[o];tg[rs]+=tg[o];
	mn[ls]+=tg[o];mn[rs]+=tg[o];
	tg[o]=0;
}
void up(int o,int l,int r,int x,int y,ll d)
{
//	printf("%d  %d  %d\n",l,r,o);
	if(x<=l&&r<=y)
	{
		mn[o]+=d;
		tg[o]+=d;
		return ;
	}
	pd(o);
	int m=(l+r)/2;
	if(x<=m)up(ls,l,m,x,y,d);
	if(y>m)up(rs,m+1,r,x,y,d);
	mn[o]=min(mn[ls],mn[rs]);
}
ll qu(int o,int l,int r,int x,int y)
{
//	printf("-=-  %d  %d  %d %d  %d\n",l,r,o,x,y);
	if(x<=l&&r<=y)
	{
		return mn[o];
	}
	pd(o);
	int m=(l+r)/2;
	ll mi=1e9+7;
	if(x<=m)mi=min(mi,qu(ls,l,m,x,y));
	if(y>m)mi=min(mi,qu(rs,m+1,r,x,y));
	return mi;
}
int main()
{
	ll t,n,k;
	cin>>t;
	while(t--)
	{
		scanf("%lld%lld",&n,&k);
		for(int i=1;i<=n;i++)
			scanf("%lld",&a[i]);
		bd(1,1,n);
		int pos=1;
		ll ans=0;
		while(pos+k-1<=n)
		{
			ll mi=qu(1,1,n,pos,pos+k-1);
		//	printf("%d  %d  %d\n",pos,mi,ans);
			ans=ans+mi;
			up(1,1,n,pos,pos+k-1,-mi);
			pos++;
		}
		printf("%lld\n",ans); 
	}
  	return 0;
}
//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int M = 1e5+7;
#define ls (o<<2)
#define rs (o<<1|1)
#define pb push_back
int a[M];
int mn[M<<2],ps[M<<2],tg[M<<2];
void pu(int o)
{
	if(mn[ls]<mn[rs])//最小值尽量取右边的 
	{
		mn[o]=mn[ls];
		ps[o]=ps[ls];
	}
	else
	{
		mn[o]=mn[rs];
		ps[o]=ps[rs];
	}
}
void bd(int o,int l,int r)
{
	tg[o]=0;
	if(l==r)
	{
		mn[o]=a[l];
		ps[o]=l;//最小值位置
		return ; 
	}
	int m=(l+r)>>1;
	bd(ls,l,m);
	bd(rs,m+1,r);
	pu(o);
}
void pd(int o)
{
	if(tg[o]==0)return ;
	tg[ls]+=tg[o];tg[rs]+=tg[o];
	mn[ls]+=tg[o];mn[rs]+=tg[o];
	tg[o]=0;
}
void up(int o,int l,int r,int x,int y,int d)
{
//	printf("%d  %d  %d\n",l,r,o);
	if(x<=l&&r<=y)
	{
		mn[o]+=d;
		tg[o]+=d;
		return ;
	}
	pd(o);
	int m=(l+r)/2;
	if(x<=m)up(ls,l,m,x,y,d);
	if(y>m)up(rs,m+1,r,x,y,d);
	pu(o);
}
int id;
int qu(int o,int l,int r,int x,int y)
{
//	printf("-=-  %d  %d  %d %d  %d\n",l,r,o,x,y);
	if(x<=l&&r<=y)
	{
		return mn[o];
	}
	pd(o);
	int m=(l+r)/2, mi=1e9+7;
	if(x<=m)mi=min(mi,qu(ls,l,m,x,y));
	if(y>m)mi=min(mi,qu(rs,m+1,r,x,y));
	return mi;
}
bool fl;
void qup(int o,int l,int r,int x,int y,int w)
{
	if(r<x||l>y||fl)return ;
//	printf("--  %d  %d  %d  %d %d\n",l,r,w,x,y);
	if(x<=l&&r<=y)
	{
		if(mn[o]==w)
		{
			fl=true;
			id=ps[o];
		}
	}
	pd(o);
	int m=(l+r)/2;
	if(mn[rs]<=w) qup(rs,m+1,r,x,y,w);
	if(mn[ls]<=w) qup(ls,l,m,x,y,w);
}
int main()
{
	int t,n,k;
	cin>>t;
	while(t--)
	{
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]);
		bd(1,1,n);
		int pos=1;
		ll ans=0;
		while(pos+k-1<=n)
		{
			fl=false;
			int mi=qu(1,1,n,pos,pos+k-1);
			qup(1,1,n,pos,pos+k-1,mi);
			ans+=mi;
			up(1,1,n,pos,pos+k-1,-mi);
			pos=id+1;//最小值的位置 
		}
		printf("%lld\n",ans); 
	}
  	return 0;
}

D - LOL

由于先考虑BAN很难。我们可以先考虑选英雄,BAN不能BAN选过的。

 

暴力dfs前4个玩家选择英雄的情况。根据最后一个玩家可选英雄情况算出方案数。复杂度1e8乘上20组数据,按理说过不了。。

但是过了,应该是数据随机的原因。

得到的结果是5分玩家选英雄的方案。地方选英雄是在剩下95个英雄中任意选择即:A(95,5);

而我方和敌方BAN英雄也是任意BAN,且不需要全排列,组合就行。//说实话这里我也不太理解,但是只能体会出题者意图了。。大不了都试一下,看看哪个能过样例。

 

%12345召唤师选英雄12345和54321是不同的方案,12345召唤师BAN英雄12345和54321是相同的方案。

//KX
#include <bits/stdc++.h>
using namespace std;
template<typename T>inline void rd(T&x){
    x=0;int f=1;char ch=getchar();
    while(ch<'0' ||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); }
    while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
    x*=f;
}
typedef unsigned long long ll;
typedef double db;
const int M = 1e2+7;
const int MOD = 1e9+7;
#define ls (o<<2)
#define rs (o<<1|1)
#define pb push_back
char s[6][110];
ll ans;
bool vis[110];
void dfs(int x)
{
	//printf("%d\n",x);
	if(x==5)
	{
		int num=0;
		for(int i=0;i<100;i++)
		{
			if(!vis[i]&&s[x][i]=='1')
			num++;
		} 
		ans=(ans+num)%MOD;
		return ;
	}
	for(int i=0;i<100;i++)
	{
		int ch=s[x][i]-'0';
		if(ch==1)
		{
			if(vis[i])continue;
			vis[i]=true;//每个玩家选择的英雄 
			dfs(x+1);
			vis[i]=false;
		}
	}
}
int main()
{
	while(~scanf("%s%s%s%s%s",s[1],s[2],s[3],s[4],s[5]))
	{
		dfs(1);
		//选完固定的5个英雄后再BAN,敌方英雄再BAN选,因为这15个是任意的。
		//还有要注意是问多少种方法满足条件,题意说的应该是10角色选择的阵容,所以角色要全排列,而BAN只需要组合 
		ans=(ans*531192758)%MOD;//后面的数字等于A(95,5)*C(90,5)* C(85,5);
		cout<<ans<<"\n";
	}
  	return 0;
}
/*
0110011100011001001100011110001110001110001010010111111110101010010011010000110100011001001111101011

1000111101111110110100001101001101010001111001001011110001111110101000011101000001011100001001011010

0100101100011110011100110110011100111100010010011001111110101111111000000110001110000110001100001110

1110010101010001000110100011101010001010000110001111111110101010000000001111001110110101110000010011

1000010011111110001101100000101001110100011000111010011111110110111010011111010110101111011111011011

*/

DP是正解。

考虑dp[i][j]前i个人选择前j个英雄的方案数。

由于我们从前往后遍历英雄。

每个人选的一定是前面人选的后面的英雄,所以不会重复。

但是会少情况。但只要遍历5个人选英雄顺序的所有可能,全部加到ans里就OK了。

复杂度(5!*100)*20组数据  稳过

//KX
#include <bits/stdc++.h>
using namespace std;
template<typename T>inline void rd(T&x){
    x=0;int f=1;char ch=getchar();
    while(ch<'0' ||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); }
    while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
    x*=f;
}
typedef unsigned long long ll;
typedef double db;
const int M = 1e2+7;
const int MOD = 1e9+7;
#define ls (o<<2)
#define rs (o<<1|1)
#define pb push_back
char s[6][110];
ll ans;
int a[5];
ll dp[6][110];//前i个人在前j个英雄中选英雄的方案数。 
int main()
{
	while(~scanf("%s%s%s%s%s",s[1]+1,s[2]+1,s[3]+1,s[4]+1,s[5]+1))
	{
		for(int i=1;i<=5;i++)
			a[i]=i;
		do{
			memset(dp,0,sizeof(dp));
			for(int j=1;j<=100;j++){
				dp[1][j]=dp[1][j-1];
				if(s[a[1]][j]=='1')dp[1][j]++;
			}
			for(int i=2;i<=5;i++)
				for(int j=1;j<=100;j++)
				{
					if(s[a[i]][j]=='0')//当前玩家没有第j个英雄 
						dp[i][j]=dp[i][j-1];//那就在j-1个英雄中选 
					else
						dp[i][j]=(dp[i][j-1]+dp[i-1][j-1])%MOD; //要么选j要么不选j 
				}
			ans=(ans+dp[5][100])%MOD;
		}while(next_permutation(a+1,a+6));
//由于dp只能按从前往后的顺序选,但实际每个人都有可能选后面的英雄
//,所以把5个人选赢英雄的顺序遍历dp求和即可 
//选完固定的5个英雄后再BAN,敌方英雄再BAN选,因为这15个是任意的。
//还有要注意是问多少种方法满足条件,题意说的应该是10角色选择的阵容,所以角色要全排列,而BAN只需要组合 
		ans=(ans*531192758)%MOD;//后面的数字等于A(95,5)*C(90,5)* C(85,5);
		cout<<ans<<"\n";
	}
  	return 0;
}
/*
0110011100011001001100011110001110001110001010010111111110101010010011010000110100011001001111101011

1000111101111110110100001101001101010001111001001011110001111110101000011101000001011100001001011010

0100101100011110011100110110011100111100010010011001111110101111111000000110001110000110001100001110

1110010101010001000110100011101010001010000110001111111110101010000000001111001110110101110000010011

1000010011111110001101100000101001110100011000111010011111110110111010011111010110101111011111011011

*/

E - Little Boxes   大整数模板

//KX
#include <bits/stdc++.h>
using namespace std;
template<typename T>inline void rd(T&x){
    x=0;int f=1;char ch=getchar();
    while(ch<'0' ||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); }
    while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
    x*=f;
}
typedef unsigned long long ll;
typedef double db;
const int M = 1e2+7;
#define ls (o<<2)
#define rs (o<<1|1)
#define pb push_back
char c[M];
int Judge(char ch[])
{//判断字符串ch是否全为0,若全为返回1,否则返回0
     int i,k;
     k=strlen(ch);
     for(i=0;i<k;i++) if(ch[i]!='0')  return 0;
     return 1;
}
void add(char a1[],char b1[])
{
	memset(c,0,sizeof(c));
	int i,j,k,lena,lenb;
	int a[M]={0},b[M]={0},d[M]={0};
	lena=strlen(a1);
	lenb=strlen(b1);
	for(i=0;i<lena;i++) //将加数与被加数化为整型数组,并且该数组的其他位为
	    a[i]=a1[lena-i-1]-'0';
	for(i=0;i<lenb;i++)
	    b[i]=b1[lenb-1-i]-'0';
	k=lena>lenb?lena:lenb;//当数组除了加数和被加数以外的整型数组元素均为时,无需考虑lena和lenb的大小
	for(i=0;i<k;i++)
	{   
		d[i]=a[i]+b[i]+d[i];  
		d[i+1]=d[i+1]+d[i]/10; 
		d[i]=d[i]%10;   
	}
	while(d[k]) //若高位进
	    k++;
	while(!d[k-1])
	    k--;//001+0003=4
	for(j=0;j<k;j++) //将整型数组逆着转变并赋值给c字符型数组
		c[j]=d[k-j-1]+'0';
	if(Judge(c))//若全为,则只输出一个
	    strcpy(c,"0");
}
char a[M],b[M],d[M];
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		
		memset(d,0,sizeof(d));
		cin>>a>>b;
		add(a,b);
		strcpy(d,c);
		cin>>a>>b;
		add(a,b);
		strcpy(a,c);
		add(a,d);
		cout<<c<<endl;
	}
  	return 0;
}

F - Rabbits

 签到题。。差分数组减1后求和,即中间点数,减去刚开始跳损失的点数即结果

//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int M = 500+7;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
int a[M],c[M];
int main()
{
	int t,n;
	cin>>t;
	while(t--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			c[i]=a[i]-a[i-1]-1;
		}
		int sum=0;
		for(int i=2;i<=n;i++)
		sum+=c[i];
		//printf("%d ",c[i]);
	//	puts("ok");
		int mi=min(c[2],c[n]);
		sum-=mi;
		printf("%d\n",sum);
		
	}
  	return 0;
}

G - Heron and His Triangle

 大数。。

规律很好找,用海伦公式推出来,打个表就发现公式:b[i]=b[i-1]*4-b[i-2]。b[1]=2,b[2]=4。这些数是满足题意的。

//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int M = 1e2+7;
char c[2*M];//全局变量,存储大数运算的结果
char a[M],b[55][M];
char d[M];
int Compare(char a[],char b[])
{//比较字符串的大小,方法不同于strcmp函数,类似于整型常量的比较
     memset(c,0,sizeof(c));
     int lena,lenb,i;
     lena=strlen(a); lenb=strlen(b);
     if(lena<lenb) return -1;
     else if(lena>lenb) return 1;
     else 
	 {
         if(strcmp(a,b)==0) return 0;
         else
		 { 
		 	for(i=0;i<lena;i++)
		 	{ 
			 	if(a[i]>b[i]) 
				 return 1; 
				 if(a[i]<b[i]) 
				 return -1;
			} 
              return 0;
         }
	}
}
int Judge(char ch[])
{//判断字符串ch是否全为0,若全为返回1,否则返回0
     int i,k;
     k=strlen(ch);
     for(i=0;i<k;i++) if(ch[i]!='0')  return 0;
     return 1;
}
/*算法:依照由低位至高位的顺序进行减法运算。在每次位运算中,
若出现不够减的情况,则向高位借位。在进行了la的减法后,若最高
位为,则a的长度减。若A、B大小未知,则需先判断大小。*/
//高精度减法
void Sub(char a1[],char b1[])
{//a1为被减数,b1为减数
     int lena,lenb,i,j,k,flag;
     int a[1000]={0},b[1000]={0},d[1000]={0};
     lena=strlen(a1);
     lenb=strlen(b1);
     if(Compare(a1,b1)>=0) 
	 {//若被减数大于等于减数
         for(i=0;i<lena;i++)  a[i]=a1[lena-1-i]-'0';
         for(i=0;i<lenb;i++)  b[i]=b1[lenb-1-i]-'0';
         flag=0;//结果正的标志
      }
     else 
	 {//若被减数小于减数
         for(i=0;i<lenb;i++) a[i]=b1[lenb-1-i]-'0';
         for(i=0;i<lena;i++)  b[i]=a1[lena-1-i]-'0';
         flag=1;//结果负的标志
     }
     k=lena>lenb?lena:lenb;
     for(i=0;i<k;i++)
     {//大数减小数
         if(a[i]<b[i]) {//若被减数不够减,向高位借一位
              a[i+1]--;
              d[i]=a[i]-b[i]+10; }
         else  d[i]=a[i]-b[i];
     }
     //若较高位已为,并且不止位时
     while(!d[i-1])
     {  k--; i--;  }
     //根据flag,输出有无"-"
     if(!flag) { for(i=0;i<k;i++) {//将结果转化为字符逆着赋给数组c
              if(!i&&!d[k-i-1])//若差的第一个字母为,则马上跳过
                   continue;
              c[i]=d[k-i-1]+'0'; } }
     else  { c[0]='-';  for(i=1;i<=k;i++)
         {//将结果转化为字符逆着赋给数组c
              if(i==1&&!d[k-i])//若差的第一个字母为,则马上跳过
                   continue;
              c[i]=d[k-i]+'0';//注意d的下标,不是k-i-1
         }
     }
     if(Judge(c))//若差全为,则只输出一个
         strcpy(c,"0");
}

void Mul(char a1[],int b1)
{ int i,j,t;

     int a[2000]={0};

     //将字符串转化为整型数组,并逆置

     t=strlen(a1);

     for(i=0;i<t;i++)  a[i]=a1[t-1-i]-'0';

     //整型数组的每个元素乘以b1,然后对其进行求余,整除,使其只有一位数

     a[0]=a[0]*b1;

     for(i=1;i<t;i++) { a[i]*=b1;  a[i]+=a[i-1]/10; a[i-1]=a[i-1]%10; }

     while(a[i-1]>9)

     {//若最后一个元素大于

         a[i]=a[i-1]/10;  a[i-1]=a[i-1]%10;  i++;

     }

     //将得到的整型数组逆置赋给字符串

     for(j=0;j<i;j++)

         c[j]=a[i-j-1]+'0';

     if(Judge(c))//若积全为,则只输出一个

         strcpy(c,"0");

}
int le[M];
void dabiao()
{
	a[0]='4';
	b[0][0]='0';
	b[1][0]='2';
	b[2][0]='4';
	le[1]=le[2]=le[3]=1;
	for(int i=3;i<=100;i++)
	{
		if(strlen(b[i-1])>=31)
			break;
		Mul(b[i-1],4);
		strcpy(d,c);
		Sub(d,b[i-2]);
		strcpy(b[i],c);
		le[i]=strlen(b[i]);
//		printf("%s\n",c);
	//	a[i]=4*a[i-1]-a[i-2];
	//	printf("%lld\n",a[i]);
	}
}

int main()
{
	dabiao();
	int t;
	//b[i][]存的是第i个能组成题意三角形的t 
	cin>>t;
	while(t--)
	{
		scanf("%s",a);
		int L=strlen(a);
		for(int i=2;i<=100;i++)
		{
		/*	if(L>le[i]+1)
				continue;
			else*/
			{
				if(Compare(b[i],a)>=0)
				{
					printf("%s\n",b[i]);
					break;
				}
			}
		}
	}
  	return 0;
}

H - Tree

 思维题吧。。。

题意仔细读读就能懂。

就是你随意在树上染色,每个节点可以染成1-k种颜色。问你把1联通的最短路径和…………把k联通的最短路径的交集最大是多少。

直接想不是很好想,但你会有一点思路,根叶子结点那一块有关。

所以我们换种思路,考虑哪个边能做为最后的路径,肯定要这条边2边的子树结点都含有1-k种颜色,即至少节点数都大于等于k。

这样的思路直接dfs一遍,算子树大小,再遍历就OK了

//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int M = 2e5+7;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
struct node
{
	int to,nxt;
}E[M];
int head[M],cnt,num;
void add(int u,int v)
{
	E[++cnt].to=v;
	E[cnt].nxt=head[u];
	head[u]=cnt;
}
int sz[M];
bool vis[M];
void dfs(int x)
{
	vis[x]=true;
	for(int i=head[x];i!=0;i=E[i].nxt)
	{

		int v=E[i].to;
		if(vis[v])continue;
		dfs(v);
		sz[x]+=sz[v];
	}
}
int main()
{
	int t,u,v;
	cin>>t;
	while(t--)
	{
		int n,k;
		scanf("%d%d",&n,&k);
		memset(head,0,sizeof(head));
		memset(vis,0,sizeof(vis));
		cnt=0,num=n;
		for(int i=1;i<=n;i++)sz[i]=1;
		for(int i=1;i<=n-1;i++)
		{
			scanf("%d%d",&u,&v);
			add(u,v);
			add(v,u);
		}
		dfs(1);
		int ans=0;
		for(int i=1;i<=n;i++)
		{
			int l=sz[i];
			int r=num-sz[i];
			if(l>=k&&r>=k)
			ans++;
		}
		printf("%d\n",ans);
	}
  	return 0;
}

I - Chat Group

 简单推一下,结果等于 2^n-(1+C(n,1)+……+C(n,k-1));

中间求和递推过去,预处理逆元即可。

//KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int M = 1e5+7;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const ll MOD =1000000007;
ll inv[M];
void get_inverse(int n,ll p)
{
	int i;
	inv[1]=1;
	for(i=2;i<=n;++i)
	  inv[i]=(p-p/i)*inv[p%i]%p;
}
ll  qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)ans=(ans*a)%MOD;
		a=a*a%MOD;
		b/=2;
	}
	return ans;
} 

int main()
{
	ll t,n,k;
	get_inverse(1e5,MOD);
	cin>>t;
	for(int ca=1;ca<=t;ca++)
	{
		scanf("%lld%lld",&n,&k);
		ll ans=qpow(2,n)-1;
		ll tmp=1;
	//	printf("--   %lld\n",ans);
		for(int i=1;i<=k-1;i++)
		{
			tmp=tmp*(n-i+1)%MOD;
			tmp=tmp*(inv[i])%MOD;
			ans=(ans-tmp+MOD)%MOD;
		}
		printf("Case #%d: %lld\n",ca,ans);
	}
  	return 0;
}
/*
3
1000000000 100000

*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值