1001-调查问卷
思路:暴力所有问题集即1-->(1<<m)-1,先预处理将AB转换为二进制10,例如AA为二进制11,保存为3。遍历问题集s,将所有试卷集也s的与运算结果t用map<int,int> imap保存下来,imap[t]++;这样所有的试卷结果都分开了,再计算不同试卷的对数即可。
Code :
#include<iostream>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
const int MAX_N=1055;
int n,m,p,T;
string a[MAX_N];
int d[MAX_N];
int main()
{
ios::sync_with_stdio(false);
cin>>T;
for(int k=1;k<=T;++k){
cin>>n>>m>>p;
for(int i=0;i<n;++i)
cin>>a[i];
for(int i=0;i<n;++i)
{
int x=0;
for(int j=0;j<a[i].size();++j)
if(a[i][j]=='A') x=x*2+1;
else x=x*2;
d[i]=x;
}
int ans=0;
int sum=pow(2,m);
for(int i=1;i<sum;++i)
{
map<int,int> imap;
for(int j=0;j<n;++j)
{
int t=i&d[j];
imap[t]++;
}
int ss=0,si=0;
for(auto c:imap) //计算不同试卷的对数
if(c.second)
{
si+=c.second;
ss+=c.second*(n-si);
}
if(ss>=p) ans++;
}
cout<<"Case #"<<k<<": "<<ans<<endl;
}
return 0;
}
1002-子串查询
思路:对于s[l,r]中的最小字典序子串即为按照a-z的顺序s[l,r]中存在的那个,因此可以预处理出a-z所有出现的下标分开保存,在遍历a-z,二分查找即可。
另一思路是可以用数组分别将a-z的前缀和保存下来,直接查询即可
code 二分:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int n,Q,T;
string str;
int main()
{
ios::sync_with_stdio(false);
cin>>T;
for(int t=1;t<=T;++t)
{
vector<int> ive[30];
cin>>n>>Q>>str;
for(int i=0;i<n;++i)
ive[str[i]-'A'].push_back(i+1);
cout<<"Case #"<<t<<":"<<endl;
int l,r;
while(Q--){
cin>>l>>r;
int ans=0;
for(int i=0;i<26;++i)
if(ive[i].size()){
int t1=lower_bound(ive[i].begin(),ive[i].end(),l)-ive[i].begin();
int t2=lower_bound(ive[i].begin(),ive[i].end(),r+1)-ive[i].begin();
if(t1!=ive[i].size()&&ive[i][t1]<=r){
ans=t2-t1; break;
}
}
cout<<ans<<endl;
}
}
return 0;
}
code 数组:
#include<iostream>
using namespace std;
const int MAX_N=100005;
int n,Q,T;
string str;
int d[30][MAX_N];
int main()
{
ios::sync_with_stdio(false);
cin>>T;
for(int t=1;t<=T;++t)
{
cin>>n>>Q>>str;
for(int i=0;i<n;++i)
for(int j=0;j<26;++j)
if((str[i]-'A')==j) d[j][i+1]=d[j][i]+1;
else d[j][i+1]=d[j][i];
cout<<"Case #"<<t<<":"<<endl;
int l,r;
while(Q--){
cin>>l>>r;
int ans=0;
for(int i=0;i<26&&!ans;++i)
ans=d[i][r]-d[i][l-1];
cout<<ans<<endl;
}
}
return 0;
}
1006-三原色图
思路:大致思路就是分红绿,蓝绿两次分别查找最小生成树s1,s2,在将剩下的边由小到大排序v1,v2,每次取s1+v1[i],s2+v2[i]的最小值输出即可
Code :
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct node{
int u;
int v;
int w;
char c;
bool operator<(const node &p)const{
return w<p.w;
}
};
const int MAX_N=105;
int n,m,T;
int id[MAX_N];
vector<node> e;
vector<int> v1,v2;
int Find(int x);
int Kruskal(char c);
int main()
{
ios::sync_with_stdio(false);
cin>>T;
for(int t=1;t<=T;++t)
{
e.clear(); v1.clear(); v2.clear();
cin>>n>>m;
int u,v,w;
char c;
for(int i=0;i<m;++i)
{
cin>>u>>v>>w>>c;
e.push_back(node{u,v,w,c});
}
sort(e.begin(),e.end());
int s1=Kruskal('R');
int s2=Kruskal('B');
vector<int> vv1,vv2;
vv1.push_back(0); vv2.push_back(0);
for(int i=0,k=0;i<m&&s1!=-1;++i)
if(k<n-1&&e[i].w==v1[k]) ++k;
else vv1.push_back(e[i].w);
for(int i=0,k=0;i<m&&s2!=-1;++i)
if(k<n-1&&e[i].w==v2[k]) ++k;
else vv2.push_back(e[i].w);
int boo=3;
if(s1==-1&&s2==-1) boo=0;
else if(s2==-1) boo=1;
else if(s1==-1) boo=2;
cout<<"Case #"<<t<<":"<<endl;
int sum1=0,sum2=0;
for(int i=1;i<=m;++i)
if(i<n-1) cout<<-1<<endl;
else{
int ans=-1;
if(boo==3){
sum1+=vv1[i-n+1]; sum2+=vv2[i-n+1];
ans=min(s1+sum1,s2+sum2);
}else if(boo==2){
sum2+=vv2[i-n+1]; ans=s2+sum2;
}else if(boo==1){
sum1+=vv1[i-n+1]; ans=s1+sum1;
}
cout<<ans<<endl;
}
}
return 0;
}
int Find(int x)
{
if(id[x]!=x) id[x]=Find(id[x]);
return id[x];
}
int Kruskal(char c)
{
for(int i=0;i<=n;++i)
id[i]=i;
int k=1,i=0,ans=0;
while(k<n&&i<m){
node t=e[i++];
if(t.c!=c&&Find(t.u)!=Find(t.v)){
id[Find(t.u)]=Find(t.v);
if(c=='R') v1.push_back(t.w);
else v2.push_back(t.w);
ans+=t.w; ++k;
}
}
if(k!=n) ans=-1;
return ans;
}