NOIP2015模拟
一、小Y的绝对战争
【问题描述】
小Y与大黄爆发了一场绝对要胜利的战争。(原因是大黄生活作风问题)
小Y现在拥有N个城池,每个城池都有一个强大值
Wi
。
现在没有一条通路连接任意两个城池(通路是双向的)。
现在小Y想顺次修建若干条通路,使得每修建一条通路都连接了两个原本不连通的城池(联通的定义是两个城池之间存在一条由通路构成的路径)。
每修建一条通路 I->J,那么安全值就会增加
Gcd(Wi,Wj)
。
为了确保这场战争的胜利,小Y想知道,可能的最大安全值是多少(囧)。
【输入】
输入文件名为war.in。
第一行一个正整数
N
,代表城池的个数。
接下来
【输出】
输出文件名为war.out。
一行一个整数,代表最大的安全值。
【输入样例】
4
1
2
3
4
【输出样例】
4
【数据范围】
对于
30%
的数据,保证有
n≤1000
。
对于
100%
的数据,保证有
n≤1000000
, 任意
W
小于等于
Solution
很恶心的题目,连Kruskal都打错了的我果断零分。
因为权值在
1
到
对于一个权值
I
,可以取的所有点就是
这样,时间复杂度就降低为
O(NlnN)
。
这个,时间复杂度为
O(NlnN)
请自行证明。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#define Max(x,y) ((x)>(y)?(x):(y))
#define LL long long
using namespace std;
LL n,maxn,cnt,ans;
LL fa[1000010];
LL find(LL x){
LL tmp=x,pre;
while(tmp!=fa[tmp])tmp=fa[tmp];
while(x!=tmp){
pre=fa[x];
fa[x]=tmp;
x=pre;
}
return tmp;
}
int main(){
freopen("war.in","r",stdin);
freopen("war.out","w",stdout);
scanf("%lld",&n);
for(LL i=1;i<=n;i++){
LL x;
scanf("%lld",&x);
if(fa[x]==x)ans+=x;
fa[x]=x;
maxn=Max(x,maxn);
}
for(LL i=maxn;i>=1&&cnt<n-1;i--){
LL big=maxn/i,tmp,ft;
bool first=true;
for(LL j=1;j<=big;j++)if(fa[i*j]){
if(first)tmp=i*j,ft=find(tmp),first=false;
else{
LL ff=find(i*j);
if(ff==ft)continue;
fa[ff]=ft;ans+=i;cnt++;
}
}
}
printf("%lld\n",ans);
return 0;
}
二、小Y的数学作业
【问题描述】
小Y是个很好学的孩子。(附注:Y=yang)
最近老师总是布置给他(或者她)一些数学作业题,每道作业题就是求一个数
X
与数字
这天晚上11:00,大黄到小Y家去“玩”,不小心弄翻了小Y的咖啡,结果
N
道题的数字
小Y很急,想问你对于每一道数学作业题,到底有多少种
【输入】
输入文件名为homework.in。
第一行一个整数
N
,代表数学老师布置的题目数量。
接下来
【输出】
输出文件名为homework.out
对于每个数学题,若存在这样的X,即输出合法的
X
的个数,否则输出
【输入样例】
2
41 1 96 288
95 1 37 1776
【输出样例】
6
2
【数据范围】
对于
50%
的数据,保证有
1≤A,A1,B,B1≤10000
且
n≤100
。
对于
100%
的数据,保证有
1≤A,A1,B,B1≤2,000,000,000
且
n≤2000
。
Solution
所以分解质因数:
对于
AA1
里有的质因子,
x
的指数必须和
对于
BB1
里有的质因子,
x
的指数必须和
x
的所有质因子的指数必须大于等于
对于一个质因子,若
x
的指数的上界为
若
x
的指数需等于
Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
LL n,a,a1,b,b1;
LL prima[100],primb1[100];
LL ca1[100],prima1[100],ca[100],cb1[100],pca[100],pcb1[100],pca1[100];
LL need_b[100],need_a[100];
LL prime[1000010];
bool no_prime[1000010];
bool flagb[100],flaga[100];
inline LL in(){
char x=getchar();
LL ans=0;
while(x<'0'||x>'9')x=getchar();
while(x>='0'&&x<='9'){ans=ans*10+x-'0';x=getchar();}
return ans;
}
void start(){
for(LL i=2;i<=1000000;i++){
if(!no_prime[i])prime[++prime[0]]=i;
for(LL j=1;prime[j]*i<=1000000;j++){
no_prime[prime[j]*i]=true;
if(i%prime[j]==0)break;
}
}
}
int main(){
freopen("homework.in","r",stdin);
freopen("homework.out","w",stdout);
start();
n=in();
while(n--){
memset(flaga,0,sizeof flaga);memset(flagb,0,sizeof flagb);
memset(need_b,0,sizeof need_b);memset(need_a,0,sizeof need_a);
ca1[0]=prima1[0]=ca[0]=pca1[0]=cb1[0]=pca[0]=pcb1[0]=prima[0]=primb1[0]=0;
LL ans=1;
a=in();a1=in();b=in();b1=in();
LL sqra=sqrt(a),sqra1=sqrt(a1),sqrb=sqrt(b),sqrb1=sqrt(b1);
LL tma=a,tma1=a1,tmb=b,tmb1=b1;
for(LL i=1;prime[i]<=sqra;i++){
if(tma%prime[i]==0){
prima[++prima[0]]=prime[i],ca[++ca[0]]=0,pca[++pca[0]]=1;
while(tma%prime[i]==0){
ca[ca[0]]++;
tma/=prime[i];
pca[pca[0]]*=prime[i];
}
}
}
if(tma!=1){prima[++prima[0]]=pca[++pca[0]]=tma;ca[++ca[0]]=1;}
for(LL i=1;prime[i]<=sqra1;i++){
if(tma1%prime[i]==0)prima1[++prima1[0]]=prime[i],ca1[++ca1[0]]=0,pca1[++pca1[0]]=1;
while(tma1%prime[i]==0){
ca1[ca1[0]]++;
tma1/=prime[i];
pca1[pca1[0]]*=prime[i];
}
}
if(tma1!=1){prima1[++prima1[0]]=pca1[++pca1[0]]=tma1;ca1[++ca1[0]]=1;}
for(LL i=1;prime[i]<=sqrb1;i++){
if(tmb1%prime[i]==0)primb1[++primb1[0]]=prime[i],cb1[++cb1[0]]=0,pcb1[++pcb1[0]]=1;
while(tmb1%prime[i]==0){
cb1[cb1[0]]++;
tmb1/=prime[i];
pcb1[pcb1[0]]*=prime[i];
}
}
if(tmb1!=1){primb1[++primb1[0]]=pcb1[++pcb1[0]]=tmb1;cb1[++cb1[0]]=1;}
for(LL i=1;i<=primb1[0];i++){
if(b%primb1[i]!=0)need_b[i]=cb1[i];
else if(b%pcb1[i]==0)need_b[i]=-1;
else need_b[i]=cb1[i];
}
for(LL i=1;i<=prima[0];i++){
if(a1%prima[i]!=0){need_a[i]=0;}
else if(a1%pca[i]==0)need_a[i]=-1;
else{
for(LL j=1;j<=prima1[0];j++)
if(prima1[j]==prima[i])need_a[i]=ca1[j];
}
}
for(LL i=1;i<=primb1[0];i++){
flagb[i]=false;
for(LL j=1;j<=prima[0];j++){
if(primb1[i]==prima[j]){
flagb[i]=flaga[j]=true;
if(need_b[i]==-1&&need_a[j]==-1){
LL tttt;
for(LL k=1;k<=prima1[0];k++)if(prima1[k]==prima[j])tttt=ca1[k];
if(cb1[i]<tttt){ans=0;goto nxt;}
else ans=ans*(cb1[i]-tttt+1);
}
else if(need_b[i]==-1&&need_a[j]!=-1){
if(need_a[j]>cb1[i]){ans=0;goto nxt;}
}
else if(need_a[j]==-1&&need_b[i]!=-1){
LL tttt;
for(LL k=1;k<=prima1[0];k++)if(prima1[k]==prima[j])tttt=ca1[k];
if(need_b[i]<tttt){ans=0;goto nxt;}
}
else if(need_a[j]!=-1&&need_b[i]!=-1&&need_a[j]!=need_b[i]){ans=0;goto nxt;}
break;
}
}
if(!flagb[i]){
if(need_b[i]==-1)ans=ans*(cb1[i]+1);
}
}
for(LL i=1;i<=prima[0];i++)
if(!flaga[i]&&need_a[i]==-1){
ans=INF;
break;
}
nxt:
printf("%lld\n",ans);
}
}
三、小Y的智力游戏
【问题描述】
小Y最近迷上了一款智力游戏。(当然小Y还是很好学的)
这款智力游戏就是让你从
1
到
他(或她,以后这个括号就省略了)想知道最大得分对
【输入】
输入文件名game.in
一行一个正整数
N
,代表数字的个数。
【输出】
输出文件名game.out
一行一个正整数,代表最大得分对
【输入样例】
3
【输出样例】
1
【数据范围】
对于
30%
的数据,保证有
n≤50
。
对于
60%
的数据,保证有
n≤1000
。
对于
70%
的数据,保证有
n≤10000
。
对于
80%
的数据,保证有
n≤100000
。
对于
90%
的数据,保证有
n≤1000000
。
对于
100%
的数据,保证有
n≤3000000
。
Solution
将 n! 唯一分解,然后将指数为奇数的质因子的指数减去一,得到的唯一分解式就是答案(想一想,为什么)。
Code
#include <iostream>
#include <cstdio>
#include <cmath>
#define Max(x,y) ((x)>(y)?(x):(y))
#define MOD 1000000007
#define LL long long
using namespace std;
LL n,ans=1;
LL prime[3000010];
bool no_prime[3000010];
LL ci[3000010];
LL first[3000010];
void work(int x){
if(x==1)return;
LL tmp=first[x];
while(x%prime[tmp]==0){
x/=prime[tmp];
ci[tmp]++;
}
work(x);
}
LL power(LL x,LL y,LL p){
if(y==0)return 1;
if(y==1)return x%p;
LL tmp=power(x,y/2,p);
tmp=tmp*tmp%p;
if(y&1)tmp=tmp*(x%p)%p;
return tmp;
}
int main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
scanf("%lld",&n);
for(LL i=2;i<=n;i++){
if(!no_prime[i]){prime[++prime[0]]=i;first[i]=prime[0];}
for(LL j=1;prime[j]*i<=n;j++){
first[prime[j]*i]=j;
no_prime[prime[j]*i]=true;
if(i%prime[j]==0)break;
}
}
for(LL i=2;i<=n;i++)work(i);
for(LL i=1;i<=prime[0];i++){
if(ci[i]&1)ans=ans*power(prime[i],ci[i]-1,MOD)%MOD;
else ans=ans*power(prime[i],ci[i],MOD)%MOD;
}
printf("%lld\n",ans);
return 0;
}