ACM International Collegiate Programming Contest, JUST Collegiate Programming Contest (2018)

ACM International Collegiate Programming Contest, JUST Collegiate Programming Contest (2018)


B. New Assignment

  • 有n个人(1?≤?n?≤?104),有男有女,每个人都有一个id,现在这n个人分成学习互助小组,有三种组队模式,一个男人一组,一个女人一组,一男一女一组,如果要一男一女一组,那么这两人id的gcd要>1。保证任意三个人的gcd=1。求小组的组数最少是多少?
  • 看起来是一个很裸的二分匹配,当两个人性别为男女,并且gcd>1时,连边。可是这里的连边的时候复杂度很高。直接暴力连边为5000 × 5000×log级别的。所以,需要换一个角度考虑。
  • 可以发现,由于任意三个数的gcd=1的性质,可以保证任何一个质因子最多有两个被除数。当且仅当这两个被除数的性别不同连边。
#include"stdio.h"
#include"string.h"
#include"queue"
#include"vector"
#include"algorithm"
#include"iostream"
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=100010;//点数
const int maxm=400010;//边数
struct node{
	int v,next,cap,flow;
}edge[maxm];
int cnt;
int head[maxn];
int cur[maxn],d[maxn];// 当前弧下标   结点到汇点弧长
int p[maxn],gap[maxn];////可增广路上的上一条弧   gap优化
int ss[maxn];//保存路径
void init(){
	cnt=-1;
	memset(head,-1,sizeof(head));
}
void debug(int k){
	int i,j;
	printf("\n");
	for (i=0;i<=k;i++)
	for (j=head[i];j!=-1;j=edge[j].next) 

        printf("%d %d %d\n",i,edge[j].v,edge[j].flow);
}
void add(int u,int v,int w,int rw=0){
	cnt++;
	edge[cnt].v=v;
	edge[cnt].next=head[u];
	edge[cnt].cap=w;
	edge[cnt].flow=0;
	head[u]=cnt;
	cnt++;
	edge[cnt].v=u;
	edge[cnt].next=head[v];
	edge[cnt].cap=rw;
	edge[cnt].flow=0;
	head[v]=cnt;
}
void bfs(int k){
	int v,i;
	int u;
	memset(gap,0,sizeof(gap));
	memset(d,-1,sizeof(d));
	d[k]=0;
	gap[0]++;
	queue<int> q;
	q.push(k);
	while(q.empty()==false){
		u=q.front();q.pop();
		for (i=head[u];i!=-1;i=edge[i].next){
			v=edge[i].v;
			if (d[v]==-1) {
				d[v]=d[u]+1;
				gap[d[v]]++;
				q.push(v);
			}
		}
	}
}
int sap(int s,int t,int N){
	int i;
	bfs(t);
	memcpy(cur,head,sizeof(head));
	int top=0;
	int u=s;
	int ans=0;
	while(d[s]<N){
		if (u==t){
			int min=inf;
			int inser;
			for (i=0;i<top;i++){
				if (min>=edge[ss[i]].cap-edge[ss[i]].flow){
					min=edge[ss[i]].cap-edge[ss[i]].flow;
					inser=i;//这跟管子是满流了
				}
			}
			for (i=0;i<top;i++){
				edge[ss[i]].flow+=min;
				edge[ss[i]^1].flow-=min;
			}
			ans+=min;
			top=inser;
			u=edge[ss[top]^1].v;//u为满流的那个结点 也就是那根管子的倒管子的终点
			continue;
		}
		bool ok=false;
		int v;
		for (i=cur[u];i!=-1;i=edge[i].next){
			v=edge[i].v;
			if (edge[i].cap-edge[i].flow>0&&d[v]+1==d[u]){
				ok=true;
				cur[u]=i;
				break;
			}//u后 添加了一条下标为i的弧
		}
		if(ok==true){
			ss[top]=cur[u];
			top++;
			u=v;
			continue;
		}
		//如果这条路已经走不通了,那么撤退
		int min=N;
		for (i=head[u];i!=-1;i=edge[i].next)
		  if (edge[i].cap-edge[i].flow>0&&d[edge[i].v]<min){
		  	min=d[edge[i].v];
		  	cur[u]=i;
		  }
		gap[d[u]]--;
		if (gap[d[u]]==0) return ans;
		d[u]=min+1;
		gap[d[u]]++;
		if (u!=s) {
			top--;
			u=edge[ss[top]^1].v;

	}
	}
	return ans;
}
int gcd(int a,int b){
	if (a%b==0) return b;
	return gcd(b,a%b);
}
int prime[600000]={0},numprime=0;
bool isNotPrime[1000010]={1,1};
void sushu(int N){
  long long int i;
   for (i=2;i<=N;i++) {
   	     if(! isNotPrime[i])
            prime[numprime ++]=i;    

        for(long j = 0 ; j < numprime && i * prime[j] <  N ; j ++)
            {
                isNotPrime[i * prime[j]] = 1;
            if( !(i % prime[j] ) )
                break;
        }
    }
}
int a[10500];
char s[10];
vector<int > v[1000005];
int vis[1000005];
int main(){
	int e,t,i,j,x,y,cap,now;
	int n,m;
	sushu(1000000);
	scanf("%d",&t);
	for (e=1;e<=t;e++){
		memset(vis,0,sizeof(vis));
		for (i=0;i<numprime;i++) v[prime[i]].clear();
		init();
		scanf("%d",&n);
		for (i=1;i<=n;i++) scanf("%d",&a[i]);
		for (j=1;j<=n;j++) {
			scanf("%s",s);

			if (s[0]==‘M‘) {
				now=a[j];
				for (i=0;i<numprime&&prime[i]<=1000;i++) {
				//	printf("%d\n",now);
					if (now%prime[i]==0) v[prime[i]].push_back(j);
					while (now%prime[i]==0) now=now/prime[i];
					if (now==1||isNotPrime[now]==0) break;
				}
				if (isNotPrime[now]==0) v[now].push_back(j);
			} else {
				now=a[j];
				for (i=0;i<numprime&&prime[i]<=1000;i++) {
					if (now%prime[i]==0) v[prime[i]].push_back(-j);
					while (now%prime[i]==0) now=now/prime[i];
					if (now==1||isNotPrime[now]==0) break;
				}
				if (isNotPrime[now]==0) v[now].push_back(-j);
			}
		}
		//	printf("%d %d %d\n",prime[0],v[prime[0]][0],v[prime[0]][1]);
		for (i=0;i<numprime;i++)
		if (v[prime[i]].size()==2&&v[prime[i]][0]*v[prime[i]][1]<0) {

			if (v[prime[i]][0]>0) {

				if (vis[v[prime[i]][0]]==0) {add(0,v[prime[i]][0],1);vis[v[prime[i]][0]]=1;}
				if (vis[-v[prime[i]][1]]==0) {add(-v[prime[i]][1],n+1,1);vis[-v[prime[i]][1]]=1;}
				add(v[prime[i]][0],-v[prime[i]][1],inf);
			//	printf("%d %d\n",v[prime[i]][0],-v[prime[i]][1]);
			}
			else {
				if (vis[v[prime[i]][1]]==0) {add(0,v[prime[i]][1],1);vis[v[prime[i]][1]]=1;}
				if (vis[-v[prime[i]][0]]==0) {add(-v[prime[i]][0],n+1,1);vis[-v[prime[i]][0]]=1;}
				add(v[prime[i]][1],-v[prime[i]][0],inf);
			//	printf("%d %d\n",v[prime[i]][1],-v[prime[i]][0]);
			}
		}
		int ans=sap(0,n+1,n+2);
		printf("%d\n",n-ans);
	}
}

E. Maximum Sum

  • 取数问题。16*16的矩阵,如果你取了这个数,那么周围8个格子的数都不能取。求取的数和最大。
  • dp瞎搞。事先筛选出行内任意两个相邻位置不同的状态,大约有3000种不到。
  • dp[i][j]代表第i行,这一行的取数方案为j时,前i行的最大和。由于第i-1行无法去影响i+1行,故可以这样设置状态。
  • 考虑转移, 设上一行的状态为k,当前行的状态为j,如果j and k==0 并且 j<<1 and k ==0 并且 j and k<<1 ==0 那么表示可以转移。
  • 尽管算下来是超高的复杂度,不过千万不要低估银河评测机的实力。
#include"stdio.h"
#include"string.h"
#include"vector"
#include"algorithm"
using namespace std;
vector<int> v;
int d[20];
int a[50][50];
int dp[17][2600];
int main(){
	int i,j,k,l;
	int e,t,n;
	int ans,x;
	int tmp;
	d[0]=1;
	v.clear();
	for (i=1;i<=17;i++) d[i]=d[i-1]*2;
	for (i=0;i<=d[16]-1;i++) {
		int sign=0;
		for (j=0;j<=14;j++)
			if ((i&d[j])>0&&(i&d[j+1])>0) {sign=1;break;}
		if (sign==0) v.push_back(i);
	}

	l=v.size();
	scanf("%d",&t);
	for (e=1;e<=t;e++) {
		scanf("%d",&n);
		for (i=1;i<=n;i++)
		for (j=1;j<=n;j++) scanf("%d",&a[i][j]);
		memset(dp,0,sizeof(dp));
		for (i=0;i<l&&v[i]<=d[n]-1;i++) {
			for (j=1;j<=n;j++) if ((v[i]&d[j-1])>0) dp[1][i]+=a[1][j];
		//	printf("%d :%d\n",i,dp[1][v[i]]);
		}
		for (k=2;k<=n;k++) {
			for (i=0;i<l&&v[i]<=d[n]-1;i++) {
			int tmp=0;
			for (x=1;x<=n;x++) if ((v[i]&d[x-1])>0) tmp+=a[k][x];
			for (j=0;j<l&&v[j]<=d[n]-1;j++)
			if ((v[i]&v[j])==0&&((v[i]<<1)&v[j])==0&&(v[i]&(v[j]<<1))==0) {

		    	dp[k][i]=max(dp[k][i],tmp+dp[k-1][j]);
		//    	printf("%d :%d :%d\n",k,v[i],dp[k][v[i]]);
		    }
		}
		}
		ans=0;
		for (i=0;i<l&&v[i]<=d[n]-1;i++) ans=max(dp[n][i],ans);
		printf("%d\n",ans);
	}
}

原文地址:https://www.cnblogs.com/nowheretrix/p/9386001.html

时间: 2024-09-27 16:21:52

ACM International Collegiate Programming Contest, JUST Collegiate Programming Contest (2018)的相关文章

ACM International Collegiate Programming Contest, Tishreen Collegiate Programming Contest (2018) Syria, Lattakia, Tishreen University, April, 30, 2018

ACM International Collegiate Programming Contest, Tishreen Collegiate Programming Contest (2018) Syria, Lattakia, Tishreen University, April, 30, 2018 Problem A. Can Shahhoud Solve it? Problem B. Defeat the Monsters Problem C. UCL Game Night Problem

The 43rd ACM International Collegiate Programming Contest Asia Shenyang Regional Contest

The 43rd ACM International Collegiate Programming Contest Asia Shenyang Regional Contest 原文地址:https://www.cnblogs.com/Accpted/p/11298233.html

IEEE/ACM International Conference on Advances in Social Network Analysis and Mining (ASONAM) 2014 Industry Track Call for Papers

IEEE/ACM International Conference on Advances in Social Network Analysis and Mining (ASONAM) 2014 Industry Track Call for Papers Beijing China August 17-20, 2014Home Page: www.asonam2014.org Full paper/short paper/extended abstract submission deadlin

English Programming Lesson: Vocabulary about Programming

In this semester, I fortunately catched the chance to get in the English-strenthened class, in which C++ lessons are done in English. After the first 2 lessons, though I can understand almost contents the teacher said, the professional terms is actua

Coursera系列-R Programming (John Hopkins University)-Programming Assignment 3

经过断断续续一个月的学习,R语言这门课也快接近尾声了.进入Week 4,作业对于我这个初学者来说感到越发困难起来.还好经过几天不断地摸索和试错,最终完整地解决了问题. 本周的作业Assignment 3是处理一个来自美国Department of Health and Human Services的一个文件,叫“outcome-of-care-measures.csv”.里面储存了美国50个州4000多家医院的几个常见疾病的死亡率.具体说来是30-day mortality and readmi

SDUT 2162-The Android University ACM Team Selection Contest(模拟)

The Android University ACM Team Selection Contest Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 Now it's 20000 A.D., and the androids also participate in the ACM Inter-national Collegiate Programming Contest (ACM/ICPC). In order to selec

Programming paradigms

https://en.wikipedia.org/wiki/Aspect-oriented_programming Action Agent-oriented Array-oriented Automata-based Concurrent computing Relativistic programming Data-driven Declarative (contrast: Imperative) Constraint Constraint logic Concurrent constrai

[Reactive Programming] RxJS dynamic behavior

This lesson helps you think in Reactive programming by explaining why it is a beneficial paradigm for programming. See how reactive programming helps you understand the dynamic behavior of a value evolving over time. It allows you to specify the dyna

Samples for Parallel Programming with the .NET Framework

The .NET Framework 4 includes significant advancements for developers writing parallel and concurrent applications, including Parallel LINQ (PLINQ), the Task Parallel Library (TPL), new thread-safe collections, and a variety of new coordination and s