ICM Technex 2017 and Codeforces Round #400 (Div. 1 + Div. 2, combined)
A:
B:
C: Molly's Chemicals(前缀和+map)
题意:在这个数组里面取连续的一段,问有多少种取法使得这段的和为k的自然数幂次;
思路:不能直接暴力,连续的自然联想到前缀和,假设要求和为x的数目,k的不同的幂次就是多个不同的x的计数和了;sum[i]-sum[j]=x,sum[i]-x=sum[j],累计sum[j]的数目就好了;
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn=1e5+10; int n,k; LL a[maxn]; vector<LL>ve; map<LL,int>mp; int main() { cin>>n>>k; for(int i=1;i<=n;i++)scanf("%I64d",&a[i]); LL tep=1; for(int i=1;i<=60;i++) { if(abs(tep)>1e14)break; ve.push_back(tep); tep=tep*k; } sort(ve.begin(),ve.end()); int len=unique(ve.begin(),ve.end())-ve.begin(); // for(int i=0;i<len;i++)cout<<ve[i]<<endl; LL ans=0,sum=0; mp[0]++; for(int i=1;i<=n;i++) { sum=sum+a[i]; for(int j=0;j<len;j++) { LL temp=ve[j]; ans=ans+mp[sum-temp]; } mp[sum]++; } cout<<ans; return 0; }
D: The Door Problem(2-SAT)
题意:有m个开关和n个门,每个门都是由两个开关控制,但每个开关控制可能不止一个门,现在给出初始的门的开闭状况,问是否有一种方法使所有的门都打开;
思路:由于每个门都是由两个开关控制,所以对于门为1(开)应该只有一个开关变化,对于门为0(闭)两个开关要么都变要么都不变,这就是2-SAT的问题的模型了;
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+4; int n,m,r[maxn],s[2*maxn],c=0; vector<int>ve[maxn],G[maxn*2]; bool mark[2*maxn]; bool dfs(int x) { if(mark[x^1])return false; if(mark[x])return true; mark[x]=true; s[c++]=x; for(int i=0;i<G[x].size();i++) { if(!dfs(G[x][i]))return false; } return true; } inline void add(int x,int xval,int y,int yval) { x=x*2+xval; y=y*2+yval; G[x^1].push_back(y); G[y^1].push_back(x); } bool solve() { for(int i=0;i<m*2;i+=2) { if(!mark[i]&&!mark[i+1]) { c=0; if(dfs(i)) { while(c>0)mark[s[--c]]=false; if(!dfs(i+1))return false; } else return false; } } return true; } int main() { memset(mark,0,sizeof(mark)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&r[i]); for(int i=0;i<m;i++) { int x,y; scanf("%d",&x); for(int j=1;j<=x;j++) { scanf("%d",&y); ve[y].push_back(i); } } for(int i=1;i<=n;i++) { int u=ve[i][0],v=ve[i][1]; if(r[i])add(u,0,v,1),add(u,1,v,0); else add(u,0,v,0),add(u,1,v,1); } if(solve())puts("YES"); else puts("NO"); return 0; }
E: The Holmes Children(数论)
题意:给出了这个公式,和f(n)和g(n)的公式,求给定的n和k下的函数值;
思路:f(n)是满足x+y=n&&gcd(x,y)==1的(x,y)对数,即gcd(x,n-x)==1的对数,就是欧拉函数值phi(n),g(n)=∑f(n/d)(d|n)=n;Fk(n)等于(k+1)/2层欧拉函数,所以就变成了一道简单题啦;
#include <bits/stdc++.h> using namespace std; typedef long long LL; LL n,k; const int maxn=1e6+10; const LL mod=1e9+7; int vis[maxn],cnt=0; LL prime[maxn]; inline void init() { for(int i=2;i<maxn;i++) { if(!vis[i]) { prime[cnt++]=i; for(int j=2*i;j<maxn;j+=i)vis[j]=1; } } } LL phi(LL x) { LL tep=x; for(int i=0;i<cnt;i++) { if(x<prime[i])break; if(x%prime[i]==0) { tep=tep/prime[i]*(prime[i]-1); while(x%prime[i]==0)x/=prime[i]; } } if(x>1)tep=tep/x*(x-1); return tep; } LL solve(LL cur,LL num) { if(cur==1)return 1; if(num==0)return cur; return solve(phi(cur),num-1); } int main() { init(); cin>>n>>k; k=(k+1)/2; cout<<solve(n,k)%mod; return 0; }