NOIP2009解题报告(C/C++)(潜伏者)(Hankson的趣味题)(最优贸易)(靶形数独)
来源:互联网 发布:linux mint 18.2 安装 编辑:程序博客网 时间:2024/06/04 23:21
2017.3.4的校内赛
这一次我们进行了NOIP2009的真题测试,算是我这几次以来最好的一次,这归功于第三题的思路较为简单和第二题的暴力能够过1/2的点。但是这不意味着这一套题很简单,与之想法,这套题稍有不慎就会有过失性失分,比如第一题容易看漏条件。下面我们来看看:
1.潜伏者
解题报告:
这道题利用筒的思路,搞一个“字典”,将一个字母的序号(ASCII码减去’a’)作为下标,将与之相对应的字母的序号存储到数组中就可以了,需要注意的是,除了不能A数组中的对应关系必须是一对一的以外,B数组也是这样。
下面来看看代码:
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int N=100;const int M=26;char s1[N+5],s2[N+5],s3[N+5];int len1,len2,len3;int map[M+1];int main(){ freopen("spy.in","r",stdin); freopen("spy.out","w",stdout); memset(map,-1,sizeof(map)); scanf("%s",s1); scanf("%s",s2); scanf("%s",s3); len1=strlen(s1),len2=strlen(s2),len3=strlen(s3); for(int i=0;i<=len1-1;i++) { if(map[s1[i]-'A']!=-1&&map[s1[i]-'A']!=s2[i]-'A')//没有一个下标对应两个字母的情况 { printf("Failed"); return 0; } map[s1[i]-'A']=s2[i]-'A'; } for(int i=0;i<=24;i++) for(int j=i+1;j<=25;j++) if(map[i]==map[j])//没有两个字母对应一个下标的情况 { printf("Failed"); return 0; } for(int i=0;i<=25;i++)//26个字母要集齐 if(map[i]==-1) { printf("Failed"); return 0; } for(int i=0;i<=len3-1;i++) printf("%c",map[s3[i]-'A']+'A'); return 0;}
2.Hankson的趣味题
解题报告:
这道题我先是想到了用暴力的方法,因为他的数据范围设这样的:
可见,我们通过最小公倍数(gcd)和最大公因数(lcm)的求解方法,可以通过枚举(枚举到b1)的方法没举出所有可能的值。
这样的暴力法不难想出,我就不细讲了。这种算法可以得50分。
那么正解是怎么样呢?我们通过观察gcd和lcm的性质,可以发现,我们只需要枚举到sqrt(b1)就可以利用其性质推出其余可能的解,而这样就不会超时。代码如下:
#include<stdio.h>#include<math.h>#include<string.h>#include<algorithm>using namespace std;const int N=10000;int t,a0,a1,b0,b1;int num,tot;int gcd(int a,int b){ return b==0?a:gcd(b,a%b);}int lcm(int a,int b){ return (a/gcd(a,b))*b;}bool judge(int i){ return(i%a1!=0)?0:(gcd(i/a1,a0/a1)==1&&gcd(b1/i,b1/b0)==1);//保证满足题意 }int main(){ freopen("son.in","r",stdin); freopen("son.out","w",stdout); scanf("%d",&t); while(t--) { tot=0; scanf("%d%d%d%d",&a0,&a1,&b0,&b1); for(int i=1;i*i<=b1;i++)//不能用sqrt,会超时 { if(b1%i==0) { if(judge(i))tot++; if(i*i!=b1&&judge(b1/i))tot++;//推出其余可能的解 } } printf("%d\n",tot); } return 0;}
(此外,这道题也可以用整数的唯一分解定理来做,想来也不难理解)
3.最优贸易
解题报告:
这道题是我为数不多的能够AC得图论的题,其思路非常简洁明了:就是用两次广搜(或者说是SPFA)。第一次我们从头到尾更新出最小的点权,第二次我们从尾到头更新出最大的点权。再将路过每个点时所经过的最大最小点权的两个数组一一枚举,找到最大差值就可以了。
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int M=500000;const int N=100000;int n,m;int head1[N+5],head2[N+5],num=0;int w[N];int minn[N+5],maxx[N+5];struct edge{ int next1,next2,u,v; edge(){next1=-1;next2=-1; }};struct edge ed[2*M+5];void build(int u,int v){ num++; ed[num].u=u; ed[num].v=v; ed[num].next1=head1[u]; head1[u]=num; ed[num].next2=head2[v];//为了满足从未到头找的性质,我们必须建一个反过来的图 head2[v]=num;}void bfs1()//从头到尾找最小 { int front=0,rear=1; int state[N],flag[N]; memset(flag,0,sizeof(flag)); memset(minn,0x7f,sizeof(minn)); state[rear]=1,minn[1]=w[1],flag[1]=1; do { front++; int u=state[front]; flag[u]=0; for(int i=head1[u];i!=-1;i=ed[i].next1) { int v=ed[i].v; if(minn[v]>minn[u]||w[v]<minn[v]) { minn[v]=min(w[v],minn[u]); if(flag[v]==0)state[++rear]=v; flag[v]=1; } } }while(front<rear);}void bfs2()//从尾到头找最大 { int front=0,rear=1; int state[N],flag[N]; memset(flag,0,sizeof(flag)); memset(maxx,-1,sizeof(maxx)); state[rear]=n,maxx[n]=w[n],flag[n]=1; do { front++; int u=state[front]; for(int i=head2[u];i!=-1;i=ed[i].next2) { int v=ed[i].u; if(maxx[u]>maxx[v]||w[v]>maxx[v]) { maxx[v]=max(w[v],maxx[u]); if(flag[v]==0)state[++rear]=v; flag[v]=1; } } flag[u]=0; }while(front<rear);}int main(){ freopen("trade.in","r",stdin); freopen("trade.out","w",stdout); memset(head1,-1,sizeof(head1)); memset(head2,-1,sizeof(head2)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&w[i]); for(int i=1;i<=m;i++) { int u,v,k; scanf("%d%d%d",&u,&v,&k); if(k==1)build(u,v); if(k==2) { build(u,v); build(v,u); } } bfs1(); bfs2(); int ans=-1; for(int i=1;i<=n;i++)//一一枚举找最大值 ans=max(ans,maxx[i]-minn[i]); printf("%d",ans); return 0;}
此外,据说这道题也可以用Tarjan+缩点的方法做出来,反正我是不会的~
4.靶形数独
解题报告:
这道题我刚开始想用DP来做,但是很快我认识到了自己的幼稚。由于这道题数据较小(宫格数较小),可以直接用搜索来解决。但只用搜索的话注定会超时,所以我们还需要位运算。下面我们看一看大神的代码:
#include <iostream>#include <cstdlib>#include <cstdio>using namespace std;const int mlen = 10;int a[mlen][mlen],b[mlen][mlen];int row[mlen],lie[mlen],line[mlen],ma[mlen];int f[512],ans,node[mlen],cnt[mlen];void init() { for(int i = 0; i < 9; i++) b[i][0] = b[0][i] = b[8][i] = b[i][8] = 6; for(int i = 1; i < 8; i++) b[i][1] = b[1][i] = b[7][i] = b[i][7] = 7; for(int i = 2; i < 7; i++) b[i][2] = b[2][i] = b[6][i] = b[i][6] = 8; for(int i = 3; i < 6; i++) b[i][3] = b[3][i] = b[5][i] = b[i][5] = 9; b[4][4] = 10; int t = 0; for(int i = 1, j = 0; i <= 511; i <<= 1, j++) f[i] = j; for(int i = 0; i < 9; i++) for(int j = 0; j < 9; j++) { scanf("%d",&a[i][j]); if(a[i][j] != 0){ row[i] |= 1<<j; t = 1<<(a[i][j]-1); if((lie[i]&t) || (line[j]&t) || (ma[i/3*3+j/3]&t)) { printf("-1\n"); exit(0); } lie[i] |= t; line[j] |= t; ma[i/3*3+j/3] |= t; }else cnt[i]++; }}inline void sore() { int nowans = 0; for(int i = 0; i < 9; i++) for(int j = 0; j < 9; j++) nowans += a[i][j]*b[i][j]; if(ans < nowans) ans = nowans;}void dfs(int t) { int pos,k; if(t == 9) { sore(); return; } int i = node[t]; if(!cnt[i]) { dfs(t+1); return; } cnt[i]--; int p = (511^row[i])&(-(511^row[i])); row[i] |= p; int j = f[p]; pos = 511^(lie[i]|line[j]|ma[i/3*3+j/3]); while(pos > 0) { k = pos&(-pos); pos ^= k; lie[i] |= k; line[j] |= k; ma[i/3*3+j/3] |= k; a[i][j] = f[k]+1; dfs(t); lie[i] ^= k; line[j] ^= k; ma[i/3*3+j/3] ^= k; } cnt[i]++; row[i] ^= p;}int main() { freopen("sudoku.in","r",stdin); freopen("sudoku.out","w",stdout); init(); for(int i = 0; i < 9; i++) node[i] = i; for(int i = 0; i < 9; i++) for(int j = i+1; j < 9; j++) if(cnt[node[i]] > cnt[node[j]]) node[i] ^= node[j], node[j] ^= node[i], node[i] ^= node[j]; int tot = 0; while(!cnt[node[tot]]) tot++; dfs(tot); if(!ans) { printf("-1\n"); return 0; } printf("%d\n",ans); return 0;}
以上
2017.3.9
- NOIP2009解题报告(C/C++)(潜伏者)(Hankson的趣味题)(最优贸易)(靶形数独)
- NOIP 2009 解题报告(潜伏者,hankson的趣味题,最有贸易,靶形数独)
- NOIP2009 题解 潜伏者 Hankson的趣味题 最优贸易 靶形数独
- NOIP2009 潜伏者 Hankson的趣味题 最优贸易 靶形数独
- Noip 2009 解题报告(潜伏着,Hankson的趣味题,最优贸易,靶形数独)
- [NOIP2009]潜伏者,Hankson's Problem,最优贸易,靶形数独
- Hankson的趣味题[NOIP2009]解题报告
- 【noip2009提高组】 Hankson 的趣味题 欧几里得(数论)
- noip2009 靶形数独 (搜索)
- NOIP2009靶形数独(DFS)
- [NOIP2009]最优贸易(spfa)
- noip2009 最优贸易(SPFA)
- NOIP2009最优贸易 (tarjan+dfs)
- noip2009 最优贸易 (spafa+链表)
- 【NOIP2009】靶形数独 DLX(Dancing Links)
- noip2009 靶形数独 (代码还算不丑)
- 【noip2009】靶形数独(搜索+二进制优化)
- noip2009 hankson的趣味题 (扩展欧几里得求最大公约数,最小公倍数与最大公约数)
- RecyclerView 点击事件
- leetcode-20. Valid Parentheses
- The Largest Generation
- php array_multisort 二维数组排序
- 图结构练习——BFS——从起始点到目标点的最短步数
- NOIP2009解题报告(C/C++)(潜伏者)(Hankson的趣味题)(最优贸易)(靶形数独)
- 转:php防止sql注入的一点心得
- iOS应用架构谈 开篇
- Java文件读取范例
- 推箱子的最优路径
- 组件嵌套
- java循环判断的使用
- 如何使linux系统下的root用户不保存终端历史记录
- oracle 用户与表空间关系