2018提高组模拟4(T1,T2)

WOJ3931

 

嘻嘻,这道题其实不算图论。(难以置信~~~)

 

抛开边不管,将每个点的值拍一下序。

第K天到的城市就将人减K。

所以从大到小得吃就好了,吃到的人小于0就break.

经过的城市不能再吃了,可以不管,因为前面能吃的调一下序就好了。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
void read(int &x){
	x=0;char s=getchar();
	while(s>'9'||s<'0')s=getchar();
	while(s<='9'&&s>='0'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
}
int n,m,a[200010];
long long s[200010],ans=0;
int main(){
	read(n);read(m);
	for(int i=1;i<=n;i++)read(a[i]);
	int e,f;
	for(int i=1;i<=m;i++)read(e),read(f);
	
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		e=a[n+1-i]-i+1;
		if(e<=0)break;
		ans+=e;
	}
	printf("%lld",ans);
	return 0;
}

WOJ3932

解法见上,代码有点难。

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int mk[N],pri[N],cnt=0;
void prime(){//ai
	for(int i=2;i<N;i++){
		if(!mk[i])pri[++cnt]=i;
		for(int j=1;j<=cnt&&1ll*i*pri[j]<N;j++){
			mk[i*pri[j]]=pri[j];//最大质因子 
			if(i%pri[j]==0)break;
		}
	}
}
int k,a[505];
long long n;
pair<int,int>b[N];
int ok[N],v[N],num=0,tmp=0,m=0,bit=0;
void divide(int x){
	tmp=0;
	for(int i=1;1ll*pri[i]*pri[i]<=x&&i<=cnt;i++)
		if(x%pri[i]==0){
			b[++tmp]=make_pair(0,0);//不用一个一个地加 
			b[tmp].first=pri[i];
			while(x%pri[i]==0)
				b[tmp].second++,x/=pri[i];
			if(!ok[pri[i]])
				ok[pri[i]]=1,v[++num]=pri[i];
		}
	if(x>1)b[++tmp]=make_pair(x,1),v[++num]=x;return;//
}
long long mul;
bool check(int x){
	if(n%x)return 0;//排除次方大于的数
	divide(x);
	for(int i=1;i<=tmp;i++){
		mul=1;
		for(int j=1;j<=b[i].second;j++)
			mul=mul*b[i].first;
		if((n/mul)%b[i].first==0)//排除次方小于的数 
			return 0;
	}
	return 1;
}
void check_zero(){
	long long tt=n;
	for(int i=0;i<bit;i++)
		while(tt%v[i]==0)tt/=v[i];
	if(tt>1){
		puts("0");
		exit(0);//退出程序 
	}
}
int cal(int x){
	int ret=0;
	for(int i=0;i<bit;i++)
		if(x%v[i]==0)ret|=1<<i;
	return ret;
}
long long f[1<<20];
int main(){
	int pow=1;
	prime();//素数线性筛 
	scanf("%lld%d",&n,&k);
	for(int x,i=1;i<=k;i++){
		scanf("%d",&x);
		if(x==1){//特判 
			pow=2;continue;
		}
		if(check(x))a[++m]=x;
	}
	sort(v+1,v+num+1);
	for(int i=1;i<=num;i++)//去重 
		if(v[i]!=v[i+1])v[bit++]=v[i];
	check_zero();//判断n是否有可能
	for(int i=1;i<=m;i++)
		a[i]=cal(a[i]);//转二进制
	//状压DP
	f[0]=1;
	for(int i=0;i<(1<<bit);i++)//要多一位
		for(int j=1;j<=m;j++)
			if((i&a[j])==0&&i<a[j])//不重复  严格按照小的乘大的(避免多算)
				f[i|a[j]]+=f[i]; 
	printf("%lld",f[(1<<bit)-1]*pow);
	return 0;
}

WOJ3933

题解未完待续……

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值