A. Team Olympiad
思路:给1,2,3计数,答案就是它们中的最小者。然后从数组里面取就可以了。
#include<iostream>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
int a[5010];
int cnt[4]={0};
int main(){
int n;
while(cin>>n){
for(int i=1;i<=n;i++){
cin>>a[i];
cnt[a[i]]++;
}
int ans=min(cnt[1],cnt[2]);
ans=min(cnt[3],ans);
cout<<ans<<endl;
while(ans--){
int q,w,e;
q=w=e=0;
for(int i=1;i<=n;i++){
if(a[i]==1&&q==0){
q=i;
a[i]=0;
}
if(a[i]==2&&w==0){
w=i;
a[i]=0;
}
if(a[i]==3&&e==0){
e=i;
a[i]=0;
}
}
printf("%d %d %d\n",q,w,e);
}
}
return 0;
}
B. Queue
思路:建立一个向后的链和向前的链。用向后的链,从0开始扫一遍,可以得到排在偶数位的。然后随便找一个没出现过的号,用向前的链跟踪到头,就是排在第一位的,再用向后的链扫一遍,得到排在奇数位的。
#include<iostream>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
int data[1000010]; //向后
int data2[1000010]; //向前
bool has[1000010];
int que[200010];
int main(){
int n;
while(cin>>n){
memset(data,-1,sizeof(data));
memset(data2,-1,sizeof(data2));
for(int i=1;i<=n;i++){
int a,b;
scanf("%d%d",&a,&b);
data[a]=b;
data2[b]=a;
has[a]=1;
has[b]=1;
}
has[0]=0;
int tmp=0;
int k=2;
while(1){
que[k]=data[tmp];
has[que[k]]=0;
k+=2;
tmp=data[tmp];
if(tmp<=0){
break;
}
}
//找一个没出现的
int fnd;
for(int i=1;i<=1000000;i++){
if(has[i]){
fnd=i;
break;
}
}
//跟踪到头
tmp=fnd;
while(1){
if(data2[tmp]==-1)break;
tmp=data2[tmp];
}
k=1;
while(1){
que[k]=tmp;
tmp=data[tmp];
k+=2;
if(tmp<=0)break;
}
for(int i=1;i<=n;i++){
printf("%d ",que[i]);
}
}
return 0;
}
C. Hacking Cypher
思路:大整数的整除判断肯定只能逐位来。如从左往右扫描,计算每位模a的结果,乘以10(因为是十进制)后往右叠加并取模,如果到某位模为0说明可以在该位分割。从右往左扫描的原理则是反过来,用一个变量表示当前位的大小,每次扩大10倍并取模(因为是十进制)往左叠加取模,如果模为0说明可以分割。如果某个地方左右都能分割,就是合法的,注意不能有前导零。
#include<iostream>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
char num[1000010];
bool ok[1000010];
int tmp [1000010];
int main(){
while(~scanf("%s",num)){
int siz=0;
int a,b;
cin>>a>>b;
if(num[0]=='0'){
cout<<"NO"<<endl;
continue;
}
int len=strlen(num);
int cur=0;
for(int i=0;i<len;i++){
cur*=10;
cur+=num[i]-'0';
cur%=a;
if(cur==0){
if(i<len-1&&num[i+1]!='0'){
ok[i]=1;
}
}
}
bool hasans=0;
int split;
int k=1;
cur=0;
for(int i=len-1;i>=0;i--){
cur+=(num[i]-'0')*k;
cur%=b;
if(cur==0&&ok[i-1]&&num[i]!='0'){
hasans=1;
split=i;
break;
}
k*=10;
k%=b;
}
if(hasans){
cout<<"YES"<<endl;
for(int i=0;i<split;i++){
printf("%c",num[i]);
}
cout<<endl;
for(int i=split;i<len;i++){
printf("%c",num[i]);
}
}else{
cout<<"NO"<<endl;
}
}
return 0;
}
D. Chocolate
思路:dfs。找到两块巧克力可以达到的状态,记录状态下需要的操作次数。最后扫描两块巧克力的状态集合,发现大小相等的,把操作次数相加并更新结果。其实这题可以用数学方法做的,效率更高。
#include<iostream>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
#define ll long long
struct node{
ll a;
ll b;
int t;
ll s;
node(ll aa,ll bb,int tt=0){
a=aa; b=bb;
t=tt;
s=aa*bb;
}
bool operator<(const node& n2)const{
if(s!=n2.s)return s<n2.s;
return t<n2.t;
}
};
set<node> s1;
set<node> s2;
void dfs(node n,int id){
if(id==1){
if(s1.count(n))return;
s1.insert(n);
}else{
if(s2.count(n))return;
s2.insert(n);
}
if(n.a%2==0){
node q(n.a/2,n.b,n.t+1);
dfs(q,id);
}
if(n.a%3==0){
node q(n.a/3*2,n.b,n.t+1);
dfs(q,id);
}
if(n.b%2==0){
node q(n.a,n.b/2,n.t+1);
dfs(q,id);
}
if(n.b%3==0){
node q(n.a,n.b/3*2,n.t+1);
dfs(q,id);
}
}
int main(){
int a1,b1,a2,b2;
while(cin>>a1>>b1>>a2>>b2){
node c1(a1,b1,0);
node c2(a2,b2,0);
dfs(c1,1);
dfs(c2,2);
int ans=10086;
int ans1,ans2,ans3,ans4;
for(set<node>::iterator it=s1.begin();it!=s1.end();it++){
for(set<node>::iterator it2=s2.begin();it2!=s2.end();it2++){
if(it->s==it2->s){
if(it->t+it2->t<ans){
ans=it->t+it2->t;
ans1=it->a;
ans2=it->b;
ans3=it2->a;
ans4=it2->b;
}
}
}
}
if(ans!=10086){
cout<<ans<<endl;
cout<<ans1<<" "<<ans2<<endl;
cout<<ans3<<" "<<ans4<<endl;
}else{
cout<<-1<<endl;
}
}
return 0;
}