[ NOIP 2008 ] TG
\(\\\)
\(\#A\) \(Word\)
给出一个长为\(N\)的小写字母串,判断出现所有字母中最多出现次数减最少出现次数得到的答案是否是质数。
- \(N\in [1,100]\)
- 直接按题意开桶记录,试除法判断即可。
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 30
#define M 110
#define R register
using namespace std;
bool v1[N],v2[N];
int to[N],now[M],p;
int main(){
char c=getchar();
while(!isupper(c)) c=getchar();
while(isupper(c)){
now[++now[0]]=c-'A'+1;
v1[c-'A'+1]=1; c=getchar();
}
for(R int i=1;i<=26;++i) if(!v1[i]){puts("Failed");return 0;}
while(!isupper(c)) c=getchar();
while(isupper(c)){
int x=now[++p];
if(to[x]){if('A'+to[x]-1!=c){puts("Failed");return 0;}}
else if(v2[c-'A'+1]){puts("Failed");return 0;}
else to[x]=c-'A'+1;
v2[c-'A'+1]=1; c=getchar();
}
while(!isupper(c)) c=getchar();
while(isupper(c)){
putchar((char)'A'+to[c-'A'+1]-1);
c=getchar();
}
return 0;
}
\(\\\)
\(\#B\) \(Matches\)
已知用火柴棒拼出每个数字所需要的数量,加号和等号各需要两根,求恰好用掉\(N\)根火柴棒构成等式\(A+B=C\)的数量,其中数字不能有前导零,当\(A\not=B\)时交换位置视作两个等式。
- \(N\in [0,24]\)
- 用暴力跑一跑,发现最大的数据范围能做到的等式数字大小不会超过\(1000\)。
- 于是预处理前\(1000\)个数每个数所需个数,\(N^2\)暴力枚举判断即可。
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define R register
using namespace std;
const int cost[10]={6,2,5,5,4,5,6,3,7,6};
int n,cnt,f[2500]={6};
inline void calc(int x){
int tmp=x,res=0;
while(tmp){
res+=cost[tmp%10];
tmp/=10;
}
f[x]=res;
}
int main(){
scanf("%d",&n); n-=4;
for(R int i=1;i<=2300;++i) calc(i);
for(R int i=0;i<=1111;++i)
for(R int j=0;j<=1111;++j)
if(f[i]+f[j]+f[i+j]==n) ++cnt;
printf("%d\n",cnt);
return 0;
}
\(\\\)
\(\#C\) \(Massage\)
给出一个\(N\times M\)的矩阵,选则两条从\((1,1)\)到\((N,M)\)的路径,使得两条路径上的权值和最大,注意每个格点的权值只能被计入答案一次。
- \(N,M\in [0,50]\)
状态显然跟步数以及两条路径的当前终点\((x_1,y_1)(x_2,y_2)\)有关,注意到两个终点的横纵坐标之和是固定的,因为起点为\((1,1)\),所以有\(x_1+y_1=x_2+y_2=2+\)当前步数。
精简状态,设\(f[i][j][k]\)表示当前两节点横纵坐标之和(即\(2+\)当前步数)为\(i\),第一条路径终点为\((j,i-j)\),第二条路径终点为\((k,i-k)\)的最大路径权值和。有显然的初始化\(f[2][1][1]=val[1][1]\)。
考虑对于已知状态\(f[i][j][k]\)的转移,根据下一步两条路径的行动方向讨论,有\(2\times 2=4\)种情况:
- 两个都向下:若当前两终点重合,则下一步也重合,权值只计算一次,否则分开累加答案:
if(j==k) f[i+1][j+1][k+1]=max(f[i+1][j+1][k+1],f[i][j][k]+val[j+1][i-j]);
else f[i+1][j+1][k+1]=max(f[i+1][j+1][k+1],f[i][j][k]+val[j+1][i-j]+val[k+1][i-k]);
- 两个都向右:讨论同上:
if(j==k) f[i+1][j][k]=max(f[i+1][j][k],f[i][j][k]+val[j][i+1-j]);
else f[i+1][j][k]=max(f[i+1][j][k],f[i][j][k]+val[j][i+1-j]+val[k][i+1-k]);
- 第一个向右,第二个向下:若\(j=k+1\),则代表下一步重合,权值只计算一次,否则分开累加:
if(k==j-1) f[i+1][j][k+1]=max(f[i+1][j][k+1],f[i][j][k]+val[j][i+1-j]);
else f[i+1][j][k+1]=max(f[i+1][j][k+1],f[i][j][k]+val[j][i+1-j]+val[k+1][i-k]);
- 第一个向下,第二个向右:讨论同上,条件改为\(k=j+1\):
if(j==k-1) f[i+1][j+1][k]=max(f[i+1][j+1][k],f[i][j][k]+val[k][i+1-k]);
else f[i+1][j+1][k]=max(f[i+1][j+1][k],f[i][j][k]+val[k][i+1-k]+val[j+1][i-j]);
答案即为\(f[N+M][N][N]\)。
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 120
#define R register
#define gc getchar
using namespace std;
int n,m,val[N][N],f[N<<1][N][N];
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
int main(){
n=rd(); m=rd();
for(R int i=1;i<=n;++i)
for(R int j=1;j<=m;++j) val[i][j]=rd();
f[2][1][1]=val[1][1];
for(R int i=2;i<=n+m-1;++i)
for(R int j=1;j<=n;++j)
for(R int k=1;k<=n;++k){
if(j==k){
f[i+1][j][k]=max(f[i+1][j][k],f[i][j][k]+val[j][i+1-j]);
f[i+1][j+1][k+1]=max(f[i+1][j+1][k+1],f[i][j][k]+val[j+1][i-j]);
}
else{
f[i+1][j][k]=max(f[i+1][j][k],f[i][j][k]+val[j][i+1-j]+val[k][i+1-k]);
f[i+1][j+1][k+1]=max(f[i+1][j+1][k+1],f[i][j][k]+val[j+1][i-j]+val[k+1][i-k]);
}
if(j==k-1) f[i+1][j+1][k]=max(f[i+1][j+1][k],f[i][j][k]+val[k][i+1-k]);
else f[i+1][j+1][k]=max(f[i+1][j+1][k],f[i][j][k]+val[k][i+1-k]+val[j+1][i-j]);
if(k==j-1) f[i+1][j][k+1]=max(f[i+1][j][k+1],f[i][j][k]+val[j][i+1-j]);
else f[i+1][j][k+1]=max(f[i+1][j][k+1],f[i][j][k]+val[j][i+1-j]+val[k+1][i-k]);
}
printf("%d\n",f[n+m][n][n]);
return 0;
}
\(\\\)
\(\#D\) \(Twostack\)
试通过\(2\)个栈\(S_1\)和\(S_2\),借助以下\(4\)种操作实现将输入的一个\(N\)的排列升序排序。
- 操作\(a\):如果输入序列不为空,将第一个元素压入栈\(S_1\)
- 操作\(b\):如果栈\(S_1\)不为空,将\(S_1\)栈顶元素弹出至输出序列
- 操作\(c\):如果输入序列不为空,将第一个元素压入栈\(S_2\)
- 操作\(d\):如果栈\(S_2\)不为空,将\(S_2\)栈顶元素弹出至输出序列
如果输入的排列不是“可双栈排序排列”,输出\(0\)。否则输出字典序最小的操作序列。
- \(N\in [0,1000]\)
- 当两个数不能连续进入同一个栈,首先需要满足前面的数小于后面的数,其次,前面的数不能在后面的数进栈之前弹出。当一个数可以弹栈,证明小于它的数字已经全部弹出,所以我们可以这样判断:
- 预处理出每一个数的后缀\(min\)。
- \(N^2\)枚举两个数\(a,b\)(\(a\)在\(b\)之前出现):若\(a<b\)且\(a>min_b\)则证明两者不能进入同一个栈。
- 如何判断是否有合法操作序列呢?注意到若合法这些点应该能通过互斥关系至多分成两类,所以不妨在不能进入同一个栈的两个点间连边,进行二分图染色,若该图是二分图则证明有合法操作关系。
- 因为要最小字典序答案,所以第一个数必定进\(S_1\)栈,注意到可能这张图不连通,所以将每次第一个遇到的点都染成黑色,代表进入\(S_1\)栈。
- 然后就可以模拟进出栈的过程了:每到一个点就按照染色入栈,然后检查是否有需要弹栈的数字,因为我们确定了输入序列为一个排列,所以直接通过栈顶权值判断。
- 但注意不能直接在插入之后把所有能弹出的数字都弹出,因为可能会存在先让数字进入第一个栈再弹出第二个栈的更优解法,所以操作变为:若插入\(S_2\),则能弹则弹;若插入\(S_1\),则先将一号栈该弹出的弹出(注意可能会附加二号栈的弹出),入栈,再将二号栈该弹出的弹出。
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 1010
#define R register
#define gc getchar
#define top1 stk1[0]
#define top2 stk2[0]
using namespace std;
int num[N],mn[N],to[N],stk1[N],stk2[N];
int n,m,tot,hd[N];
struct edge{int to,nxt;}e[N*N];
inline void add(int u,int v){
e[++tot].to=v; e[tot].nxt=hd[u]; hd[u]=tot;
}
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
inline bool dfs(int u,int tmp){
to[u]=tmp;
for(R int i=hd[u],v;i;i=e[i].nxt)
if(!to[v=e[i].to]){if(dfs(v,3-tmp))return 1;}
else if(to[v]==tmp) return 1;
return 0;
}
int main(){
n=rd();
for(R int i=1;i<=n;++i) num[i]=rd();
mn[n]=num[n];
for(R int i=n-1;i>=1;--i) mn[i]=min(mn[i+1],num[i]);
for(R int i=1;i<n;++i)
for(R int j=i+1;j<=n;++j)
if(num[i]<num[j]&&num[i]>mn[j]){add(i,j);add(j,i);}
for(R int i=1;i<=n;++i)
if(!to[i]) if(dfs(i,1)){putchar('0');return 0;};
m=1;
for(R int i=1;i<=n;++i){
if(to[i]==1){putchar('a'); putchar(' '); stk1[++top1]=num[i];}
else{putchar('c'); putchar(' '); stk2[++top2]=num[i];}
while(stk1[top1]==m||stk2[top2]==m){
if(stk1[top1]==m){putchar('b');putchar(' ');--top1;}
else{putchar('d');putchar(' ');--top2;} ++m;
}
}
return 0;
}
[ NOIP 2008 ] TG的更多相关文章
- NOIP 2008提高组第三题题解by rLq
啊啊啊啊啊啊今天已经星期三了吗 那么,来一波题解吧 本题地址http://www.luogu.org/problem/show?pid=1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们 ...
- Luogu 1006 传纸条 / NOIP 2008 传纸条(动态规划)
Luogu 1006 传纸条 / NOIP 2008 传纸条(动态规划) Description 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m ...
- noip 2008 传纸条
题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运的是 ...
- 历年真题 未完成(Noip 2008 - Noip 2017)
Noip 2008 :全部 Noip 2009 :全部 Noip 2010 :AK Noip 2011 :AK Noip 2012 : Vigenère 密码,国王游戏,开车旅行 Noip 2013 ...
- TYVJ 1011 NOIP 2008&&NOIP 2000 传纸条&&方格取数 Label:多线程dp
做题记录:2016-08-15 15:47:07 背景 NOIP2008复赛提高组第三题 描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行 ...
- [ NOIP 2014 ] TG
\(\\\) \(Day\ 1\) \(\\\) \(\#\ A\) \(Rps\) 定义五种方案的石头剪刀布游戏,两人共进行\(N\)局游戏,已知两人各自的循环节和具体方案,胜者得\(1\)分,败者 ...
- NOIP 2008 双栈排序
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
- NOIP 2008 传纸条 NOIP 2000 方块取数 多线程DP
思路都是一样,建立一个四维dp然后跑一发就完了 当然,也可以像我这么帅的人,降成三维再傻傻的跑一发啦啦啦~ #include<iostream> #include<stdio.h&g ...
- NOIP 2008 立体图 (字符串+模拟)
立体图 时间限制: 1 Sec 内存限制: 50 MB提交: 2 解决: 0[提交][状态][讨论版][命题人:外部导入] 题目描述 小渊是个聪明的孩子,他经常会给周围的小朋友们讲些自己认为有趣的 ...
随机推荐
- ajax加载本地html文件出现 XMLHttpRequest cannot load的问题
谷歌浏览器ajax加载本地html文件出现 XMLHttpRequest cannot load的问题(火狐中不会出现这问题) Cross origin requests are only suppo ...
- cmd界面中断一个程序快捷键 ctrl+c
cmd界面中断一个程序快捷键 ctrl+c
- Leetcode 122.买卖股票的最佳时机II
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你可以尽可能地完成更多的交易(多次买卖一支股票). 注意:你不能同时参与多笔交易(你必须在再次 ...
- poj 1364 查分约束
#include<stdio.h> #include<iostream> #include<stack> #include<string.h> usin ...
- Bellman_ford 算法 Currency Exchange POJ1860
Bellman_ford算法用于寻找正环或者负环! 算法导论: 24.1 The Bellman-Ford algorithm The Bellman-Ford algorithm solves th ...
- 洛谷—— P2047 社交网络
P2047 社交网络 题目描述 在社交网络(social network)的研究中,我们常常使用图论概念去解释一些社会现象.不妨看这样的一个问题.在一个社交圈子里有n个人,人与人之间有不同程度的关系. ...
- velt-0.1.7开发: KernelConfig的问题
快乐虾 http://blog.csdn.net/lights_joy/(QQ群:Visual EmbedLinux Tools 375515651) 欢迎转载.但请保留作者信息 VELT的全称是Vi ...
- linux下uart应用编程
目的:在用户空间通过读写uart设备文件,控制uart串口发送和接收数据. 在用户空间设置uart波特率.奇偶校验使能等操作是通过termios结构体和termios库函数完毕.须要在应用程序中包括t ...
- Linux C 网络编程——多线程的聊天室实现(server端)
server端的主要功能: 实现多用户群体聊天功能(此程序最多设定为10人.可进行更改),每一个人所发送的消息其它用户均能够收到.用户能够任意的增加或退出(推出以字符串"bye"实 ...
- 全然卸载oracle11g步骤
iLife's 博客http://blog.csdn.net/fei1502816 全然卸载oracle11g步骤: 1. 開始->设置->控制面板->管理工具->服务 停止全 ...