#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"math.h"
#define N 111
int ans[N];
void init()
{
ans[5]=272400600;
ans[6]=9717617;
ans[7]=898515;
int k,q;
double t,temp;
for(k=8;k<=100;k++)
{
t=0;
temp=1;
q=0;
while(t<100)
{
t+=k/temp;
temp++;
q++;
}
ans[k]=q;
}
}
int main()
{
init();
int k;
while(scanf("%d",&k)!=-1)
printf("%d\n",ans[k]);
return 0;
}
Queuing
/*
题意:f代表男,m代表女,给定长度L,有2^L个不同组合的字符串(f、m相间),不能出现fmf和fff,问有几种组合。
思路:只要能找到递推公式就可以马上切掉这题。
设f(n)为字符串长度为n时复合条件的字符串个数,以字符串最后一个字符为分界点,当最后一个字符为m时前n-1个字符没有限制,即为f(n-1);当最后一个字符为f时就必须去除最后3个字符是fmf和fff的情况,在考虑最后两个字符为mf和ff的情况,显然不行;最后3个字符为fmf、mmf和fff、mff时只有当最后3个字符为mmf时前n-3个字符没有限制,即为f(n-3),当为mff时第n-3个字符可能为f因而对前n-3个字符串有限制;最后4个字符为fmff和mmff时mmff可行。这样就讨论完了字符串的构成情况,得出结论:
f(n)=f(n-1)+f(n-3)+f(n-4)
然后就像fibonacci那样构建矩阵用快速幂取模。。。
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
int f[5]={0,2,4,6,9};
typedef struct In{
int m[5][5];
}Matrix;
Matrix init,unit,F;
int n,m;
void Init(){
for(int i=1;i<=4;i++){
for(int j=1;j<=4;j++){
if(i==1&&j==1) init.m[i][j]=1;
else if(i==1&&j==3) init.m[i][j]=1;
else if(i==1&&j==4) init.m[i][j]=1;
else if(i==2&&j==1) init.m[i][j]=1;
else if(i==3&&j==2) init.m[i][j]=1;
else if(i==4&&j==3) init.m[i][j]=1;
else init.m[i][j]=0;
unit.m[i][j]=(i==j);
F.m[i][j]=0;
}
}
F.m[1][1]=f[4];
F.m[2][1]=f[3];
F.m[3][1]=f[2];
F.m[4][1]=f[1];
}
Matrix Mul(Matrix a,Matrix b){
Matrix c;
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++){
c.m[i][j]=0;
for(int k=1;k<=4;k++){
c.m[i][j]+=a.m[i][k]*b.m[k][j]%m;
c.m[i][j]%=m;
}
}
return c;
}
Matrix Pow(Matrix a,Matrix b){
while(n){
if(n&1) b=Mul(a,b);
a=Mul(a,a);
n>>=1;
}
return b;
}
int main(){
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
while(scanf("%d%d",&n,&m)!=EOF){
if(n<5){
printf("%d\n",f[n]%m);
continue;
}
Init();
n-=4;
Matrix x=Pow(init,unit);
x=Mul(x,F);
printf("%d\n",x.m[1][1]%m);
}
return 0;
}
胜利大逃亡(续)
#include<cstdio>
#include<queue>
#include<string.h>
using namespace std;
struct state{
state(int a,int b,int d,int e){r=a,c=b,v=d,st=e;}
int r,c,v,st;
};
char map[30][30];
int n,m,t,stx,sty,mint;
int vis[30][30][1100];
int dr[]={1,0,-1,0},dc[]={0,1,0,-1};
int bfs(){
memset(vis,0,sizeof vis);
queue<state> q;
q.push(state(stx,sty,0,0));
vis[stx][sty][0]=1;
while(!q.empty()){
state os=q.front();q.pop();
int r=os.r,c=os.c,v=os.v,st=os.st;//旧的状态参数
for(int i=0;i<4;i++){
int nr=r+dr[i],nc=c+dc[i],nv=v,nst=st+1;//新的状态参数
if(nst>=t||nr<0||nc<0||nr>=n||nc>=m||map[nr][nc]=='*')continue;//超出时间,范围,以及墙都是不可达位置
char tc=map[nr][nc];
if(tc=='^')return nst;//到达终点
if(tc>='A'&&tc<='J'){//如果到了这个点却没有对应钥匙
if((nv&(1<<(tc-'A')))==0)continue;
}else if(tc>='a'&&tc<='j'){//如果到的这个点有钥匙
nv^=(1<<(tc-'a'));
}
if(!vis[nr][nc][nv]){//如果这个点未被访问过
vis[nr][nc][nv]=1;
q.push(state(nr,nc,nv,nst));
}
}
}
return -1;
}
int main(){
while(scanf("%d%d%d",&n,&m,&t)!=EOF){
for(int i=0;i<n;i++){
scanf("%s",map[i]);
for(int j=0;j<m;j++){
if(map[i][j]=='@')stx=i,sty=j;
}
}
printf("%d\n",bfs());
}
return 0;
}
The Worm Turns
#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 630
char mat[MAX][MAX];
bool visit[MAX][MAX];
int dir[4][2]= {0,1,-1,0,1,0,0,-1};
int n,m,maxx;
int xi,yi,ki,xt,yt,kt;
void dfs(int a,int b,int d,int step)//深搜
{
if(step>maxx)//更新最大值
{
maxx=step;
xi=xt;
yi=yt;
ki=kt;
}
int tx=a+dir[d][0],ty=b+dir[d][1];
if(tx<0||tx>=n||ty<0||ty>=m||visit[tx][ty]==true||mat[tx][ty])
{
if(step==0) return;//第一步是不允许转向的
for(int i=0; i<4; ++i)
{
if(i==d) continue;
tx=a+dir[i][0];
ty=b+dir[i][1];
if(0<=tx&&tx<n&&0<=ty&&ty<m&&visit[tx][ty]==false&&!mat[tx][ty])
{
visit[tx][ty]=true;
dfs(tx,ty,i,step+1);
visit[tx][ty]=false;
}
}
}
else
{
visit[tx][ty]=true;
dfs(tx,ty,d,step+1);
visit[tx][ty]=false;
}
}
int main()
{
int t,a,b;
char c;
for(int cas=1; ~scanf("%d%d",&n,&m); ++cas)
{
if(n+m==0) break;
memset(mat,0,sizeof(mat));
maxx=0;
scanf("%d",&t);
for(; t--;)
{
scanf("%d%d",&a,&b);
mat[a][b]=1;
}
//枚举每个点
for(int i=0; i<n; ++i)
for(int j=0; j<m; ++j)
for(int k=0; k<4; ++k)
if(!mat[i][j])
{
xt=i;
yt=j;
kt=k;
visit[i][j]=true;
dfs(i,j,k,0);
visit[i][j]=false;
}
if(ki==0) c='E';
if(ki==1) c='N';
if(ki==2) c='S';
if(ki==3) c='W';
printf("Case %d: %d %d %d %c\n",cas,maxx+1,xi,yi,c);
}
return 0;
}
T9
/*
字典树,不难。建字典树时对每一点有一个频度值,
每次取这一层上频度最大的字母所在路径所组成的
*/
#include<cstdio>
#include<string.h>
using namespace std;
struct trie{
trie(){
for(int i=0;i<26;i++)next[i]=NULL;
pro=0;
}
trie *next[26];
int pro;
}*root;
int cas,words,k;
char find[105],res[105],bres[105],wd[105];
int bpro;
bool flag;
//对应按键上的字母
int alpha[8][5]={{0,1,2},{3,4,5},{6,7,8},{9,10,11},{12,13,14},{15,16,17,18},{19,20,21},{22,23,24,25}};
int alphas[8]={3,3,3,3,3,4,3,4};
void instrie(char *wd,int pro){
int len=strlen(wd);
trie *p=root;
for(int i=0;i<len;i++){
int t=wd[i]-'a';
if(p->next[t]==NULL){
p->next[t]=new trie;
}
p=p->next[t];
p->pro+=pro;//字典树上每一点的概率
}
}
void dfs(int now,int len,trie *tr){
if(now==len){//标记字典中右对应按键的结果并且选择最大概率的组合
flag=true;
if(tr->pro>bpro){
bpro=tr->pro;
for(int i=0;i<now;i++){
bres[i]=res[i];
}
bres[now]='\0';
}
return;
}
int t=find[now]-'2';
for(int i=0;i<alphas[t];i++){
int r=alpha[t][i];
if(tr->next[r]==NULL)continue;
res[now]=r+'a';
dfs(now+1,len,tr->next[r]);
}
}
int main(){
int pro;
scanf("%d",&cas);
for(int ca=1;ca<=cas;ca++){
printf("Scenario #%d:\n",ca);
scanf("%d",&words);
root=new trie;
for(int i=0;i<words;i++){
scanf("%s%d",wd,&pro);
instrie(wd,pro);
}
scanf("%d",&k);
while(k--){
scanf("%s",find);
int len=strlen(find);
for(int i=1;i<len;i++){
flag=false;
bpro=0;
dfs(0,i,root);
if(flag){
printf("%s\n",bres);
}else{
printf("MANUALLY\n");
}
}
printf("\n");
}
printf("\n");
}
return 0;
}
Cycling
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string.h>
#include<queue>
//枚举上下界求最短路
using namespace std;
const int inf=1000000000;
struct node{
int v,i;
node(int a,int b){v=a,i=b;}
bool operator <(const node& n)const{
return v>n.v;
}
};
struct ati{
int l,h;
bool operator<(const ati& a)const{
return h-l<(a.h-a.l);
}
}at[100004];
int cas,n,m,h[105],a,b,c;
int map[105][105];
int dij(int low,int high){
int done[105];
int d[105];
for(int i=1;i<=n;i++)d[i]=inf;
d[1]=0;
memset(done,0,sizeof done);
priority_queue<node> pq;
pq.push(node(d[1],1));
while(!pq.empty()){
node nd=pq.top();pq.pop();
int u=nd.i;
if(done[u]||h[u]<low||h[u]>high)continue;
done[u]=1;
for(int v=1;v<=n;v++){
if(h[v]<low||h[v]>high)continue;
if(map[u][v]&&d[v]>d[u]+map[u][v]){
d[v]=d[u]+map[u][v];
pq.push(node(d[v],v));
}
}
}
return d[n];
}
int myabs(int x){return x>0?x:-x;}
int main(){
int cas;
scanf("%d",&cas);
while(cas--){
memset(map,0,sizeof map);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&h[i]);
for(int i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
if(map[a][b]&&map[a][b]<c)continue;
map[a][b]=map[b][a]=c;
}
int k=0;
int lmin=min(h[1],h[n]),lmax=max(h[1],h[n]);
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
if(min(h[i],h[j])>lmin||max(h[i],h[j])<lmax)continue;
at[k].l=min(h[i],h[j]);
at[k++].h=max(h[i],h[j]);
}
}
sort(at,at+k);
for(int i=0;i<k;i++){
int d=dij(at[i].l,at[i].h);
if(d!=inf){
printf("%d %d\n",at[i].h-at[i].l,d);
break;
}
}
}
return 0;
}
Game
/*
能从A取一部分到B,当B<A,并且(A+B)%2=1,(A+B)%3=0,其中A,B是堆的编号
博弈,搞不来啊。将堆数分成两部分,一部分到终态要奇数步,一部分要偶数步。对奇数步的做NIM
*/
#include<cstdio>
using namespace std;
int cas,n,a;
//1,3,4是最终状态,%6为0,2,5为奇数步,对这些堆做NIM游戏
int main(){
scanf("%d",&cas);
for(int ca=1;ca<=cas;ca++){
int rs=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a);
if(i%6==0||i%6==2||i%6==5)rs^=a;
}
printf("Case %d: ",ca);
printf(rs?"Alice\n":"Bob\n");
}
return 0;
}
Equations
/*
简单的哈希,但是要注意在a,b,c,d都是正或者都是负的情况要直接排除,否则会TLE
*/
#include<cstdio>
#include<string.h>
using namespace std;
int hash[2000005];
int main(){
int a,b,c,d;
while(scanf("%d%d%d%d",&a,&b,&c,&d)!=EOF){
//注意排除
if((a>0&&b>0&&c>0&&d>0)||(a<0&&b<0&&c<0&&d<0)){
printf("0\n");
continue;
}
memset(hash,0,sizeof hash);
for(int i=-100;i<=100;i++){
for(int j=-100;j<=100;j++){
if(i&&j)hash[a*i*i+b*j*j+1000000]++;
}
}
int rs=0;
for(int i=-100;i<=100;i++){
for(int j=-100;j<=100;j++){
if(i&&j)rs+=hash[-c*i*i-d*j*j+1000000];
}
}
printf("%d\n",rs);
}
}