@Asuna
2016-10-28T23:24:27.000000Z
字数 8033
阅读 709
题意:字符串给一串母串,给n个子串,每个子串两个字母而且字母不重复,问要让每个子串正拟序都不在母串中出现需要在母串中删除几个字符。
题解:每读入一个子串就在母串中进行匹配,sum1和sum2分别代表子串中第一个和第二个字母出现的次数(可能有aaaabbbb这种串)然后每次取min加到ans上就可以了。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
string s,c;
int l,k,ans,sum1,sum2,sum;
int main()
{
cin>>s;
cin>>k;
l=s.size();
while(k>0)
{
cin>>c;
sum1=0;
sum2=0;
for(int i=0; i<l; i++)
{
if (s[i]==c[0]) sum1++;
else
if(s[i]==c[1]) sum2++;
else
{
cout<<sum1<<endl;
cout<<sum2<<endl;
sum=min(sum1,sum2);
ans+=sum;
sum1=0;
sum2=0;
}
sum=min(sum1,sum2);
}
ans+=sum;
k--;
}
cout<<ans<<endl;
return 0;
}
题意:有n个电子碰撞机,编号为1~n,初始状态所有的碰撞机都没有激活。然后需要你编写程序对下面的m次操作进行判断。’+’操作代表激活,’-’操作代表关闭激活,后面跟的数字就是操作的机器号。
1.当操作为’+’时:
1) 当i号机器已经激活时,则输出 Already on
2) 当i号机器没有激活时,则如果有一个已经激活的j号机器,并且i与j不互质的话即gcd(i,j)!=1时,那么提示 Conflict with j。
3) 否则机器正常激活,输出Success
2.当操作为’-’时:
1) 当i号机器已经激活时,则关闭激活成功,输出Success
2) 当i号机器没有激活时,则不需要关闭,则输出Already off
题解:考虑到时间复杂度,这道题必须控制在nlogn了吧。。。然后就是考虑到n<=10^5,我们可以用一个筛法筛出10^5以内的数的质因数作为预处理。然后开一个f数组保存n的质因数,w数组表示一个数x的质因数(起指向作用),之后对于每一个操作,假设是“+”,读入的是x,我们就处理出x的质因数有哪些,然后判断这些质因数是否已经出现,出现的话就输出Conflict With w数组指向的那个数,否则就把x加入进来并且把它的所有质因数都打上标记。假设是“-”,读入的是y,我们就把和y有关的质因数去掉(和y有关的w清零)。这样我们可以说严格控制了时间复杂度(真的严格么。。。。whatever反正本萌妹没t)。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int p[100005],w[100005],nfp[100005],f[100005][25],sum,x,k,j,n,m,y;
char c;
bool a[100005],bo[100005];
bool cprime(int x)
{
for (int i=2; i*i<=x; i++)
if (x%i==0) return false;
return true;
}
int main()
{
int i;
sum=0;
memset(bo,false,sizeof(bo));
for (int i=2; i<=100000; i++)
if (cprime(i))
{
sum++;
p[sum]=i;
bo[i]=true;
}
for (int i=2; i<=100000; i++)
{
k=i;
j=1;
while (p[j]*p[j]<=k)
{
// cout<<p[j]<<" !";
if (k%p[j]==0)
{
nfp[i]++;
f[i][nfp[i]]=p[j];
while (k%p[j]==0) k/=p[j];
}
j++;
}
if (bo[k])
{
// cout<<f[i][nfp[i]]<<endl;
nfp[i]++;
f[i][nfp[i]]=k;
}
}
cin>>n>>m;
//for (int i=1; i<=10000; i++)
// cout<<N[i]<<" ";
memset(a,false,sizeof(a));
while (m>0)
{
cin>>c;
cin>>x;
if (c=='+')
{
if (a[x]) cout<<"Already on"<<endl;
else
{
for (i=1; i<=nfp[x]; i++)
{
//cout<<w[f[x][i]]<<endl;
if (w[f[x][i]])
{
// cout<<i<<"!!!"<<endl;
break;
}
else
{
// cout<<i<<"!!!!"<<endl;
}
//cout<<y<<endl;
}
if (i<=nfp[x]) cout<<"Conflict with "<<w[f[x][i]]<<endl;
else
{
cout<<"Success"<<endl;
a[x]=true;
for (int i=1; i<=nfp[x]; i++) w[f[x][i]]=x;
}
//y=1;
}
}
else
{
if (!a[x]) cout<<"Already off"<<endl;
else
{
cout<<"Success"<<endl;
for (int i=1; i<=nfp[x]; i++) w[f[x][i]]=0;
}
a[x]=false;
}
m--;
}
return 0;
}
题意:判断下一个数是否位于之前的最大最小值之外.
题解:维护一个max和一个min,之后每读入就判断并改变范围。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int a[1005],n,maxx,minn,sum;
int main()
{
cin>>n;
cin>>a[1];
maxx=a[1];
minn=a[1];
for (int i=2; i<=n; i++)
{
cin>>a[i];
if (a[i]>maxx)
{
maxx=a[i];
sum++;
}
if (a[i]<minn)
{
minn=a[i];
sum++;
}
}
cout<<sum<<endl;
return 0;
}
题意:给你n张牌,每张牌有a[i]、b[i],分别表示可以获得的分数和可以获得的取牌次数,问在一开始只能取一次的情况下能获得的最大分数是多少。
题解:取牌越多分一定越大,先按b从大到小排,若b一样则a大的先排。
参考代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int a,b;
}f[10005];
int a[10005],n,ans,sum;
bool cmp(node x,node y)
{
if(x.b!=y.b) return x.b>y.b;
else return x.a>y.a;
}
int main()
{
cin>>n;
for (int i=1; i<=n; i++)
cin>>f[i].a>>f[i].b;
sort(f+1,f+n+1,cmp);
ans=f[1].a;
sum=f[1].b;
for (int i=2; i<=n; i++)
{
if (sum==0) break;
ans+=f[i].a;
sum+=f[i].b-1;
}
cout<<ans<<endl;
return 0;
}
题意:给两串字符,去第一个字符串的某一子串,经过若干次变换之后,变成子串二。允许的变换是:从任意一个末尾删去、或增加一个字符,置换一个字符。设计最优方案,求出最少的变换次数。
题解:似乎。。直接暴力解决就行了呢。。
参考代码:
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstdio>
using namespace std;
string s1,s2;
int l,l1,l2,l3,sum,ans=10000000,j,k;
int main()
{
cin>>s1>>s2;
l1=s1.size();
l2=s2.size();
l=l2;
if (l1<l2)
{
swap(s1,s2);
swap(l1,l2);
}
for (int i=1; i<l2; i++)
{
sum=0;
k=i;
j=0;
while((k<l2) && (j<l1))
{
if (s2[k]==s1[j]) sum++;
k++;
j++;
}
//cout<<sum<<" !!!"<<endl;
ans=min(ans,l-sum);
//cout<<ans<<" !!!"<<endl;
}
for (int i=0; i<l1; i++)
{
sum=0;
k=i;
j=0;
while((j<l2) && (k<l1))
{
if (s2[j]==s1[k]) sum++;
k++;
j++;
}
//cout<<sum<<" !!!!!"<<endl;
ans=min(ans,l-sum);
//cout<<ans<<" !!!!"<<endl;
}
cout<<ans<<endl;
return 0;
}
题意:给你n表示嫌疑人说的话,+i表示第i个人说i是犯人,-i表示第i个人说i不是犯人。m表示这n个人中有m个人说真话。现在让你判断每个人说的是真话还是假话,或者不确定。
题解:我们知道当一个人说的话和另外超过n-m个人说的话发生冲突的时候,这个人说的一定是假话(因为要有m个人说真话),而当一个人说的话的相反一定是假话的时候,这个人说的话就一定是真话,剩下的都是不确定的。问题就剩下如何判断一个人说的话有多少和他冲突。我们假设这个人指认了第i个人,那么说第i个人不是犯人的人和说别人是犯人的人就和他发生了冲突(因为只有一个犯人)。假设这个人为第i个人开脱了,那么说第i个人是犯人的人就和他冲突了。因此我们只需要多开几个数组求出每一个人和他冲突的话的个数就可以得出哪些话是必假的,从而推出哪些话是必真的。为了防止复杂度达到n^2,我们要用O1复杂度算出第i个人的冲突数,所以我们要预处理出共有多少人指认了别人,设为kk,那么说别人是犯人的个数就是kk-说第i个人是犯人的个数。至此就求出了冲突数。
参考代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int a[100005],b[100005],c[100005],d[100005],e[100005],n,m,sum,sum1,t;
int main()
{
cin>>n>>m;
for (int i=1; i<=n; i++)
{
cin>>a[i];
if (a[i]>0) b[a[i]]++;
else
{
c[abs(a[i])]++;
sum++;
}
}
for (int i=1; i<=n; i++)
{
sum1=b[i]+sum-c[i];
if (sum1==m)
{
e[t]=i;
d[i]=1;
t++;
}
}
// cout<<t<<endl;
if (t==1)
{
for (int i=1; i<=n; i++)
{
if (a[i]>0)
{
if (d[a[i]]) cout<<"Truth"<<endl;
else cout<<"Lie"<<endl;
}
else
{
if (d[abs(a[i])]) cout<<"Lie"<<endl;
else cout<<"Truth"<<endl;
}
}
}
else
{
for (int i=1; i<=n; i++)
{
if (a[i]>0)
{
if (d[a[i]]) cout<<"Not Defined"<<endl;
else cout<<"Lie"<<endl;
}
else
{
if (d[abs(a[i])]) cout<<"Not Defined"<<endl;
else cout<<"Truth"<<endl;
}
}
}
return 0;
}
题意:矩形列的和大于行的和就是成功的,判断有多少个数成功了。
题解:暴力枚举每个数。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
int a[35][35],n,ans,sum1,sum2,b[35][35],c[35][35];
int main()
{
cin>>n;
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++)
cin>>a[i][j];
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++)
{
for (int k=1; k<=n; k++) b[i][j]+=a[i][k];
//cout<<b[i][j]<<" !!!"<<endl;
for (int p=1; p<=n; p++) c[i][j]+=a[p][j];
//cout<<b[i][j]<<" !!!!"<<endl;
if (b[i][j]<c[i][j]) ans++;
}
cout<<ans<<endl;
return 0;
}
**题意:**n个同心圆有不同半径,两个相邻的圆之间颜色要不同,只有两种颜色红和蓝,问最后涂红色的面积。
题解:按半径排序,把能多涂一个的用红的涂,剩下的蓝。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[105],n,sum;
double ans;
bool bo=true;
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
cin>>n;
for (int i=1; i<=n; i++)
cin>>a[i];
sort(a+1,a+n+1,cmp);
for (int i=1; i<=n; i++)
{
if (bo==true)
{
sum+=a[i]*a[i];
bo=false;
}
else
{
sum-=a[i]*a[i];
bo=true;
}
}
ans=sum*3.141592653589793;
cout<<ans<<endl;
return 0;
}
题意:前k大的数有几个(不包含0)
题解:不知该说些什么。
参考代码:
#include<iostream>
using namespace std;
int a[105],n,k,ans;
int main()
{
cin>>n>>k;
for (int i=1; i<=n; i++)
cin>>a[i];
for (int i=1; i<=n; i++)
if (a[i]>=a[k] && a[i]!=0)
ans++;
cout<<ans<<endl;
return 0;
}
题意:有n组人,每组都是1到4人,准备做出租车去参加Party。一个出租车只能坐4个人,每个组的人不能拆分,求需要出租车的数量。
题解:记录每种一组人数的个数,4个人一组的就直接一辆了。分类讨论在于1人一组和3人一组的个数谁大,如果3人一组的个数多,就拿一人的都填上,然后就需要3人一组的车数,两人一组的就2组一辆车。如果一个人一组的组数多,就先把3人一组的填满,然后再拿1人一组的去补二人一组的。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
int n,ans,a[100005],b[11];
int main()
{
cin>>n;
memset(b,0,sizeof(b));
for (int i=1; i<=n; i++)
{
cin>>a[i];
b[a[i]]++;
}
ans=b[4]+b[3]+b[2]/2;
if (b[1]>b[3]) b[1]-=b[3];
else b[1]=0;
b[2]=b[2]%2;
if (b[2]==1)
{
ans++;
if (b[1]>2) b[1]-=2;
else b[1]=0;
}
ans+=b[1]/4;
if (b[1]%4!=0) ans++;
cout<<ans<<endl;
return 0;
}
题意:模拟目录?题目中总共有三种情况:以"/"开头是指新建一个根目录,以前清空就行了,".."是返回上一层的文件夹,"单词开头"就是在停在的文件夹处建立这个单词所描述的文件夹。
题解:按照题目要求来进行字符串操作就好了。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
string s,ans,p,s1;
int n,k,t;
int main()
{
ans="/";
cin>>n;
for (int i=1; i<=n; i++)
{
cin>>s;
if (s=="cd")
{
cin>>s1;
s1+='/';
//cout<<s1<<endl;
for (int j=0; j<s1.length(); j++)
{
p+=s1[j];
if(s1[j]=='/')
{
if(p=="/") ans=p;
else if (p=="../")
{
t=1;
k=ans.size()-1;
while (k>0)
{
if (ans[k-1]=='/') break;
k--;
t++;
}
// cout<<t<<endl;
ans.erase(ans.size()-t,t);
}
else ans+=p;
p="";
}
}
}
if (s=="pwd")
{
cout<<ans<<endl;
}
}
return 0;
}
题意:有n个冰雕等距地站成一个圈,每个冰雕都有自己的价值,现在你可以融化掉其中的一些,但必须使得剩余的冰雕围城的是正多边形,求价值总和的最大值。
题解:我们只要计算需要剩下多少个冰雕即可,但是要注意的是因为要组成多边形,所以最小一定是三角形,所以只能去掉n/3个冰雕最多。然后就是暴力枚举每一种情况求最大值了。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
int a[20005],ans,n,sum;
int main()
{
cin>>n;
for (int i=1; i<=n; i++)
{
cin>>a[i];
ans+=a[i];
}
for (int i=2; i<=n/3; i++)
{
if (n%i==0)
{
for (int j=1; j<=i; j++)
{
sum=0;
for (int k=j; k<=n; k+=i)
sum+=a[k];
if (sum>ans) ans=sum;
}
}
}
cout<<ans<<endl;
return 0;
}