标签:
高级打字机 |
难度级别: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; }
不等数列 |
难度级别: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; }
经营与开发 |
难度级别: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; }
机器人 |
难度级别: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; }
数列 |
难度级别: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; }
虫洞 |
难度级别: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; }
双色球 |
难度级别: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; }
魔方 |
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B |
试题描述
|
ccy(ndsf)觉得手动复原魔方太慢了,所以他要借助计算机。 ccy(ndsf)家的魔方都是3*3*3的三阶魔方,大家应该都见过。 (3的“顺时针”改为“逆时针”,即3 4以图为准。) 输入数据观察角度说明图:
|
输入
|
第一行,一串数字,表示从网上搜到的攻略。
下面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‘); } }
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; }
护花 |
难度级别: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; }
修剪草坪 |
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B |
试题描述
|
在一年前赢得了小镇的最佳草坪比赛后,FJ变得很懒,再也没有修剪过草坪。现在, |
输入
|
* 第一行:空格隔开的两个整数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; }
虫洞 |
难度级别: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; }
水灾 |
难度级别: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
|
标签:
原文地址:http://www.cnblogs.com/wzj-is-a-juruo/p/4853102.html