码迷,mamicode.com
首页 > 其他好文 > 详细

COJ2152至2177(除2173)

时间:2015-10-03 10:40:10      阅读:601      评论:0      收藏:0      [点我收藏+]

标签:

 

高级打字机
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

早苗入手了最新的高级打字机。最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧。

请为这种高级打字机设计一个程序,支持如下3种操作:

1.T x:在文章末尾打下一个小写字母x。(type操作)

2.U x:撤销最后的x次修改操作。(Undo操作)

(注意Query操作并不算修改操作)

3.Q x:询问当前文章中第x个字母并输出。(Query操作)

文章一开始可以视为空串。

输入
第1行:一个整数n,表示操作数量。
以下n行,每行一个命令。保证输入的命令合法。
输出
每行输出一个字母,表示Query操作的答案。
输入示例
7
T a
T b
T c
Q 2
U 2
T c
Q 2
输出示例
b
c
其他说明
对于20%的数据 n<=200;
对于50%的数据 n<=100000;保证Undo操作不会撤销Undo操作。
<高级挑战>
对于100%的数据 n<=100000;Undo操作可以撤销Undo操作。
<IOI挑战>
必须使用在线算法完成该题。

用可持久化线段树来维护数组就可以了

技术分享
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==-) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x*f;
}
const int maxn=1000010;
const int maxnode=2000010;
char S[maxnode];
int ToT,root[maxn],len[maxn],ls[maxnode],rs[maxnode];
void update(int& y,int x,int l,int r,int pos,char c) {
    y=++ToT;
    if(l==r) S[y]=c;
    else {
        int mid=l+r>>1;ls[y]=ls[x];rs[y]=rs[x];
        if(pos<=mid) update(ls[y],ls[x],l,mid,pos,c);
        else update(rs[y],rs[x],mid+1,r,pos,c);
    }
}
void query(int y,int l,int r,int pos) {
    if(l==r) printf("%c\n",S[y]);
    else {
        int mid=l+r>>1;
        if(pos<=mid) query(ls[y],l,mid,pos);
        else query(rs[y],mid+1,r,pos);
    }
}
int main() {
    int n=read(),vs=0;
    while(n--) {
        char cmd[2],s[2];
        scanf("%s",cmd);
        if(cmd[0]==T) {
            scanf("%s",s);vs++;len[vs]=len[vs-1]+1;
            update(root[vs],root[vs-1],1,100000,len[vs],s[0]);
        }
        else if(cmd[0]==U) {
            int x=read();vs++;
            root[vs]=root[vs-x-1];
            len[vs]=len[vs-x-1];
        }
        else query(root[vs],1,100000,read());
    }
    return 0;
}
View Code

 

 

不等数列
难度级别:C; 运行时间限制:1000ms; 运行空间限制:256000KB; 代码长度限制:2000000B
试题描述

将1到n任意排列,然后在排列的每两个数之间根据他们的大小关系插入“>”和“<”。问在所有排列中,有多少个排列恰好有k个“<”。答案对2012取模。

输入
第一行2个整数n,k。
输出
一个整数表示答案。
输入示例
5 2
输出示例
66
其他说明
对于30%的数据:n <= 10
对于100%的数据:k < n <= 1000, 

 设f[n][k]表示1到n的排列,有k个<号的方案。

考虑将n+1插入n+1个位置中,如果插入到<之间不会增加<的数量,如果插入到>之间增加1个<。

技术分享
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==-) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x*f;
}
const int mod=2012;
const int maxn=1010;
long long f[maxn][maxn];
int main() {
    int n=read(),k=read();
    f[1][0]=1;
    rep(i,1,n-1) rep(j,0,i-1) {
        f[i][j]%=mod;
        f[i+1][j]+=(j+1)*f[i][j];
        f[i+1][j+1]+=(i-j)*f[i][j];
    }
    printf("%lld\n",f[n][k]%mod);
    return 0;
}
View Code

 

经营与开发
难度级别:C; 运行时间限制:1000ms; 运行空间限制:256000KB; 代码长度限制:2000000B
试题描述

4X概念体系,是指在PC战略游戏中一种相当普及和成熟的系统概念,得名自4个同样以“EX”为开头的英语单词。

eXplore(探索)

eXpand(拓张与发展)

eXploit(经营与开发)

eXterminate(征服)

——维基百科

 

今次我们着重考虑exploit部分,并将其模型简化:

你驾驶着一台带有钻头(初始能力值w)的飞船,按既定路线依次飞过n个星球。

 

星球笼统的分为2类:资源型和维修型。(p为钻头当前能力值)

1.资源型:含矿物质量a[i],若选择开采,则得到a[i]*p的金钱,之后钻头损耗k%,即p=p*(1-0.01k)

2.维修型:维护费用b[i],若选择维修,则支付b[i]*p的金钱,之后钻头修复c%,即p=p*(1+0.01c)

    注:维修后钻头的能力值可以超过初始值(你可以认为是翻修+升级)

 

请作为舰长的你仔细抉择以最大化收入。

输入
第一行4个整数n,k,c,w。
以下n行,每行2个整数type,x。
type为1则代表其为资源型星球,x为其矿物质含量a[i];
type为2则代表其为维修型星球,x为其维护费用b[i];
输出
一个实数(保留2位小数),表示最大的收入。
输入示例
5 50 50 10
1 10
1 20
2 10
2 20
1 30
输出示例
375.00
其他说明
对于30%的数据 n<=100
另有20%的数据 n<=1000;k=100
对于100%的数据 n<=100000; 0<=k,c,w,a[i],b[i]<=100;保证答案不超过10^9

设f[i]表示后i个星球最多获益值且必须采集第i个星球,DP维护一个最大值即可。

技术分享
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==-) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x*f;
}
const int maxn=100010;
int n,k,c,w,t[maxn],A[maxn];
double f[maxn],C,K,mx;
int main() {
    n=read();k=read();c=read();w=read();
    rep(i,1,n) t[i]=read(),A[i]=read();
    C=(100+c)/100.0;K=(100-k)/100.0;
    dwn(i,n,1) {
        if(t[i]==1) f[i]=mx*K+w*A[i];
        else f[i]=mx*C-w*A[i];
        mx=max(mx,f[i]);
    }
    printf("%.2lf\n",mx);
    return 0;
}
View Code

 

机器人
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

早苗入手了最新的Gundam模型。最新款自然有着与以往不同的功能,那就是它能够自动行走,厉害吧。

早苗的新模型可以按照输入的命令进行移动,命令包括‘E’、‘S’、‘W’、‘N’四种,分别对应东南西北。执行某个命令时,它会向对应方向移动一个单位。作为新型机器人,它可以执行命令串。对于输入的命令串,每一秒它会按命令行动一次。执行完命令串的最后一个命令后,会自动从头开始循环。在0时刻时机器人位于(0,0)。求T秒后机器人所在位置坐标。

输入
第1行:一个字符串,表示早苗输入的命令串,保证至少有1个命令
第2行:一个正整数T
输出
2个整数,表示T秒时,机器人的坐标。
输入示例
NSWWNSNEEWN
12
输出示例
-1 3
其他说明
【数据范围】
对于60%的数据 T<=500,000 且命令串长度<=5,000
对于100%的数据 T<=2,000,000,000 且命令串长度<=5,000

【注意】
向东移动,坐标改变改变为(X+1,Y); 
向南移动,坐标改变改变为(X,Y-1); 
向西移动,坐标改变改变为(X-1,Y); 
向北移动,坐标改变改变为(X,Y+1); 

这个就不说了233

技术分享
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==-) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x*f;
}
const int maxn=5010;
char s[maxn];
int main() {
    scanf("%s",s);int n=strlen(s);
    int T=read();
    int x0=0,y0=0;
    rep(i,0,n-1) {
        if(s[i]==W) x0--;
        if(s[i]==E) x0++;
        if(s[i]==N) y0++;
        if(s[i]==S) y0--;
    }
    int x=x0*(T/n),y=y0*(T/n);
    rep(i,0,(T%n)-1) {
        if(s[i]==W) x--;
        if(s[i]==E) x++;
        if(s[i]==N) y++;
        if(s[i]==S) y--;
    }
    printf("%d %d\n",x,y);
    return 0;
}
View Code

 

数列
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

a[1]=a[2]=a[3]=1

a[x]=a[x-3]+a[x-1]  (x>3)

求a数列的第n项对1000000007(10^9+7)取余的值。

 

输入
第一行一个整数T,表示询问个数。
以下T行,每行一个正整数n。
输出
每行输出一个非负整数表示答案。
输入示例
3
6
8
10
输出示例
4
9
19
其他说明
对于30%的数据 n<=100;
对于60%的数据 n<=2*10^7;
对于100%的数据 T<=100,n<=2*10^9;

直接矩阵快速幂即可

技术分享
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==-) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x*f;
}
const int MOD=1000000007;
typedef long long ll;
struct Matrix {
    ll A[3][3];
    Matrix() {memset(A,0,sizeof(A));}
    Matrix operator * (const Matrix& b) const {
        Matrix c;
        rep(i,0,2) rep(j,0,2) {
            c.A[i][j]=0;
            rep(k,0,2) c.A[i][j]+=A[i][k]*b.A[k][j];
            c.A[i][j]%=MOD;
        }
        return c;
    }
    void print() {
        rep(i,0,2) {
            rep(j,0,2) printf("%lld ",A[i][j]);
            puts("");
        }
    }
};
void pow(Matrix& ans,int n) {
    Matrix t=ans;n--;
    while(n) {
        if(n&1) ans=ans*t;
        t=t*t;n>>=1;
    }
}
ll solve(int n) {
    if(n<=3) return 1;
    Matrix t;
    t.A[0][0]=1;t.A[0][2]=1;
    t.A[1][0]=1;t.A[2][1]=1;
    pow(t,n-3);
    return (t.A[0][0]+t.A[1][0]+t.A[2][0])%MOD;
}
int main() {
    int T=read();
    while(T--) printf("%lld\n",solve(read()));
    return 0;
}
View Code

 

虫洞
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

N个虫洞,M条单向跃迁路径。从一个虫洞沿跃迁路径到另一个虫洞需要消耗一定量的燃料和1单位时间。虫洞有白洞和黑洞之分。设一条跃迁路径两端的虫洞质量差为delta。

1.从白洞跃迁到黑洞,消耗的燃料值减少delta,若该条路径消耗的燃料值变为负数的话,取为0。

2.从黑洞跃迁到白洞,消耗的燃料值增加delta。

3.路径两端均为黑洞或白洞,消耗的燃料值不变化。

作为压轴题,自然不会是如此简单的最短路问题,所以每过1单位时间黑洞变为白洞,白洞变为黑洞。在飞行过程中,可以选择在一个虫洞停留1个单位时间,如果当前为白洞,则不消耗燃料,否则消耗s[i]的燃料。现在请你求出从虫洞1到N最少的燃料消耗,保证一定存在1到N的路线。

输入
第1行:2个正整数N,M
第2行:N个整数,第i个为0表示虫洞i开始时为白洞,1表示黑洞。
第3行:N个整数,第i个数表示虫洞i的质量w[i]。
第4行:N个整数,第i个数表示在虫洞i停留消耗的燃料s[i]。
第5..M+4行:每行3个整数,u,v,k,表示在没有影响的情况下,从虫洞u到虫洞v需要消耗燃料k。
输出
一个整数,表示最少的燃料消耗。
输入示例
4 5
1 0 1 0
10 10 100 10
5 20 15 10
1 2 30
2 3 40
1 3 20
1 4 200
3 4 200
输出示例
130
其他说明
【数据范围】
对于30%的数据: 1<=N<=100,1<=M<=500
对于60%的数据: 1<=N<=1000,1<=M<=5000
对于100%的数据: 1<=N<=5000,1<=M<=30000
其中20%的数据为1<=N<=3000的链
1<=u,v<=N, 1<=k,w[i],s[i]<=200
【样例说明】
按照1->3->4的路线。

将一个点拆成两个点,分别是奇数秒和偶数秒第i个点,然后各种连边最短路即可。

技术分享
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==-) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x*f;
}
const int maxn=10010;
const int maxm=1000010;
const int INF=1000000000;
struct Dijkstra {
    int n,m,first[maxn],next[maxm];
    struct Edge {int to,dist;}edges[maxm];
    int done[maxn],d[maxn];
    struct HeapNode {
        int u,d;
        bool operator < (const HeapNode& ths) const {return d>ths.d;}
    };
    void init(int n) {
        this->n=n;m=0;
        memset(first,0,sizeof(first));
    }
    void AddEdge(int u,int v,int w) {
        //printf("%d --> %d   %d\n",u,v,w);
        edges[++m]=(Edge){v,w};next[m]=first[u];first[u]=m;
    }
    void solve(int s) {
        rep(i,1,n) d[i]=INF,done[i]=0;
        priority_queue<HeapNode> Q;
        Q.push((HeapNode){s,0});d[s]=0;
        while(!Q.empty()) {
            int x=Q.top().u;Q.pop();
            if(done[x]) continue;done[x]=1;
            ren {
                Edge& e=edges[i];
                if(d[e.to]>d[x]+e.dist) {
                    d[e.to]=d[x]+e.dist;
                    Q.push((HeapNode){e.to,d[e.to]});
                }
            }
        }
    }
}sol;
//1---n 0    n+1----2*n 1
int n,m,type[maxn],w[maxn],s[maxn],u[maxn*3],v[maxn*3],k[maxn*3];
int first[maxn],next[maxn*3];
void Add(int x,int v) {
    next[v]=first[x];first[x]=v;
}
int main() {
    n=read();m=read();
    rep(i,1,n) type[i]=read();
    rep(i,1,n) w[i]=read();
    rep(i,1,n) s[i]=read();
    rep(i,1,m) u[i]=read(),v[i]=read(),k[i]=read(),Add(u[i],i);
    sol.init(n*2);
    rep(x,1,n*2) {
        if(x<=n) sol.AddEdge(x,x+n,type[x]*s[x]);
        else sol.AddEdge(x,x-n,(type[x-n]^1)*s[x-n]);
        if(x<=n) ren {
            if(type[x]==type[v[i]]) sol.AddEdge(x,v[i]+n,k[i]);
            else if(type[x]) sol.AddEdge(x,v[i]+n,k[i]+abs(w[x]-w[v[i]]));
            else sol.AddEdge(x,v[i]+n,max(0,k[i]-abs(w[x]-w[v[i]])));
        }
        else for(int i=first[x-n];i;i=next[i]) {
                if(type[x-n]==type[v[i]]) sol.AddEdge(x,v[i],k[i]);
                else if(type[x-n]) sol.AddEdge(x,v[i],max(0,k[i]-abs(w[x-n]-w[v[i]])));
                else sol.AddEdge(x,v[i],k[i]+abs(w[x-n]-w[v[i]]));
        }
    }
    sol.solve(1);
    printf("%d\n",min(sol.d[n],sol.d[n*2]));
    return 0;
}
View Code

 

 

双色球
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

机房来了新一届的学弟学妹,邪恶的chenzeyu97发现一位学弟与他同名,于是他当起了善良的学长233

“来来来,学弟,我考你道水题检验一下你的水平……”

一个栈内初始有n个红色和蓝色的小球,请你按照以下规则进行操作

1.      只要栈顶的小球是红色的,将其取出,直到栈顶的球是蓝色

2.      然后将栈顶的蓝球变成红色

3.      最后放入若干个蓝球直到栈中的球数为n

以上3步骤为一次操作

如栈中都是红色球,则操作停止,请问几次操作后停止

chenzeyu97出完题发现他自己不能AC所以想请你帮忙

输入
第一行为一个整数n,表示栈的容量为n
第二行为一个字符串,第i个字符表示自顶向下的第i个球的颜色,R代表红色,B代表蓝色
输出
一个整数表示操作数
输入示例
10
BRRRRRRRRR
输出示例
1
其他说明
50%的数据,1<=n<=20
100%的数据,1<=n<=50

发现将RRRRRR--B变成RRRRRR--R需要2^n次操作。

             n个R

技术分享
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==-) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x*f;
}
char s[55];
int main() {
    int n=read();
    long long ans=0;
    scanf("%s",s);
    rep(i,0,n-1) ans|=(1ll<<i)*(s[i]==B);
    printf("%lld\n",ans);
    return 0;
}
View Code

 

魔方
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

ccy(ndsf)觉得手动复原魔方太慢了,所以他要借助计算机。

ccy(ndsf)家的魔方都是3*3*3的三阶魔方,大家应该都见过。

技术分享

(3的“顺时针”改为“逆时针”,即3 4以图为准。)
ccy(ndfs)从网上搜了一篇攻略,并找人翻译成了他自己会做的方法。现在告诉你他的魔方情况,以及他从网上搜到的攻略,请你求出最后魔方变成什么样子。

输入数据观察角度说明图:

技术分享

 

输入
 第一行,一串数字,表示从网上搜到的攻略。
   下面6*3行,每行3个数字,每三行表示魔方一个面的情况,六个面的顺序是前、后、左、右、上、下。
输出
 6*3行,表示处理后的魔方,形式同输入。
输入示例
23
121
221
111
123
321
111
123
321
132
132
231
132
121
112
233
332
111
333
输出示例
123
222
113
212
121
211
323
321
132
121
333
121
131
213
112
331
111
331
其他说明
40%的数据,攻略的长度小于5且仅有4种操作的其中一种
100%的数据,攻略的长度小于100

恩,问LZJ吧。

技术分享
#include<iostream>
#include<cstdio>
#define front 0
#define back 1
#define left 2
#define right 3
#define up 4
#define down 5
using namespace std;
char order[110];
struct Cube
{
    int block[6][3][3];
    void Rotate(int n)
    {
        Cube b=*this;
        if(n==1)
        {
            b.block[up][2][2]=block[front][2][2];
            b.block[up][2][1]=block[front][2][1];
            b.block[up][2][0]=block[front][2][0];
            b.block[front][2][2]=block[down][2][2];
            b.block[front][2][1]=block[down][2][1];
            b.block[front][2][0]=block[down][2][0];
            b.block[back][0][0]=block[up][2][2];
            b.block[back][0][1]=block[up][2][1];
            b.block[back][0][2]=block[up][2][0];
            b.block[down][2][0]=block[back][0][2];
            b.block[down][2][1]=block[back][0][1];
            b.block[down][2][2]=block[back][0][0];
            b.block[right][2][0]=block[right][0][0];
            b.block[right][0][0]=block[right][0][2];
            b.block[right][0][2]=block[right][2][2];
            b.block[right][2][2]=block[right][2][0];
            b.block[right][1][0]=block[right][0][1];
            b.block[right][2][1]=block[right][1][0];
            b.block[right][1][2]=block[right][2][1];
            b.block[right][0][1]=block[right][1][2];
        }
        else if(n==2)
        {
            b.Rotate(1);
            b.Rotate(1);
            b.Rotate(1);
        }
        else if(n==3)
        {
            b.block[left][2][0]=block[back][2][0];
            b.block[left][1][0]=block[back][1][0];
            b.block[left][0][0]=block[back][0][0];
            b.block[back][2][0]=block[right][2][0];
            b.block[back][1][0]=block[right][1][0];
            b.block[back][0][0]=block[right][0][0];
            b.block[right][2][0]=block[front][2][0];
            b.block[right][1][0]=block[front][1][0];
            b.block[right][0][0]=block[front][0][0];
            b.block[front][2][0]=block[left][2][0];
            b.block[front][1][0]=block[left][1][0];
            b.block[front][0][0]=block[left][0][0];
            b.block[up][0][0]=block[up][2][0];
            b.block[up][0][2]=block[up][0][0];
            b.block[up][2][2]=block[up][0][2];
            b.block[up][2][0]=block[up][2][2];
            b.block[up][0][1]=block[up][1][0];
            b.block[up][1][0]=block[up][2][1];
            b.block[up][2][1]=block[up][1][2];
            b.block[up][1][2]=block[up][0][1];
        }
        else if(n==4)
        {
            b.Rotate(3);
            b.Rotate(3);
            b.Rotate(3);
        }
        *this=b;
    }
}C;
int main()
{
    int c;
    scanf("%s",order);
    for(int i=0;i<6;i++)
        for(int x=0;x<3;x++)
            for(int y=0;y<3;y++)
            {
                c=getchar();
                while(!isdigit(c))c=getchar();
                C.block[i][y][x]=c-0;
            }
    for(int i=0,len=strlen(order);i<len;i++)
    {
        C.Rotate(order[i]-0);
    }
    for(int i=0;i<6;i++)
        for(int x=0;x<3;x++)
        {
            for(int y=0;y<3;y++)
                printf("%d",C.block[i][y][x]);
            putchar(\n);
        }
}
View Code

 

czy的后宫
难度级别:C; 运行时间限制:3000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

czy要妥善安排他的后宫,他想在机房摆一群妹子,一共有n个位置排成一排,每个位置可以摆妹子也可以不摆妹子。有些类型妹子如果摆在相邻的位置(隔着一个空的位置不算相邻),就不好看了。假定每种妹子数量无限,求摆妹子的方案数。

输入
输入有m+1行,第一行有两个用空格隔开的正整数n、m,m表示妹子的种类数。接下来的m行,每行有m个字符1或0,若第i行第j列为1,则表示第i种妹子第j种妹子不能排在相邻的位置,输入保证对称。(提示:同一种妹子可能不能排在相邻位置)。
输出
输出只有一个整数,为方案数(这个数字可能很大,请输出方案数除以1000000007的余数。
输入示例
2 2
01
10
输出示例
7
其他说明
【样例说明】
七种方案为(空,空)、(空,1)、(1、空)、(2、空)、(空、2)、(1,1)、(2,2)。
【数据范围】
20%的数据,1<n≤5,0<m≤10。
60%的数据,1<n≤200,0<m≤100。
100%的数据,1<n≤1000000000,0<m≤100。
注:此题时限1.5s是因为本评测机跑太慢,大家正常做
但写的太丑可能T一俩个点

将空格视为一种新的MZ,设f[i][k]表示已放了i个MZ,最后一个MZ种类为k的方案数,然后用矩阵快速幂优化。

技术分享
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==-) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x*f;
}
const int maxn=110;
const int MOD=1000000007;
typedef long long ll;
int n,m;
struct Matrix {
    ll A[maxn][maxn];
    Matrix() {memset(A,0,sizeof(A));}
    Matrix operator * (const Matrix& b) const {
        Matrix c;
        rep(i,1,m) rep(j,1,m) {
            c.A[i][j]=0;
            rep(k,1,m) (c.A[i][j]+=A[i][k]*b.A[k][j])%=MOD;
        }
        return c;
    }
    void print() {
        rep(i,1,m) {
            rep(j,1,m) printf("%lld ",A[i][j]);
            puts("");
        }
    }
};
void pow(Matrix& ans,int n) {
    Matrix t=ans;n--;
    while(n) {
        if(n&1) ans=ans*t;
        t=t*t;n>>=1;
    }
}
char s[maxn];
int main() {
    Matrix ans;
    n=read();m=read();
    rep(i,1,m) {
        scanf("%s",s+1);
        rep(j,1,m) ans.A[i][j]=(s[j]==0);
    }
    m++;rep(i,1,m) ans.A[i][m]=ans.A[m][i]=1;
    pow(ans,n);
    ll res=0;
    rep(i,1,m) (res+=ans.A[m][i])%=MOD;
    printf("%lld\n",res);
    return 0;
}
View Code

 

护花
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

约翰留下他的N(N<=100000)只奶牛上山采木.他离开的时候,她们像往常一样悠闲地在草场里吃草.可是,当他回来的时候,他看到了一幕惨剧:牛们正躲在他的花园里,啃食着他心爱的美丽花朵!为了使接下来花朵的损失最小,约翰赶紧采取行动,把牛们送回牛棚. 牛们从1到N编号.第i只牛所在的位置距离牛棚Ti(1≤Ti≤2000000)分钟的路程,而在约翰开始送她回牛棚之前,她每分钟会啃食Di(1≤Di≤100)朵鲜花.无论多么努力,约翰一次只能送一只牛回棚.而运送第第i只牛事实上需要2Ti分钟,因为来回都需要时间.    写一个程序来决定约翰运送奶牛的顺序,使最终被吞食的花朵数量最小.

输入
第1行输入N,之后N行每行输入两个整数Ti和Di
输出
一个整数,表示最小数量的花朵被吞食
输入示例
6
3 1
2 5
2 3
3 2
4 1
1 6
输出示例
86
其他说明
【样例解释】
 约翰用6,2,3,4,1,5的顺序来运送他的奶牛 

与国王游戏类似,用相邻交换法自己证吧。

技术分享
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==-) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x*f;
}
typedef long long ll;
const int maxn=100010;
struct Cow {
    int t,d;
    bool operator < (const Cow& ths) const {return d*ths.t>ths.d*t;}
}A[maxn];
int n;
ll ans,all;
int main() {
    n=read();
    rep(i,1,n) A[i].t=read(),A[i].d=read(),all+=A[i].d;
    sort(A+1,A+n+1);
    rep(i,1,n) {
        all-=A[i].d;
        ans+=all*A[i].t;
    }
    printf("%lld\n",ans*2);
    return 0;
}
View Code

 

修剪草坪
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

在一年前赢得了小镇的最佳草坪比赛后,FJ变得很懒,再也没有修剪过草坪。现在,
新一轮的最佳草坪比赛又开始了,FJ希望能够再次夺冠。
然而,FJ的草坪非常脏乱,因此,FJ只能够让他的奶牛来完成这项工作。FJ有N
(1 <= N <= 100,000)只排成一排的奶牛,编号为1...N。每只奶牛的效率是不同的,
奶牛i的效率为E_i(0 <= E_i <= 1,000,000,000)。
靠近的奶牛们很熟悉,因此,如果FJ安排超过K(1<=K<=N)只连续的奶牛,那么,这些奶牛就会罢工
去开派对:)。因此,现在FJ需要你的帮助,计算FJ可以得到的最大效率,并且该方案中
没有连续的超过K只奶牛。

输入
* 第一行:空格隔开的两个整数N和K
* 第二到N+1行:第i+1行有一个整数E_i
输出
* 第一行:一个值,表示FJ可以得到的最大的效率值。
输入示例
5 2
1
2
3
4
5
输出示例
12
其他说明
输入解释:
FJ有5只奶牛,他们的效率为1,2,3,4,5。他们希望选取效率总和最大的奶牛,但是
他不能选取超过2只连续的奶牛
FJ可以选择出了第三只以外的其他奶牛,总的效率为1+2+4+5=12。

设f[i]表示前i头奶牛最少浪费的效率和,转移时用个单调队列即可。

技术分享
#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==-) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x*f;
}
const int maxn=100010;
int n,k,A[maxn];
int q[maxn],l,r;
long long f[maxn],ans,mn=1ll<<50;
int main() {
    n=read();k=read();
    rep(1,n) A[i]=read(),ans+=A[i];
    int l=1,r=0;
    rep(1,n) {
        while(l<=r&&f[q[r]]>=f[i-1]) r--;q[++r]=i-1;
        while(l<=r&&q[l]<i-k-1) l++;
        f[i]=f[q[l]]+A[i];
    }
    rep(n-k,n) mn=min(mn,f[i]);
    printf("%lld\n",ans-mn);
    return 0;
}
View Code

 

虫洞
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

John在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前)。John的每个农场有M条小路(无向边)连接着N (从1..N标号)块地,并有W个虫洞(有向边)。其中1<=N<=500,1<=M<=2500,1<=W<=200。 现在John想借助这些虫洞来回到过去(出发时刻之前),请你告诉他能办到吗。 John将向你提供F(1<=F<=5)个农场的地图。没有小路会耗费你超过10000秒的时间,当然也没有虫洞回帮你回到超过10000秒以前。

输入
* Line 1: 一个整数 F, 表示农场个数。
* Line 1 of each farm: 三个整数 N, M, W。
* Lines 2..M+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地中间有一条用时T秒的小路。
* Lines M+2..M+W+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地中间有一条可以使John到达T秒前的虫洞。
输出
* Lines 1..F: 如果John能在这个农场实现他的目标,输出"YES",否则输出"NO"。
输入示例
2
3 3 1
1 2 2
1 3 4
2 3 1
3 1 3
3 2 1
1 2 3
2 3 4
3 1 8
输出示例
NO
YES

判负环用DFS版的SPFA比较优美。

技术分享
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==-) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-0;
    return x*f;
}
const int maxn=510;
const int maxm=7010;
struct SPFA {
    int n,m,ok,first[maxn],next[maxm];
    void init(int n) {
        this->n=n;m=0;ok=0;
        fill(first+1,first+n+1,0);
    }
    struct Edge {int to,dist;}edges[maxm];
    void AddEdge(int u,int v,int w) {
        edges[++m]=(Edge){v,w};next[m]=first[u];first[u]=m;
    }
    int vis[maxn],d[maxn];
    int spfa(int x) {
        vis[x]=1;
        ren {
            Edge& e=edges[i];
            if(d[e.to]>d[x]+e.dist) {
                if(vis[e.to]) return 1;
                else {
                    d[e.to]=d[x]+e.dist;
                    if(spfa(e.to)) return 1;
                }
            }
        }
        vis[x]=0;
        return 0;
    }
    int solve() {
        rep(i,1,n) d[i]=vis[i]=0;
        rep(i,1,n) if(spfa(i)) return 1;
        return 0;
    }
}sol;
int main() {
    int T=read();
    while(T--) {
        int n=read(),m=read(),w=read(),a,b,c;
        sol.init(n);
        rep(i,1,m) {
            a=read();b=read();c=read();
            sol.AddEdge(a,b,c);sol.AddEdge(b,a,c);
        }
        rep(i,1,w) {
            a=read();b=read();c=read();
            sol.AddEdge(a,b,-c);
        }
        puts(sol.solve()?"YES":"NO");
    }
    return 0;
}
View Code

水灾
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

已经连续下了几天雨,却还是没有停的样子。土豪CCY刚从外地赚完1e元回来,知道不久除了自己别墅,其他的地方都将会被洪水淹没。

CCY所在的城市可以用一个N*M(N,M<=50)的地图表示,地图上有五种符号:“. * X D S”。其中“X”表示石头,水和人都不能从上面经过。“.”表示平原,CCY和洪水都可以经过。“*”表示洪水开始地方(可能有多个地方开始发生洪水)。“D”表示CCY的别墅。“S”表示CCY现在的位置。

CCY每分钟可以向相邻位置移动,而洪水将会在CCY移动之后把相邻的没有的土地淹没(从已淹没的土地)。

求CCY回到别墅的最少时间。如果聪哥回不了家,就很可能会被淹死,那么他就要膜拜黄金大神涨RP来呼叫直升飞机,所以输出“ORZ hzwer!!!”。

输入
第一行:N和M
接下来N行,每行M个字符,表示地图。
输出
若能回家,输出一个整数,表示最少回家步数;否则输出“ORZ hzwer!!!”。
输入示例
3 3
D.*
...
.S.
输出示例
3

COJ2152至2177(除2173)

标签:

原文地址:http://www.cnblogs.com/wzj-is-a-juruo/p/4853102.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!