NOIP2009提高组

2009提高
A.潜伏者(模拟)
B.Hankson 的趣味题(素数筛+数论+分解质因数)
a1,a2的最大公因数为a0,则对于每一个质因子,他在a0中的指数为a1,a2中的最小值,即反过来,如果a1中的指数为x1,a0中的指数为x0,x1>x0,则a2中的指数x2必为x0.如果x1==x0,则x2>=x0.最小公倍数同理。这样我们就能得出每一个质因子的指数的取值范围,根据乘法原理算出答案。考虑如何质因数分解,我们只能筛出 2e9=45000 以内的质数,我们把这些质因数都统计出来之后,如果还剩下了x,且x不为1,则x一定是一个大质数。把它暂时加入prime中即可。
C.最优贸易(spfa+枚举)
两遍spfa,具体见题解
D.靶形数独(搜索+剪枝)
玄学剪枝。每次找一个候选数最少的地方填,减小搜索树的规模。

A

#include<cstdio>
#include<cstring>
char str1[100],str0[100],str2[100],str[100];
bool flag[100];
int main(){
    //freopen("a.in","r",stdin);
    memset(str,0,sizeof(str));
    memset(flag,0,sizeof(flag));
    scanf("%s%s%s",str0,str1,str2);
    for(int i=0;i<strlen(str0);++i){
        if(str[str0[i]]!=0&&str[str0[i]]!=str1[i]){puts("Failed");return 0;}
        str[str0[i]]=str1[i];flag[str1[i]]=1;
    }for(int i='A';i<='Z';++i) 
        if(str[i]==0||!flag[i]) {puts("Failed");return 0;}
    for(int i=0;i<strlen(str2);++i) putchar(str[str2[i]]);
    return 0;
} 

B

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 45010
inline int read(){
    int x=0,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();
    return x*f;
}
int tst,a1,a2,b1,b2,a[N],aa[N],b[N],bb[N],ans,prime[N],tot=0;
bool notprime[N];
void getprime(){
    notprime[1]=1;
    for(int i=2;i<=45000;++i){
        if(!notprime[i]) prime[++tot]=i;
        for(int j=1;prime[j]*i<=45000;++j){
            notprime[prime[j]*i]=1;
            if(i%prime[j]==0) break;
        }
    }
}
void work(int x,int num[]){
    for(int i=1;i<=tot;++i){
        num[i]=0;
        while(x%prime[i]==0){
            x/=prime[i];num[i]++;
        }
    }if(x!=1) prime[++tot]=x,num[tot]=1;
}
int main(){
//  freopen("a.in","r",stdin);
    tst=read();getprime();
    while(tst--){
        a1=read(),a2=read(),b1=read(),b2=read();ans=1;
        work(a1,a);work(a2,aa);work(b1,b);work(b2,bb);
        for(int i=1;i<=tot;++i){
            if(a[i]!=aa[i]&&b[i]!=bb[i]){
                if(aa[i]!=bb[i]){ans=0;break;}continue;
            }if(a[i]!=aa[i]&&b[i]==bb[i]){
                if(aa[i]>b[i]){ans=0;break;}continue;
            }if(b[i]!=bb[i]){
                if(bb[i]<aa[i]){ans=0;break;}continue;
            }if(a[i]>b[i]){ans=0;break;}ans*=(b[i]-a[i]+1);
        }if(!ans) puts("0");
        else printf("%d\n",ans);while(prime[tot]>45000) --tot;
    }return 0;
}

C

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 100010
#define M 500010
#define inf 0x3f3f3f3f
inline int read(){
    int x=0,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();
    return x*f;
}
struct edge{
    int to,from,next1,next2;
}data[M<<1];
int n,m,a[N],mn[N],mx[N],h1[N],h2[N],num=0;
bool f[N];
void spfa1(){
    std::queue<int>q;
    memset(mn,0x3f,sizeof(mn));
    mn[1]=a[1];q.push(1);f[1]=1;
    while(!q.empty()){
        int x=q.front();q.pop();f[x]=0;
        for(int i=h1[x];i;i=data[i].next1){
            int y=data[i].to;
            if(mn[x]<mn[y]){
                mn[y]=std::min(mn[x],a[y]);
                if(!f[y]) q.push(y);f[y]=1;
            }
        }
    }
}
void spfa2(){
    std::queue<int>q;
    memset(mx,0,sizeof(mx));
    mx[n]=a[n];q.push(n);f[n]=1;
    while(!q.empty()){
        int x=q.front();q.pop();f[x]=0;
        for(int i=h2[x];i;i=data[i].next2){
            int y=data[i].from;
            if(mx[x]>mx[y]){
                mx[y]=std::max(mx[x],a[y]);
                if(!f[y]) q.push(y);f[y]=1;
            }
        }
    }
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();m=read();for(int i=1;i<=n;++i) a[i]=read();
    while(m--){
        int x=read(),y=read(),op=read();
        data[++num].from=x;data[num].to=y;
        data[num].next1=h1[x];h1[x]=num;
        data[num].next2=h2[y];h2[y]=num;
        if(op==1) continue;
        data[++num].from=y;data[num].to=x;
        data[num].next1=h1[y];h1[y]=num;
        data[num].next2=h2[x];h2[x]=num;
    }
    spfa1();spfa2();
    int ans=0;
    for(int i=1;i<=n;++i)
        if(mx[i]-mn[i]>ans) ans=mx[i]-mn[i];
    printf("%d\n",ans);
    return 0;
}

D

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
inline int read(){
    int x=0,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();
    return x*f;
}
bool r[10][10],l[10][10],s[10][10];//行,列,小九宫格 
int a[10][10],ans=-1,res=0,score[10][10][10],cnt=0,rnum[10],cnum[10];
int cal(int x,int y,int k){
    if(x==5&&y==5) return 10*k;
    if(x>=4&&x<=6&&y>=4&&y<=6)return 9*k;
    if(x>=3&&x<=7&&y>=3&&y<=7)return 8*k;
    if(x>=2&&x<=8&&y>=2&&y<=8)return 7*k;return 6*k;
}
bool fillin(int x,int y){
    int k=a[x][y];
    if(r[x][k]||l[y][k]||s[(x-1)/3*3+(y-1)/3][k]) return 0;
    r[x][k]=l[y][k]=s[(x-1)/3*3+(y-1)/3][k]=1;
    res+=score[x][y][k];cnt++;rnum[x]++;cnum[y]++;
    return 1;
}
void del(int x,int y){
    int k=a[x][y];r[x][k]=l[y][k]=s[(x-1)/3*3+(y-1)/3][k]=0;
    res-=score[x][y][k];cnt--;rnum[x]--;cnum[y]--;
}
void dfs(int x,int y){
    if(cnt==81){ans=max(ans,res);return;}
    for(int k=1;k<=9;++k){
        a[x][y]=k;
        if(fillin(x,y)){
            int xx=0,yy=0;
            for(int i=1;i<=9;++i)
                if(rnum[i]!=9&&rnum[i]>=rnum[xx]) xx=i;
            for(int i=1;i<=9;++i)
                if(!a[xx][i]&&cnum[i]>=cnum[yy]) yy=i;
            dfs(xx,yy);del(x,y);
        }a[x][y]=0;
    }
}
int main(){
//  freopen("a.in","r",stdin);
    for(int i=1;i<=9;++i)
        for(int j=1;j<=9;++j)
            for(int k=1;k<=9;++k)
                score[i][j][k]=cal(i,j,k);
    for(int i=9;i>=1;--i)
        for(int j=9;j>=1;--j){
            a[i][j]=read();if(!a[i][j]) continue;
            if(!fillin(i,j)){puts("-1");return 0;}
        }int x=0,y=0;
    for(int i=1;i<=9;++i)
        if(rnum[i]!=9&&rnum[i]>=rnum[x]) x=i;
    for(int i=1;i<=9;++i)
        if(!a[x][i]&&cnum[i]>=cnum[y]) y=i;
    dfs(x,y);printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值