关于输入输出:
同学们在使用OJ时,请看清楚题目描述。OJ判题时,是将测试数据做为标准输入输入的,你的程序需要输出每一组输入的结果。大部分题目都要求输入到文件末尾,也就是说,你的读入也应当读取到文件末尾,并输出读取到的所有数据的结果。每一组数据都一定满足题目给出的规范,无需进行特判。也不要输出除了所需结果外的任何字符。
关于WA:
出现Wrong Answer时,请思考自己的程序复杂度及解法的正确性。一般来说,系统的测试数据不会出错(虽然这次就错了囧),当怀疑系统的正确性时,请在Clarification中提出疑问。
1000.
枚举插入的位置及插入的字母,之后统计新字符串的结果即可。
时间复杂度为
O(9n2)
。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
//
typedef long long ll;
char cz[110],tz[110];int n;
int _cl(int n){
int i,rs=0;for(i=0;i+2<n;++i)if(tz[i]=='A'&&tz[i+1]=='C'&&tz[i+2]=='M')++rs;
return rs;
};
bool cl(){
int i,j,k,t;if(scanf("%s",cz)==-1)return 0;n=strlen(cz);
for(i=0,j=0;i<n+1;++i){
for(k=0;k<i;++k)tz[k]=cz[k];
for(++k;k<n+1;++k)tz[k]=cz[k-1];
tz[i]='A';j=max(j,_cl(n+1));
tz[i]='C';j=max(j,_cl(n+1));
tz[i]='M';j=max(j,_cl(n+1));
}
printf("%d\n",j);
return 1;
};
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(cl());
return 0;
};
1001.
空间没限制,直接用map硬上即可,复杂度
O(nlogn)
。
PS.有
O(n)
的解法。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
#include<map>
//
typedef long long ll;
typedef pair<int,int>pi;
bool cl(){
int n,i,j,k,a;map<int,int>mp;
if(scanf("%d",&n)==-1)return 0;
n=n*2+1;
for(j=0;n;n--){
scanf("%d",&a);
map<int,int>::iterator it=mp.find(a);
if(it==mp.end())mp.insert(pi(a,1));
else
j=max(j,++it->second);
}
map<int,int>::iterator it=mp.begin();
for(;it!=mp.end();++it)if(it->second==j){
j=it->first;
break;
}
printf("%d\n",j);
return 1;
};
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(cl());
return 0;
};
1002.
一个模板题,对于每一个点对,求出他们的LCA(最近公共祖先),结果为
dis(s,lca)+dis(t,lca)
。
先固定根,dfs预处理出每个点的深度,则
dis(a,b)=|dep(a)−dep(b)|
,用倍增
O(nlogn+qlogn)
可以通过。
也可以用Tarjan离线把复杂度中的
log
去掉。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
#include<map>
//
typedef long long ll;
typedef pair<int,int>pi;
int fa[18][40010],dep[40010];
struct eg{int u,v,nx;}gp[80010];int cnt,hd[40010];
void psh(int u,int v){
++cnt;gp[cnt].u=u,gp[cnt].v=v,gp[cnt].nx=hd[u],hd[u]=cnt;
};
int tds(int v,int d){
int i;for(i=0;d;++i,d>>=1)if(d&1)v=fa[i][v];
return v;
};
int lca(int a,int b){
if(dep[a]<dep[b])b=tds(b,dep[b]-dep[a]);
else
a=tds(a,dep[a]-dep[b]);
if(a==b)return a;
int i;for(i=17;i>=0;--i)if(fa[i][a]!=fa[i][b])
a=fa[i][a],b=fa[i][b];
return fa[0][a];
};
void dfs(int v,int f,int d){
dep[v]=d;int i;for(i=hd[v];i;i=gp[i].nx)if(gp[i].v!=f)
dfs(gp[i].v,v,d+1),fa[0][gp[i].v]=v;
};
void init(int n){
int i,j;for(i=1;i<=17;++i)for(j=1;j<=n;++j)
fa[i][j]=fa[i-1][fa[i-1][j]];
};
bool cl(){
int i,j,k,n,q,a,b;if(scanf("%d",&n)==-1)return 0;
for(cnt=0,clr(hd),clr(fa),i=1;i<n;++i){
scanf("%d %d",&a,&b);psh(a,b),psh(b,a);
}
dfs(1,0,0);scanf("%d",&q);init(n);
for(;q;q--){
scanf("%d %d",&a,&b);
int t=lca(a,b);
printf("%d\n",dep[b]-dep[t]+dep[a]-dep[t]);
}
return 1;
};
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(cl());
return 0;
};
1003.
枚举因数,预处理出每个数的因子数,再将满足要求的数置为1,其余置为0,求前缀和,即可在
O(1)
下计算每个查询(任意一个区间都可以表示为两个前缀相减)。
预处理因子的时间复杂度为:
O(∑ni=1ni)=O(nlogn)
。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
#include<map>
//
typedef long long ll;
typedef pair<int,int>pi;
const int up=500000;
int ar[up+1];
void init(){
int i,j;clr(ar);for(i=1;i<=up;++i){
for(j=i;j<=up;j+=i)ar[j]++;
}
for(i=1;i<=up;++i)ar[i]=ar[i]==4?1:0;
for(i=1;i<=up;++i)ar[i]+=ar[i-1];
};
void cl(){
int a,b;scanf("%d %d",&a,&b);printf("%d\n",ar[b]-ar[a-1]);
};
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
init();int t;scanf("%d",&t);while(t--)cl();
return 0;
};
1004.
直接求乘积很显然会爆double,容易想到将每个数取对数,则有
ln(AB)=ln(A)+ln(B)
。
枚举区间求和比较即可。
时间复杂度为
O(n)
。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
#include<map>
//
typedef long long ll;
double ar[1010];int n;
bool cl(){
int i,j,k;if(scanf("%d %d",&n,&k)==-1)return 0;
for(i=1;i<=n;++i){
scanf("%d",&j);
ar[i]=log((double)j);
}
double rs=0;
for(i=1;i<=k;++i){
rs+=ar[i];
}
double mx=rs;int ts=1;
for(i=2;i+k-1<=n;++i){
rs=0;for(j=i;j<=i+k-1;++j)rs+=ar[j];
if(rs>mx)
mx=rs,ts=i;
}
printf("%d\n",ts);
return 1;
};
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(cl());
return 0;
};
1005.
恶俗暴力题,枚举所有的符号及括号组合即可。
括号组合如下:
ABCD,(AB)(CD),A(B(CD)),A(BC)D,A((BC)D)
注意到每个数可以调换顺序,故我们预处理出所有
104
种排列,并计算是否满足要求。同时记录满足要求的序列的递增序列,即我们将序列排序得到他们的最小表示,之后将这个序列转换给11进制数存储。
对每个查询,计算序列的最小表示,在表中查询即可。
总共可能的方案数为
104∗34∗5
。
注意在比较中需要处理精度问题。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
#include<set>
#include<map>
//
typedef long long ll;
#define x(a,b,c) (_cl(ar[a],ar[b],c))
int ar[4],dr[3];bool bd[15000];
double _cl(double a,double b,int x){
return !x?a+b:x==1?a-b:x==2?a*b:a/b;
};
bool _ck(double x){return fabs(x-24.0)<=1e-6;};
bool ck(){
int i,j,k;for(i=0;i<4;++i)for(j=0;j<4;++j)for(k=0;k<4;++k){
dr[0]=i,dr[1]=j,dr[2]=k;
if(_ck(_cl(_cl(x(0,1,dr[0]),ar[2],dr[1]),ar[3],dr[2])))return 1;
if(_ck(_cl(x(0,1,dr[0]),x(2,3,dr[2]),dr[1])))return 1;
if(_ck(_cl(ar[0],_cl(ar[1],x(2,3,dr[2]),dr[1]),dr[0])))return 1;
if(_ck(_cl(_cl(ar[0],x(1,2,dr[1]),dr[0]),ar[3],dr[2])))return 1;
if(_ck(_cl(ar[0],_cl(x(1,2,dr[1]),ar[3],dr[2]),dr[0])))return 1;
}
return 0;
};
void init(){
int i,j,k,d;for(clr(bd),i=1;i<=10;++i)for(j=1;j<=10;++j)for(k=1;k<=10;++k)for(d=1;d<=10;++d){
ar[0]=i,ar[1]=j,ar[2]=k,ar[3]=d;
if(ck()){
sort(ar,ar+4);bd[ar[0]+ar[1]*11+ar[2]*121+ar[3]*1331]=1;
}
}
};
void cl(){
int i;for(i=0;i<4;scanf("%d",&ar[i++]));sort(ar,ar+4);
printf("%s\n",bd[ar[0]+ar[1]*11+ar[2]*121+ar[3]*1331]?"YES":"NO");
};
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t;scanf("%d",&t),init();while(t--)cl();
return 0;
};
1006.
可以发现,第一次必然要将一个饼放到小盘上,之后可以从其他饼中不断的填补之前产生的空缺。这样每个饼都要往外拿
n−1
次,最后我们将小盘上的饼放到空缺中即可。
答案为
n(n−1)+1
。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
#include<map>
//
typedef long long ll;
bool cl(){
int n;if(scanf("%d",&n)==-1)return 0;
if(n==1){printf("0\n");return 1;}
printf("%d\n",n*(n-1)+1);
return 1;
};
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(cl());
return 0;
};
1007.
计算几何,不存在的。百度“点到线段最短距离”即可。
1008.
考虑用dp解决,设
f(n,k)
表示有
n
块地待挖,剩余
每次枚举挖第
i
块,则:
爆炸时,有
否则,有
f(n−i,k)+1
。
那么,有转移方程:
f(n,k)=MINni=1{MAX{f(n−i,k),f(i−1,k−1)}+1}
时间复杂度为
O(n2k)
。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
#include<map>
//
typedef long long ll;
int dp[101][21];
void init(){
int i,j,k;for(clr(dp),i=1;i<=100;++i)dp[i][1]=i;
for(i=1;i<=20;++i)dp[1][i]=1;
for(i=2;i<=100;++i)for(j=2;j<=20;++j){
dp[i][j]=21;
dp[i][j]=dp[i-1][j]+1;
dp[i][j]=min(dp[i][j],dp[i-1][j-1]+1);
for(k=2;k<i;++k){
dp[i][j]=min(dp[i][j],max(dp[i-k][j],dp[k-1][j-1])+1);
}
}
};
bool cl(){
int n,k;if(scanf("%d %d",&n,&k)==-1)return 0;
printf("%d\n",dp[n][k]);
return 1;
};
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
init();while(cl());
return 0;
};
1009.
直接模拟即可。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
#include<map>
//
typedef long long ll;
char mt[10][10]={
"11111100",
"01100000",
"11011010",
"11110010",
"01100110",
"10110110",
"10111110",
"11100000",
"11111110",
"11110110"
},cz[10];
ll _cl(int d){
ll r=0,t=1;int i;for(i=0;i<8;++i,t<<=1)if(mt[d][i]=='1')
r+=t;
return r;
};
bool cl(){
int i,j;if(scanf("%s",cz)==-1)return 0;
ll rs=_cl(cz[4]-'0');
rs+=(_cl(cz[3]-'0')<<8);
rs+=(_cl(cz[1]-'0')<<16);
rs+=(_cl(cz[0]-'0')<<24);
printf("%lld\n",rs);
return 1;
};
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(cl());
return 0;
};
1010.
考虑使用Polya定理解决。
容易发现翻转操作等价于连续两次平行边的扭转,所以不用考虑。
注意到仅仅使用扭转操作,产生的置换个数是
O(4!)
,非常的少。
在本机暴力包含扭转与旋转的所有循环节后,使用Polya定理即可。
答案为
20n4+21n8+6n12+n1648
。
暴力的代码也在下面。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
#include<set>
#include<map>
//
typedef long long ll;
#define w(a,b) swap(a,b)
#define e(a,b) x[a]=t[b]
set<string>st;
void r0(int*t){w(t[6],t[10]),w(t[12],t[2]),w(t[14],t[5]),w(t[16],t[9]);};
void r1(int*t){w(t[3],t[7]),w(t[1],t[11]),w(t[13],t[4]),w(t[15],t[8]);};
void r2(int*t){w(t[3],t[6]),w(t[1],t[2]),w(t[16],t[4]),w(t[15],t[5]);};
void r3(int*t){w(t[7],t[10]),w(t[11],t[12]),w(t[14],t[8]),w(t[13],t[9]);};
void rot(int*t){
int x[17];
e(3,2),e(7,1);e(1,6),e(2,10);
e(11,3),e(12,7);e(6,12),e(10,11);
e(8,4),e(9,8),e(5,9),e(4,5);
e(15,16),e(16,14),e(14,13),e(13,15);
memcpy(t,x,17*sizeof(int));
};
int dr[17],sm[17];
void cd(string&a,int x){
for(;x;x/=10)a.push_back(char(x%10+'0'));
};
string xd(int*r){
int i;string a;for(i=1;i<=16;cd(a,dr[i++]));
return a;
};
int _cl(int*t){
int i,j,r=0;bool bd[17];for(clr(bd),i=1;i<=16;++i)if(!bd[i]){
for(j=i,++r;!bd[j];j=t[j])bd[j]=1;
}
return r;
};
void dfs(){
int i,j,k,t[17];memcpy(t,dr,17*sizeof(int));
string s=xd(dr);if(st.find(s)!=st.end())return;st.insert(s);
sm[_cl(dr)]++;
r0(dr);dfs();memcpy(dr,t,17*sizeof(int));
r1(dr);dfs();memcpy(dr,t,17*sizeof(int));
r2(dr);dfs();memcpy(dr,t,17*sizeof(int));
r3(dr);dfs();memcpy(dr,t,17*sizeof(int));
rot(dr);dfs();memcpy(dr,t,17*sizeof(int));
};
ll qni(ll a,ll b){
ll r=1;for(;b;b>>=1,a*=a)if(b&1)r*=a;
return r;
};
bool cl(){
int n;if(scanf("%d",&n)==-1)return 0;
ll rs=qni(n,4)*20+qni(n,8)*21+qni(n,12)*6+qni(n,16);
printf("%lld\n",rs/48);
return 1;
};
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(cl());
return 0;
};