[NOIP2009]潜伏者,Hankson's Problem,最优贸易,靶形数独
2017-03-05 13:25
531 查看
这一年的题感到有些奇怪,跟做前后两年的题感觉都不一样,还是有一点难度的。虽然据计算骗分也能达到一等奖的分数,但就是没骗到啊。那年全省没有满分的,但现在时代变了,能得满分的人估计也很多,还是提高打模板的能力,不然知道怎么做都做不出来。
Problem 1: 潜伏者
Problem 2: Hankson’s Problem
Problem3 最优贸易
Problem4:靶形数独
题目略
Problem 1: 潜伏者
R国和S国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动。 历经艰险后,潜伏于S国的R国间谍小C终于摸清了S国军用密码的编码规则: 1、 S国军方内部欲发送的原信息经过加密后在网络上发送,原信息的内容与加密后所的内容均由大写字母‘A’—‘Z’构成(无空格等其他字母)。 2、 S国对于每个字母规定了对应的“密字”。加密的过程就是将原信息中的所有字母替换为其对应的“密字”。 3、 每个字母只对应一个唯一的“密字”,不同的字母对应不同的“密字”。“密字”可以和原字母相同。 例如,若规定‘A’的密字为‘A’,‘B’的密字为‘C’(其他字母及密字略),则原信息“ABA”被加密为“ACA”。 现在,小C通过内线掌握了S国网络上发送的一条加密信息及其对应的原信息。小C希望能通过这条信息,破译S国的军用密码。小C的破译过程是这样的:扫描原信息,对于原信息中的字母x(代表任一大写字母),找到其在加密信息中的对应大写字母y,并认为在密码里y是x的密字。如此进行下去直到停止于如下的某个状态: 1、 所有信息扫描完毕,‘A’—‘Z’所有26个字母在原信息中均出现过并获得了相应的“密字”。 2、 所有信息扫描完毕,但发现存在某个(或某些)字母在原信息中没有出现。 3、 扫描中发现掌握的信息里有明显的自相矛盾或错误(违反S过密码的编码规则)。例如某条信息“XYZ”被翻译为“ABA”就违反了“不同字母对应不同密字”的规则。 在小C忙得头昏脑胀之际,R国司令部又发来电报,要求他翻译另外一条从S国刚刚截取到的加密信息。现在请你帮助小C:通过内线掌握的信息,尝试破译密码。然后利用破译的密码,翻译电报中的加密信息。 输入文件名为spy.in,共3行,每行为一个长度在1到100之间的字符串。 第1行为小C掌握的一条加密信息。 第2行为第1行的加密信息所对应的原信息。 第3行为R国司令部要求小C翻译的加密信息。 输入数据保证所有字符串仅由大写字母‘A’—‘Z’构成,且第1行长度与第2行相等。 输出文件spy.out共1行。 若破译密码停止时出现2,3两种情况,请你输出“Failed”(不含引号,注意首字母大写,其它小写)。 否则请输出利用密码翻译电报中加密信息后得到的原信息 存正向翻译和逆向翻译,因为两边翻译矛盾都会错误
#include<cstdio> #include<cstring> #include<iostream> using namespace std; char s1[105],s2[105],x[105],s3[105]; char mima[30],scre[30]; int main() { freopen("spy.in","r",stdin); freopen("spy.out","w",stdout); scanf("%s",s1); scanf("%s",s2); scanf("%s",s3); int len3 = strlen(s3); int len1 = strlen(s1); int len2 = strlen(s2); if(len1 != len2){ printf("Failed");return 0; } for(int i = 0; i < len1; i++ ) { if(mima[s2[i]-64] != 0 && mima[s2[i]-64] != s1[i]){ printf("Failed");return 0; } if(scre[s1[i]-64] != 0 && scre[s1[i]-64] != s2[i]){ printf("Failed");return 0; } if(scre[s1[i]-64] == 0) scre[s1[i]-64] = s2[i]; if(mima[s2[i]-64] == 0) mima[s2[i]-64] = s1[i]; } for(int i = 1; i <= 26; i++ ) if(!scre[i]){ printf("Failed");return 0; } for(int i = 0; i < len3; i++ ) if( !scre[s3[i]-64] ){ printf("Failed");return 0; } for(int i = 0; i < len3; i++ ) printf("%c",scre[s3[i]-64]); return 0; }
Problem 2: Hankson’s Problem
已知正整数a0,a1,b0,b1,设某未知正整数x满足: 1、 x和a0的最大公约数是a1; 2、 x和b0的最小公倍数是b1。 Hankson的“逆问题”就是求出满足条件的正整数x。但稍加思索之后,他发现这样的x并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的x的个数。请你帮助他编程求解这个问题。 因为是很大的数,穷举绝对会T掉,但我们知道数的唯一分解定理,可以筛法求出前40000个素数,存在一个数组里面,找每一个素数的值再在总数上乘一个这个值,如果不符合,就乘一个0.
#include<cmath> #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define LL long long; using namespace std; int T,a0,a1,b0,b1; int pri[200005],pd[200005],top,ans; void fdprime() { for(int i = 2; i <= 40000; i++ ) { if(!pd[i]){top++;pri[top]=i;} for(int j = 1; j <= top && pri[j]*i <= 40000; j++ ) { pd[pri[j]*i]=1; if(i%pri[j]==0) break; } } } void find(int x) { int c0 = 0,c1 = 0,c2 = 0,c3 = 0; while(a0 % x == 0) {a0 /= x; c0++;} while(a1 % x == 0) {a1 /= x; c1++;} while(b0 % x == 0) {b0 /= x; c2++;} while(b1 % x == 0) {b1 /= x; c3++;} if(c1 > c0 || c2 > c3) ans *= 0; else if(c0 == c1 && c2 == c3) { if (c1 <= c3) ans *= c3-c1+1; else ans *= 0; } else if(c0==c1&&c2<c3) { if (c1<=c3) ans*=1; else ans*=0; } else if(c0>c1&&c2==c3) { if (c1<=c3) ans*=1; else ans*=0; } else if (c1 != c3) ans*=0; } void work() { int i; ans=1; for( i = 1; i <= top; i++ ) find(pri[i]); if(a0 != 1) find(a0); if(b1 != 1) find(b1); printf("%lld\n",ans); } int main(){ freopen("son.in","r",stdin); freopen("son.out","w",stdout); scanf("%d",&T); fdprime(); while(T--){ scanf("%d%d%d%d",&a0,&a1,&b0,&b1); work(); } return 0; }
Problem3 最优贸易
【问题描述】 C 国有n 个大城市和m 条道路,每条道路连接这n 个城市中的某两个城市。任意两个 城市之间最多只有一条道路直接相连。这m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路,双向通行的道路在统计条数时也计为1 条。 C 国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价 格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。 商人阿龙来到 C 国旅游。当他得知同一种商品在不同城市的价格可能会不同这一信息 之后,便决定在旅游的同时,利用商品在不同城市中的差价赚回一点旅费。设C 国n 个城 市的标号从1~ n,阿龙决定从1 号城市出发,并最终在n 号城市结束自己的旅行。在旅游的 过程中,任何城市可以重复经过多次,但不要求经过所有n 个城市。阿龙通过这样的贸易方 式赚取旅费:他会选择一个经过的城市买入他最喜欢的商品——水晶球,并在之后经过的另 一个城市卖出这个水晶球,用赚取的差价当做旅费。由于阿龙主要是来C 国旅游,他决定 这个贸易只进行最多一次,当然,在赚不到差价的情况下他就无需进行贸易。 假设 C 国有5 个大城市,城市的编号和道路连接情况如下图,单向箭头表示这条道路 为单向通行,双向箭头表示这条道路为双向通行。 假设 1~n 号城市的水晶球价格分别为4,3,5,6,1。 阿龙可以选择如下一条线路:1->2->3->5,并在2 号城市以3 的价格买入水晶球,在3 号城市以5 的价格卖出水晶球,赚取的旅费数为2。 阿龙也可以选择如下一条线路 1->4->5->4->5,并在第1 次到达5 号城市时以1 的价格 买入水晶球,在第2 次到达4 号城市时以6 的价格卖出水晶球,赚取的旅费数为5。 现在给出 n 个城市的水晶球价格,m 条道路的信息(每条道路所连接的两个城市的编号 以及该条道路的通行情况)。请你告诉阿龙,他最多能赚取多少旅费。 输入描述 Input Description 第一行包含 2 个正整数n 和m,中间用一个空格隔开,分别表示城市的数目和道路的 数目。 第二行 n 个正整数,每两个整数之间用一个空格隔开,按标号顺序分别表示这n 个城 市的商品价格。 接下来 m 行,每行有3 个正整数,x,y,z,每两个整数之间用一个空格隔开。如果z=1, 表示这条道路是城市x 到城市y 之间的单向道路;如果z=2,表示这条道路为城市x 和城市 y 之间的双向道路。 输出描述 Output Description 包含1 个整数,表示最多能赚取的旅费。如果没有进行贸易, 则输出0。 样例输入 Sample Input 5 5 4 3 5 6 1 1 2 1 1 4 1 2 3 2 3 5 1 4 5 2 样例输出 Sample Output 5 数据范围及提示 Data Size & Hint 1≤n≤100000,1≤m≤500000,水晶球价格≤100 其实我是不想写这道题的题解的,这道题为什么与图论有关,因为它有可能有强连通分量,缩点后就是很弱鸡了,前五个点就不用缩,但我还是做错了真是悲哀,现在也没用tarjan写,只用了个双向SPFA一个方向搜最小值,一个方向搜最大值就可以了,注意要用两个邻接表存。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> using namespace std; const int MX = 100005; int ans; int value[MX],head[MX*2],vest[MX*2],next[MX*2],tail = 1; int had[MX*2],vast[MX*2],naxt[MX*2],minn[MX*2],maxn[MX*2]; bool b[MX*2]; void adde(int a,int b) { vest[tail] = b; next[tail] = head[a]; head[a] = tail; vast[tail] = a; naxt[tail] = had[b]; had[b] = tail; tail++; } void spfa(int s,int t) { queue<int>que; memset(minn,127/3,sizeof(minn)); memset(b,0,sizeof(b)); minn[s] = value[s]; b[s] = 1; que.push(s); while( !que.empty() ) { int u=que.front(); que.pop(); for(int v = head[u]; v; v = next[v]){ if(minn[vest[v]] > minn[u]) { minn[vest[v]] = min(minn[u], value[vest[v]]); if( !b[vest[v]] ) { b[vest[v]] = 1; que.push(vest[v]); } } } } } void SPFA(int s,int t) { queue<int>que; memset(maxn,0,sizeof(maxn)); memset(b,0,sizeof(b)); maxn[s]=value[s]; b[s]=1; que.push(s); while(!que.empty()) { int u=que.front(); que.pop(); for(int v = had[u]; v; v = naxt[v]){ if(maxn[vast[v]] < maxn[u]) { maxn[vast[v]] = max(maxn[u],value[vast[v]]); if( !b[vast[v]] ) { b[vast[v]]=1; que.push(vast[v]); } } } } } int main() { freopen("trade.in","r",stdin); freopen("trade.out","w",stdout); int n,m; scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++ ) scanf("%d", &value[i]); for(int i = 1; i <= m; i++ ) { int q,w,e; scanf("%d%d%d", &q, &w, &e); adde(q,w); if(e == 2) adde(w,q); } spfa(1,n); SPFA(n,1);//从终点回来 for(int i = 1; i <= n; i++ ) ans = max(ans,maxn[i]-minn[i]); printf("%d", ans); return 0; }
//Tarjan #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAXN = 100010, MAXM = 1000010; int N, M, ans; int head[MAXN*2],next[MAXN*2],vast[MAXN*2],tail; void addedge(int a,int b) { tail++; next[tail] = head[a]; head[a] = tail; vast[tail] = b; } int belong[MAXN], bcnt; int bmx[MAXN], bmn[MAXN]; int tmr, dfn[MAXN], low[MAXN]; int sta[MAXN], tp; int val[MAXN]; int x[MAXM], y[MAXM], type[MAXM]; bool insta[MAXN]; void tarjan(int u) { dfn[u] = low[u] = ++tmr; sta[++tp] = u; insta[u] = 1; for (int i = head[u]; i; i = next[i]) { int v = vast[i]; if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (insta[v]) low[u] = min(low[u], dfn[v]); } if (low[u] == dfn[u]) { ++bcnt; int i; do { i = sta[tp]; belong[i] = bcnt; bmx[bcnt] = max(bmx[bcnt], val[i]); bmn[bcnt] = min(bmn[bcnt], val[i]); insta[i] = 0; --tp; } while (tp>0 && i!=u); } } int f[MAXN]; bool vis[MAXN]; void dfs(int u) { vis[u] = 1; if (u == belong ) f[u] = max(f[u], bmx[u]); for (int p = head[u]; p; p = next[p]) { if (!vis[vast[p]]) dfs(vast[p]); f[u] = max(f[u], f[vast[p]]); } if (f[u]) f[u] = max(f[u], bmx[u]); ans = max(ans, f[u] - bmn[u]); } int main() { int i; scanf("%d%d", &N, &M); for (i = 1; i <= N; ++i) { scanf("%d", val+i); bmx[i]=-1, bmn[i]=999999; } for (i = 1; i <= M; ++i) { scanf("%d%d%d", &x[i], &y[i], &type[i]); addedge(x[i], y[i]); if (type[i] == 2) addedge(y[i], x[i]); } tarjan(1); memset(head,0,sizeof(head)); memset(vast,0,sizeof(vast)); memset(next,0,sizeof(next)); tail = 0; for (i = 1; i<= M; ++i) if (belong[x[i]] != belong[y[i]]) addedge(belong[x[i]], belong[y[i]]); dfs(belong[1]); printf("%d\n", ans); return 0; }
Problem4:靶形数独
题目略
#include<cstdio> #include<cmath> #include<cstring> #include<iostream> using namespace std; int ans=-1,a[10][10],b[10][10],c[10][10]; int f1[10][10],f2[10][10],f3[10][10]; void work(int deft) {//深搜 int s = 0,x1,y1,ds = 10; for(int i = 1; i <= 9; i++ ) for(int j = 1; j <= 9; j++ ) if(a[i][j] == 0){ int s = 0; for(int k = 1; k <= 9; k++ ) if(!f1[c[i][j]][k] && !f2[i][k] && !f3[j][k] ) s++; if(s < ds) ds = s,x1 = i,y1 = j;//存在情况最少的点 } if(ds == 10) {//点都找完了 int k = 0; for(int i = 1; i <= 9; i++ ) for(int j = 1; j <= 9; j++ ) k += a[i][j] * b[i][j]; ans = max(ans,k); return ; } if(ds == 0) return ; for(int k = 1; k <= 9; k++ ) if( !f1[c[x1][y1]][k] && !f2[x1][k] && !f3[y1][k]) { a[x1][y1] = k; f1[c[x1][y1]][k] = f2[x1][k] = f3[y1][k] = 1; work(deft+1); a[x1][y1] = 0; f1[c[x1][y1]][k] = f2[x1][k] = f3[y1][k] = 0; } } int main() { freopen("sudoku.in","r",stdin); freopen("sudoku.out","w",stdout); for(int i=1;i<=9;i++) for(int j=1;j<=9;j++) { scanf("%d",&a[i][j]); b[i][j]=10-max(abs(i-5),abs(j-5));//存分数 c[i][j]=(i-1)/3*3+(j-1)/3+1;//分成9个九宫格 f1[c[i][j]][a[i][j]]=1;//该小九宫格存进該点 f2[i][a[i][j]]=1;//列上的 f3[j][a[i][j]]=1;//存行上的 } work(1); printf("%d",ans); return 0; }
相关文章推荐
- Noip 2009 解题报告(潜伏着,Hankson的趣味题,最优贸易,靶形数独)
- NOIP 2009 解题报告(潜伏者,hankson的趣味题,最有贸易,靶形数独)
- NOIP2009 潜伏者 Hankson的趣味题 最优贸易 靶形数独
- NOIP2009解题报告(C/C++)(潜伏者)(Hankson的趣味题)(最优贸易)(靶形数独)
- NOIP2009 题解 潜伏者 Hankson的趣味题 最优贸易 靶形数独
- NOIP2009最优贸易——史上最详细解析
- [DLX] [NOIP2009] 靶形数独
- 【NOIP2009提高组T4】靶形数独-DFS剪枝+位运算优化
- NOIP 2009 最优贸易
- NOIP 2009 最优贸易
- 【NOIP 2009 提高组】靶形数独
- noip2009 最优贸易 两次SPFA题解
- NOIP 2009 靶形数独
- Noip2009最优贸易题解
- NOIP2009 最优贸易(BFS)
- NOIP 2009 Senior 3 - 最优贸易
- 洛谷1037 NOIP2009 最优贸易
- NOIP 2009 最优贸易
- NOIP2009 最优贸易
- [NOIP2009 最优贸易]