\(\\\)

\(\#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的更多相关文章

  1. NOIP 2008提高组第三题题解by rLq

    啊啊啊啊啊啊今天已经星期三了吗 那么,来一波题解吧 本题地址http://www.luogu.org/problem/show?pid=1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们 ...

  2. Luogu 1006 传纸条 / NOIP 2008 传纸条(动态规划)

    Luogu 1006 传纸条 / NOIP 2008 传纸条(动态规划) Description 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m ...

  3. noip 2008 传纸条

    题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运的是 ...

  4. 历年真题 未完成(Noip 2008 - Noip 2017)

    Noip 2008 :全部 Noip 2009 :全部 Noip 2010 :AK Noip 2011 :AK Noip 2012 : Vigenère 密码,国王游戏,开车旅行 Noip 2013 ...

  5. TYVJ 1011 NOIP 2008&&NOIP 2000 传纸条&&方格取数 Label:多线程dp

    做题记录:2016-08-15 15:47:07 背景 NOIP2008复赛提高组第三题 描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行 ...

  6. [ NOIP 2014 ] TG

    \(\\\) \(Day\ 1\) \(\\\) \(\#\ A\) \(Rps\) 定义五种方案的石头剪刀布游戏,两人共进行\(N\)局游戏,已知两人各自的循环节和具体方案,胜者得\(1\)分,败者 ...

  7. NOIP 2008 双栈排序

    题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...

  8. NOIP 2008 传纸条 NOIP 2000 方块取数 多线程DP

    思路都是一样,建立一个四维dp然后跑一发就完了 当然,也可以像我这么帅的人,降成三维再傻傻的跑一发啦啦啦~ #include<iostream> #include<stdio.h&g ...

  9. NOIP 2008 立体图 (字符串+模拟)

    立体图 时间限制: 1 Sec  内存限制: 50 MB提交: 2  解决: 0[提交][状态][讨论版][命题人:外部导入] 题目描述 小渊是个聪明的孩子,他经常会给周围的小朋友们讲些自己认为有趣的 ...

随机推荐

  1. vue项目使用static目录存放图片解决方案

    我个人喜欢把所有引用文件全部放在打包文件src的同级文件static文件内部,方便整合. 提醒:vue项目中正常情况下图片是由 url-loader 处理,加入了hash值,如果放到static里面w ...

  2. Uva10305 Ordering Tasks

    John有n个任务,但是有些任务需要在做完另外一些任务后才能做. 输入 输入有多组数据,每组数据第一行有两个整数1 <= n <= 100 和 m.n是任务个数(标记为1到n),m两个任务 ...

  3. python爬取数据保存到Excel中

    # -*- conding:utf-8 -*- # 1.两页的内容 # 2.抓取每页title和URL # 3.根据title创建文件,发送URL请求,提取数据 import requests fro ...

  4. [K/3Cloud]调用动态表单时,传递自定义参数

    插件中在调用动态表单时,通过DynamicFormShowParameter的CustomParams,增加自定义的参数. private void ShowMaterialStock() { obj ...

  5. (12)GrabCut前景提取

    import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread('opencv-python-foregr ...

  6. FreeMarker与Spring MVC 4集合的HelloWorld示例

    0.整体的项目结构 1.引入POM <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="ht ...

  7. 复习es6-解构赋值+字符串的扩展

    1. 数组的解构赋值 从数组中获得变量的值,给对应的声明变量赋值,,有次序和对应位置赋值 解构赋值的时候右边必须可以遍历 解构赋值可以使用默认值 惰性求值,当赋值时候为undefined时候,默认是个 ...

  8. 条款50: 提高对C++的认识

    class Base { public: virtual void f(int x); }; class Derived: public Base { public: virtual void f(d ...

  9. python supervisor进程监控工具的使用

    supervisor —— a process control system 另外一个类似 supervisor的工具,因为supervisor 不兼容python3, !!! Circus Proc ...

  10. VB的程序如何破解

    VB的程序,不会告诉你这个VB写的,但是从界面来看就很像VB,一般是单文件的EXE,然后软件还比较小(早期的傻瓜式软件写的东西)   比如说我们想要知道这个"手动采集"按钮干了什么 ...