此文章可以使用目录功能哟↑(点击上方[+])
咕~~(╯﹏╰)b,这次bestcoder hack别人挺爽的,但也被别人hack得挺爽,冤冤相报何时了/(ㄒoㄒ)/~~...
Problem 1001 Fxx and string
Accept: 0 Submit: 0
Time Limit: 2000/1000 MS (Java/Others) Memory Limit : 131072/65536 K (Java/Others)
Problem Description
Input
Output
For each case, output the answer.
输出共T行。
每行一个整数表示答案。
Sample Input
xyyrxx
yyrrxxxxx
Sample Output
2
Problem Idea
解题思路:
【题意】
给定一个数列,问存在多少个三元组(i,j,k)满足下列条件
1.i,j,k三个数成等比
2.si='y',sj='r',sk='x'
3.i/j和k/j中必须有整数
【类型】
暴力枚举公比
【分析】
由第3个条件可知,i,j,k的正向公比或反向公比两者中必定存在整数
也就是说,我们可以暴力枚举公比,然后判断条件2
考虑一下暴力枚举公比的复杂度,由于字符串长度不超过10000,即使是下标为1的位置,公比也不会超过100,因为i*q*q<=10000,i>=1,故q<=100
所以复杂度<=O(1000000),可行
而反向公比可以把枚举i位置当做是枚举k位置
【时间复杂度&&优化】
O(1000000)
Source Code
/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<list>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 10005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
char s[N];
int main()
{
int t,i,j,n;
__int64 ans;
scanf("%d",&t);
while(t--)
{
ans=0;
scanf("%s",s+1);
n=strlen(s+1);
for(i=1;i<=n;i++)
for(j=2;i*j*j<=n;j++)
{
if(s[i]=='y'&&s[i*j]=='r'&&s[i*j*j]=='x')
ans++;
if(s[i]=='x'&&s[i*j]=='r'&&s[i*j*j]=='y')
ans++;
}
printf("%I64d\n",ans);
}
return 0;
}
Problem 1002 Fxx and game
Accept: 0 Submit: 0
Time Limit: 3000/1500 MS (Java/Others) Memory Limit : 131072/65536 K (Java/Others)
Problem Description
Young theoretical computer scientist Fxx designed a game for his students.
In each game, you will get three integers X,k,t.In each step, you can only do one of the following moves:
1.X=X−i(0<=i<=t).
2.if k|X,X=X/k.
Now Fxx wants you to tell him the minimum steps to make X become 1.
青年理论计算机科学家Fxx给的学生设计了一款数字游戏。
一开始你将会得到一个数X,每次游戏将给定两个参数k,t, 任意时刻你可以对你的数执行下面两个步骤之一:
1.X=X−i(1<=i<=t)。
2.若X为k的倍数,X=X/k。
现在Fxx想要你告诉他最少的运行步骤,使X变成1。
Input
In the first line, there is an integer T(1≤T≤20) indicating the number of test cases.
As for the following T lines, each line contains three integers X,k,t(0≤t≤10^6,1≤X,k≤10^6)
For each text case,we assure that it's possible to make X become 1。
第一行一个整数T(1≤T≤20)表示数据组数。
接下来T行,每行三个数X,k,t(0≤t≤10^6,1≤X,k≤10^6)
数据保证有解。
Output
For each test case, output the answer.
输出共T行。
每行一个整数表示答案。
Sample Input
9 2 1
11 3 3
Sample Output
3
Problem Idea
解题思路:
【题意】
给你X,k,t,每一步你可以执行两种操作中的一种
1.X=X−i(1<=i<=t)
2.若X是k的倍数,X/k
问将X变成1至少需要多少步
【类型】
单调队列维护dp 或者 bfs剪枝
【分析】
一开始的时候,想想X的大小是10^6,于是想到bfs(从X开始,把当前状态能够一步到达且还没有到达的状态均压入队列中待下一步处理,直到X为1),虽然复杂度有点悬,还是尝试了一发
int bfs(int x,int k,int t)
{
if(k==1&&t)
return (x+t-2)/t;
int i,Min;
node u;
queue<node> q;
for(i=1;i<=x;i++)
v[i]=false;
q.push(node(x,0));
v[x]=true;
while(!q.empty())
{
u=q.front();
q.pop();
if(u.x==1)
return u.c;
if(u.x%k==0&&!v[u.x/k])
{
q.push(node(u.x/k,u.c+1));
v[u.x/k]=true;
}
Min=min(t,u.x-1);
for(i=Min;i>=1;i--)
if(!v[u.x-i])
{
q.push(node(u.x-i,u.c+1));
v[u.x-i]=true;
}
}
}
交了之后跑了390MS,而别人的才0MS
好吧,我承认我虚了,所以开始想新的方法
于是,博主会用两种方法来讲解此题:
①bfs剪枝
bfs爆搜已经被我放弃了,那么该如何剪枝呢
显然操作2是不需要剪枝的,因为它的下一状态就一个
于是着手点在操作1,X的下一状态可以是X-t~X-1中的任意一种,有点多,我们是不是可以省掉一些状态呢?
可以的,对于X-t~X-1这些状态中,我们从小往大遍历,当遇到某一状态已经访问过,那我们就不再取该状态及之后状态
为什么呢?理由很简单,我们在步数少的情况下已经到达该状态,那之后的状态还留着干嘛用呢?
没想到这一剪枝使得最后跑出来的时间比另一种方法还要快
详细代码见Source Code
②单调队列维护dp
这种做法就是出题人的做法
设Fi表示将i变为1的最少步骤,如果k∣i,Fi=min{Fj,Fki},否则Fi=min{Fj},其中i−t≤j≤i−1。
而求min{Fj}(i-t≤j≤i-1)需要用单调队列维护,之所以用单调队列是因为它均摊的复杂度为O(n)
这比用线段树等其他O(nlogn)的方法维护要快一些
单调队列的介绍,在此不作说明,想了解的可以去看一下POJ 2823
这种方法跑出来的大概时间
【时间复杂度&&优化】
O(n)
Source Code
//bfs剪枝
/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<list>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1000005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
struct node
{
int x,c;
node(){}
node(int _x,int _c):x(_x),c(_c){}
};
bool v[N];
int bfs(int x,int k,int t)
{
if(k==1&&t)
return (x+t-2)/t;
int i,Min;
node u;
queue<node> q;
for(i=1;i<=x;i++)
v[i]=false;
q.push(node(x,0));
v[x]=true;
while(!q.empty())
{
u=q.front();
q.pop();
if(u.x==1)
return u.c;
if(u.x%k==0&&!v[u.x/k])
{
q.push(node(u.x/k,u.c+1));
v[u.x/k]=true;
}
Min=min(t,u.x-1);
for(i=Min;i>=1;i--)
if(!v[u.x-i])
{
q.push(node(u.x-i,u.c+1));
v[u.x-i]=true;
}
else//剪枝
break;
}
}
int main()
{
int T,X,k,t;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&X,&k,&t);
printf("%d\n",bfs(X,k,t));
}
return 0;
}
//单调队列维护dp
/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<list>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1000005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
int ans[N],p[N];
int main()
{
int T,X,k,t,i,head,tail;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&X,&k,&t);
if(k==1&&t)
{
printf("%d\n",(X+t-2)/t);
continue;
}
ans[1]=0;p[1]=1;head=tail=1;
for(i=2;i<=X;i++)
{
if(i%k==0)
ans[i]=ans[i/k]+1;
else
ans[i]=inf;
while(head<=tail&&i-p[head]>t)
head++;
if(head<=tail)
ans[i]=min(ans[i],ans[p[head]]+1);
while(head<=tail&&ans[p[tail]]>=ans[i])
tail--;
p[++tail]=i;
}
printf("%d\n",ans[X]);
}
return 0;
}
菜鸟成长记