(ECPC 16) (6/11)


problem D(10) Popcorn n个物品取m个方法数C(n,m)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+20;
int main()
{
	//freopen("popcorn.in","r",stdin);
	int t;
	cin>>t;
	while(t--)
	{
		int n,m,ans=1;
		cin>>n>>m;
		//C(n,m)=n!/(n-m)!m!
		//=n-m+1..n / 1..m
		for(int i=1;i<=m;i++)
		{
			ans*=n-i+1;
			ans/=i;
		}
		cout<<ans<<endl;
	} 
	return 0;
}

Problem H(20) Commandos(简单DP)

10*10*10三维地图,点A(F,Y,X)每次可以移动到(F-1,Y,X),(F,Y+1,X),(F,Y,X+1);
有N<=1e3个地点(F,Y,X)有人质a[i] 求从点(10,1,1)出发最多能救多少人质
从移动方式得出该图是为无环的 所以dp[f][x][y]表示从(f,x,y)出发最多能救多少人 记忆化转移状态即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=20;
int n;
int g[N][N][N],dp[N][N][N];
int DP(int f,int x,int y)
{
	if(dp[f][x][y]!=-1)
		return dp[f][x][y];
	int &res=dp[f][x][y];
	if(f<1||x>10||y>10)
		return 0;
	res=max(DP(f-1,x,y),max(DP(f,x+1,y),DP(f,x,y+1)))+g[f][x][y];
	return res;
}
int main()
{
	//freopen("commandos.in","r",stdin);
	int t;
	cin>>t;
	while(t--)
	{
		int f,x,y,h;
		cin>>n;
		memset(dp,-1,sizeof(dp));
		memset(g,0,sizeof(g));
		for(int i=0;i<n;i++)
		{
			cin>>f>>x>>y>>h;	
			g[f][x][y]=h;
		}	
		cout<<DP(10,1,1)<<endl;
	}
	return 0;
}

Problem E(30) Jumping (建图后BFS)

题意:x轴上有点1~N,每个点i可以跳到i-a[i],i+a[i].求每个点i跳到n的最少次数 
不是无环图 无法DP. 建图:若i能跳到j 则j->i 连接一条边,初始时把定点n压入队列做BFS从小到大更新答案即可 O(2*N)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+20;
const int inf=2e6;
int n,a[N],ans[N],vis[N];
vector<int> e[N];
struct node{
	int u,d;
	node(int a,int b):u(a),d(b)
	{
		
	}
};
queue<node> q;
void bfs()
{
	while(!q.empty())
		q.pop();
	q.push(node(n,0));
	ans[n]=0;
	vis[n]=1;
	while(!q.empty())
	{
		node t=q.front();
		q.pop();
		int u=t.u,d=t.d;
		for(int i=0;i<e[u].size();i++)
		{
			int v=e[u][i];
			if(!vis[v])
			{
				vis[v]=1;
				ans[v]=d+1;
				q.push(node(v,d+1));
			}
		}
	}
}
int main()
{
//	freopen("jumping.in","r",stdin);
	int t;
	cin>>t;
	while(t--)
	{
		cin>>n;
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=n;i++)
		{
			ans[i]=-1;
			scanf("%d",&a[i]);
			//i能到j  j->i 
			if(i-a[i]>=1)
				e[i-a[i]].push_back(i);		
			if(i+a[i]<=n)
				e[i+a[i]].push_back(i);
		}
		bfs();
		for(int i=1;i<=n;i++)
			printf("%d\n",ans[i]),e[i].clear();	
	} 
	return 0;
} 

Problem J(40)  Whistle's to the car (dfs+树上差分)

题意:n个结点,带权的树,v控制u当且仅当 u为v的子孙&& dist[u,v]<=a[u],n<=2e5,问每个结点控制的数量?
设d[i]为i->rt的距离,dist[u,v]=d[u]-d[v],根据u来更新答案,控制u的v必须满足 ,d[v]>=d[u]-a[u] 
d[i]随着深度递增,若在dfs过程中保存u的祖先的d值,可以二分找到第一个满足的pos,则ans[pos~fa[u]]都应该+1 
怎么判断祖先v被加了多少次?  
sum[pos~fa[u]]+1,在树上进行差分:让sum[fa[pos]]--,sum[fa[u]]++,问v被加了多少次? 只要累加v的子树的sum,(v不在某个u的[pos~fa[u],则累加时,该段sum被抵消)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> ii;
const int N=2e6+20;
ll a[N],sum[N],d[N],n;
vector<ii> e[N];//w,v
vector<ii> que;
void dfs(int u,int fa)
{
	sum[fa]++;
	ll t=d[u]-a[u];	
	int pos=lower_bound(que.begin(),que.end(),ii(t,0))-que.begin();
	pos--;//fa[pos]
	if(pos>=0)
		sum[que[pos].second]--;
	que.push_back(ii(d[u],u));
	for(int i=0;i<e[u].size();i++)
	{
		ll v=e[u][i].second,w=e[u][i].first;
		if(v==fa) continue;
		
		d[v]=d[u]+w;
		dfs(v,u);
		sum[u]+=sum[v];//
	}
	que.pop_back();//u不在为任何结点的祖先 
}
int main()
{
	freopen("car.in","r",stdin);
	int t;
	cin>>t;
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++)
			scanf("%I64d",&a[i]),e[i].clear(),sum[i]=0,d[i]=0;
		ll p,w;
		int i;
		for(int k=2;k<=n;k++)
		{
			scanf("%d%I64d%I64d",&i,&p,&w);
			e[i].push_back(ii(w,p));
			e[p].push_back(ii(w,i));
		}
		dfs(1,0);
		for(int i=1;i<=n;i++)
			printf("%I64d%c",sum[i],i==n?'\n':' ');
	}
	return 0;
}

Problem G(40) The Galactic Olympics 排列+第二类Stirling数

题意:k不同个人,n场不同比赛 k<=1e6,n<=1e3,每人至少要参加一场比赛,问方法数?
先转化成:对于n个不同的球放入,k个相同的盒子 每个盒子不为空方法数 即第二类Stirling
考虑最后一个人单独一个盒子 或者放到某个盒子中.则S(n,k)=S(n-1,k-1)+S(n-1,k)*k 
最后在考虑k个人的顺序 ans=S(n,k)*k! 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+20;
const ll mod=1e9+7;
ll S[N][N];
int main()
{
//	freopen("galactic.in","r",stdin);
	memset(S,0,sizeof(S));
	S[0][0]=S[1][1]=1;
	for(ll i=2;i<=2000;i++)
	{
		for(ll j=1;j<=i;j++)
		{
			S[i][j]=(S[i-1][j-1]+S[i-1][j]*(ll)j)%mod;
		}
	}
	int t;
	cin>>t;
	while(t--)
	{
		ll n,k;
		cin>>n>>k;
		if(k>n)
		{
			puts("0");
			continue;
		}
		ll ans=S[n][k];
		for(ll i=1;i<=k;i++)
			ans=(ans*i)%mod;
		
		cout<<ans<<endl;
	}
	return 0;
} 


Problem A(50) The Game of osho 博弈SG

题意:给出G(G<100)个子游戏,每个子游戏由(Bi,Ni)(Bi,Ni<=1e9),每次可以使Ni-Bi^k(k=0,1,2..) Bi^k<=Ni 
玩家可以选择任意一个子游戏操作,不能操作算输  
子游戏:相当于nim游戏中的一堆石子 

因为b^0=1 所以最终局面肯定为(0,0...0),求出f(i):第i个子游戏的SG(mex)值 

若f(1)^f(2)^..f(n)=x(x!=0) 则必然有后继状态SG值为f[i]^x 则可以转移到0,所以SG值异或和!=0为必胜态(每次都可以转移到0) 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+20;
/*
ll SG(ll b,ll n)
{
	set<ll> s;
	if(n==0)
		return 0;
	if(b==1)
		return n;
	ll x=1;
	while(x<=n)
	{
		s.insert(SG(b,n-x));
		x=x*b;
	}
	ll y=0;
	while(s.count(y))//logn(b)
		y++;
	return y;
}
*/
//打表得规律 
ll calc_SG(ll b,ll n)
{
	if(b%2)
	{
		if(n%2)
			return (ll)1;
		else
			return (ll)0;
	}
	else
	{
		if((n-b)%(b+1)==0)
			return (ll)2;
		ll p=n/(b+1);//反转多少次 (1,0)->(0,1)->(1,0) ...
		if(p%2)
			return n%2==0;
		else
			return n%2;
	}
}
int main()
{
	//freopen("powers.in","r",stdin);
	int t;
	cin>>t;
	while(t--)
	{
		ll G,b,n;
		cin>>G;
		ll ans=0;
		for(int i=0;i<G;i++)
		{
			cin>>b>>n;
			ans^=calc_SG(b,n);
		}
		if(ans)
			puts("1");
		else
			puts("2");
	}	
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值