题型:数论
题意:
有n个纸片,每张纸片上有一个数,两张纸片拼接起来形成一个新的数,如歌这个数能够被3整除,那么就称这个数是Lucky Tickets。现在问最多拼出多少个Lucky Tickets。(拼过的纸片不能再拼)。
分析:
根据性质,当一个数各个位上的数之和能够被3整除,则这个数能被3整除。
此题用贪心求解可过,下面证明贪心的正确性。
设有四个数a,b,c,d,若(a+b)%3=0,(a+c)%3=0,(c+d)%3=0,那么(b+d)%3=0。
证明: (a+b)%3=0 ①
(a+c)%3=0 ②
(c+d)%3=0 ③
①②合并得: ((a+b)%3+(a+c)%3)%3=0
→ (2a+b+c)%3=0 ④
②③合并得: ((a+c)%3+(c+d)%3)%3=0
→ (2c+a+d)%3=0 ⑤
④⑤合并的: (3(a+c)+b+d)%3=0
→ (3(a+c)%3+(b+d)%3)%3=0
∵ 3(a+c)%3=0
∴ (b+d)%3=0
得证。
上述证明说明:选ab拼接和cd拼接,与选ac拼接和bd拼接是一样的,所以只需贪心拼接即可。
代码:
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#define INF 0x7f7f7f7f
using namespace std;
struct Number {
char str[10];
int sum;
} a[12345];
bool vis[12345];
int n;
int main() {
while(~scanf("%d",&n)) {
for(int i=0; i<n; i++) {
scanf("%s",a[i].str);
a[i].sum=0;
int len=strlen(a[i].str);
for(int j=0; j<len; j++) {
a[i].sum+=a[i].str[j]-'0';
}
}
memset(vis,true,sizeof(vis));
bool find=false;
int ans=0;
for(int i=0; i<n-1; i++) {
if(vis[i]==false) continue;
for(int j=i+1; j<n; j++) {
if(vis[j]==false) continue;
if((a[i].sum+a[j].sum)%3==0) {
ans++;
vis[i]=false;
vis[j]=false;
find=true;
break;
}
}
if(find) continue;
}
printf("%d\n",ans);
}
return 0;
}