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;
}

  

 

posted @ 2017-02-25 21:35  LittlePointer  阅读(159)  评论(0编辑  收藏  举报