洛谷P2856
【题目翻译】: 奶牛的名字都是由英文字母表的前 个字母构成的(全部为大写字母且长度 )。现在奶牛们想设计一种手机, 有 个按键。请你把这 个字母按顺序分配给 个按键,使能够通过按这些键而唯一确定的奶牛数尽量多。求最多可以唯一确定多少头奶牛,输出方案。如果有多种方案,输出编号小的按键容纳字母最多的方案。
【思路】: 暴力枚举每个字母分配给哪个按键。记 表示字母 分配给按键 。不难发现, 可以用搜索算法得出。
假设我们已经得到了 ,考虑如何计算可以唯一确定多少头奶牛的名字。
依题意,每头奶牛的名字长度
,我们可以视整个字符串为一个
进制的数,这样就可以判断每个字符串的hash值
。得到hash值
后,我们就可以判断每个字符串是否只出现一次了。
【注意】: 数据的开头有一个没有用的整数,必须把它输入但忽略掉。
【代码】:
int L,B,ans,ch[30],CH[30];
string str[1010];int n;
long long num[1010];
void updata_answer(){
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)
for(int j=0;j<str[i].size();j++)
num[i]=num[i]*(B+1)+ch[str[i][j]-'A'+1];//计算hash值
sort(num+1,num+n+1);
register int tot=0;
for(int i=1;i<=n;i++)
if (num[i]!=num[i-1]&&num[i]!=num[i+1]) tot++;//计算有多少个不同的字符串
if (tot>=ans){//注意这样才保证了答案字典序最小
ans=tot;
memcpy(CH,ch,sizeof(ch));
}
}
void dfs(int sub,int color){
if (sub>L){
if (color>=B)
updata_answer();
return;
}
if (sub>1&&color<B){
ch[sub]=color+1;
dfs(sub+1,color+1);
}
if (color+L-sub>=B){
ch[sub]=color;
dfs(sub+1,color);
}
ch[sub]=-1;
}
int test_number;
int main(){
cin>>test_number;test_number=1;//忽略掉这个无用的数字
while (test_number--){
memset(ch,-1,sizeof(ch));
cin>>B>>L>>n;
for(int i=1;i<=n;i++)
cin>>str[i];
dfs(1,1);CH[0]=CH[1]-1;
printf("%d",ans);
for(int i=1;i<=L;i++)
if (CH[i]!=CH[i-1])
printf("\n%c",(char)(i+'A'-1));
else printf("%c",(char)(i+'A'-1));
printf("\n");
}
return 0;
}
洛谷P3708
【题意】: 输入一个整数
,记
求
。
【思路】: 假设我们已经知道了 ,考虑如何 推得 ,我们发现被模数增加 ,取模后的结果要么变为 ,要么也随之增加 。
假设所有的结果都增加 ,那么结果就增加 。哪些数会变为零呢?当然是 的因数啦。
举个例子, 。对比 中的每一项就可以得到如上的规律了。
记
表示
的因数和,则:
这就可以递推计算了,当然 ,而 可以在 的时间复杂度内提前计算出来,然后就是 递推计算了。
【代码】:
#define ll long long
void write(ll a,bool b){
if (a==0){
if (b) putchar('0');
return;
}
else if (a<0){
putchar('-');
write(-a,false);
}
else{
write(a/10,false);
putchar(a%10+'0');
}
}
void print(ll a){
write(a,true);
putchar(' ');
}
const int N=1e6+100;
ll f[N],cnt[N];int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n/i;j++)
f[i*j]+=i;
cnt[1]=n-1;
for(int i=2;i<=n;i++)
cnt[i]=cnt[i-1]+n-f[i];
for(int i=1;i<=n;i++)
print(cnt[i]);
return 0;
}