Codeforces #400
Codeforces #400
Codeforces 776A A Serial Killer
链接:http://codeforces.com/problemset/problem/776/A
题意:刚开始有两个幸存者,每天会死一个人,新来一个人,输出每天存活人姓名
思路:水题
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
using namespace std;
int main(){
string name1,name2;
string tmp1,tmp2;
while(cin>>name1>>name2){
int n;
cin>>n;
for(;n!=-1;n--){
cout<<name1<<" "<<name2<<endl;
cin>>tmp1>>tmp2;
if(name1==tmp1) name1=tmp2;
else name2=tmp2;
}
}
return 0;
}
Codeforces 776B Sherlock and his girlfriend
链接:http://codeforces.com/problemset/problem/776/B
题意:有n个数,2,3,4...n+1,现在需要用尽量少的颜色来将这些数染色,如果一个数能整除另一个数,那么就不能涂同样的颜色
思路:将质数涂1,质数能够整除的数涂2就行了,最多两种颜色,注意一下只有两个数和一个数的情况就行
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
int color[100000+10];
int main(){
int n;
while(scanf("%d",&n)!=EOF){
memset(color,-1,sizeof(color));
int maxx;
maxx=2;
int cnt,cntnow;
for(int i=2;i<=n+1;i++){
if(color[i]==-1){
color[i]=1;
for(int j=2;j*i<=n+1;j++){
color[i*j]=2;
}
}
}
if(n<=2) maxx=1;
printf("%d\n",maxx);
for(int i=2;i<=n+1;i++){
printf("%d ",color[i]);
}
printf("\n");
}
}
Codeforces 776C Molly's Chemicals
链接:http://codeforces.com/contest/776/problem/C
题意:
给一个序列有n个数,问有多少个区间的和是\(K^t\)
思路:
\({sum[j]-sum[i]=k^t =>sum[j]=k^t+sum[i]}\)
因为k的幂次不会很大,所以枚举t,从前往后做,标记\({flag[k^t+sum[i]]}++\),这样做到后面每次有满足这样的前缀和,就说明有\(flag[k^t+sum[i]]\)个区间。枚举的时候注意k=1和-1的时候,可以预处理\(k^t\) 。#include <stdio.h>
#include <iostream>
#include <map>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <vector>
using namespace std;
const int MAXN = 1e5+10;
long long a[MAXN];
long long sum[MAXN];
map<long long ,int> m;
vector<long long> Pow;
int n,k;
void init(){
if(k==1||k==-1) return ;
Pow.clear();
long long num=1;
while(1){
Pow.push_back(num);
num*=k;
if(num>1e15||num<-1e15)break;
}
}
long long solve(){
init();
memset(sum,0,sizeof(sum));
sum[0]=0;
long long cnt=0;
long long num;
for(int i=0;i<=n;i++){
if(i>0)
sum[i]=sum[i-1]+a[i];
cnt+=m[sum[i]];
if(k==1) m[1+sum[i]]++;
else if(k==-1) m[1+sum[i]]++,m[-1+sum[i]]++;
else
for(int j=0;j<Pow.size();j++){
num=Pow[j];
m[num+sum[i]]++;
}
}
return cnt;
}
int main(){
while(scanf("%d %d",&n,&k)!=EOF){
m.clear();
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
printf("%lld\n",solve());
}
return 0;
}
Codeforces 776D The Door Problem
链接:http://codeforces.com/contest/776/problem/D
题意:n扇门,m个开关,开关可以控制很多扇门,每扇门由一定由两个开关控制,每扇门也有自己初始的状态,问能否按开关使得门都是开的
思路:把开关分成两个点,\(i\)为选择,\(i+m\)为不选择,那么将门作为边,门如果原本是开的,那么要么两个开关都选择,要么两个开关都不选择,如果门本来是关的,那么两个开关只能且一定要选择一个,并查集将两个开关通过门链接起来,最后查询祖先的时候,如果\(fa[i]==fa[i+m]\)说明矛盾,达不到全开的状态
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int n,m;
const int MAXN=2e5+10;
int fa[MAXN];
int door[MAXN];
int Sw[MAXN][2];
void init(){
for(int i=0;i<2*m+5;i++){
fa[i]=i;
}
}
int find(int x){
return fa[x]=fa[x]==x?x:find(fa[x]);
}
void unite(int x,int y){
x=find(x),y=find(y);
fa[x]=y;
}
int main(){
while(scanf("%d %d",&n,&m)!=EOF){
init();
memset(Sw,0,sizeof(Sw));
for(int i=1;i<=n;i++) scanf("%d",&door[i]);
for(int i=1;i<=m;i++){
int cnt;
int num;
scanf("%d",&cnt);
while(cnt--){
scanf("%d",&num);
if(!Sw[num][0]) Sw[num][0]=i;
else Sw[num][1]=i;
}
}
for(int i=1;i<=n;i++){
if(door[i]){
unite(Sw[i][0],Sw[i][1]);
unite(Sw[i][0]+m,Sw[i][1]+m);
}
else {
unite(Sw[i][0],Sw[i][1]+m);
unite(Sw[i][0]+m,Sw[i][1]);
}
}
bool flag=true;
for(int i=1;i<=m;i++){
if(find(i)==find(i+m)){
flag=false;
break;
}
}
if(flag){
puts("YES");
}
else puts("NO");
}
}
Codeforces 776E The Holmes Children
链接:http://codeforces.com/contest/776/problem/E
题意:\(f(n)\)表示\(f(1)=1\),\(n≥2\)时有多少个\((x,y)\)满足\(x+y=n \quad and \quad gcd(x,y)=1\),\(g(n)=\sum_{d|n}f(n/d)\),\(F_{k}(n)=\begin{cases}f(g(n),&\text{for k =1}\\ g(F_{k-1}(n)),&\text{for k > 1 and k mod 2 = 0}\\ f(F_{k-1}(n)),&\text{for k > 1 and k mod 2 = 1} \end{cases}\)
求\(F_{k}(n)\text{ mod 1e9+7}\)
思路:\(f(n)\)表示\(f(1)=1\),\(n≥2\)时有多少个\((x,y)\)满足\(x+y=n\) \(and\) \(gcd(x,y)=1\)
即\(gcd(x,n-x)=1=>gcd(x,n)=1\) 即有多少个小于n的数与x互质,即欧拉函数的定义,\(f(x)=phi(x)\) ,\(g(n)=\sum_{i=1}^{n}f(d)[d|n]\),即莫比乌斯反演公式,\(g(n)=n\),也就是求(k+1)/2次\(𝛷(𝛷(𝛷(...)))\)
现在证明 \(g(n)=\sum_{i=1}^{n}f(d)[d|n]=n\)
\(g(n)={\sum}_{d|n}𝛷(d),n=\prod^{k}_{i=1}p^{e_i}_{i}\),\(p\)为\(n\)的质因数。
根据莫比乌斯反演的充分必要性,\(𝛷(n)\)为积性函数,则\(g(n)\)也为积性函数
\(g(n)=\prod^{k}_{i=1}g(p_i^{e_i})\) 则 \(g(p^k)=\sum_{i=0}^kf(p^i)\) 因为\(f(x)=𝛷(x)\)
所以\(g(p^k)=\sum_{i=0}^kf(p^i)\)=\(\sum_{i=0}^k𝛷(p^i)\)
因为$ 𝛷(pi)=pi(1-\frac{1}{p})=pi-p,\quad i\geq1$
所以\(\sum^k_{i=0}𝛷(p^i)\)=1+\(\sum^k_{i=1}𝛷(p^i)\)=1+\(p^k\)-1=\(p^k\)
所以\(g(p^k)=p^k\),即\(g(n)=n\)
#include <stdio.h>
const int mod=1e9+7;
long long res,a;
long long phi(long long n){
res=n,a=n;
for(long long i=2;i*i<=a;i++){
if(a%i==0){
res=res/i*(i-1);
while(a%i==0) a/=i;
}
}
if(a>1) res=res/a*(a-1);
return res;
}
int main(){
long long n,k;
while(scanf("%lld %lld",&n,&k)!=EOF){
long long ans=n;
k=(k+1)/2;
while(k--){
if(ans==1){
break;
}
ans=phi(ans);
}
printf("%lld\n",ans%mod);
}
return 0;
}