The 2018 ICPC Asia Nanjing Regional Contest [Cloned]

A-Adrien and Austin

题意:

给了你n个石子,编号从1到n,玩家要取最少一个最多k个连续编号的石子,求是先手赢,还是后手赢(不能操作即为输)

solution:

1、k==1时,判奇偶
2、k>1时,n<3时,此时n<=k必定成立,先手必胜,n>=3时,将n个石子从中间取几个,使其两边变成完全一样的两堆,此时先手必胜。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
int n,k;
int main()
{
   
    scanf("%d%d",&n,&k);
    if(n==0)printf("Austin");
    else if(k==1)
    {
   
        if(n%2)printf("Adrien");
        else printf("Austin");
    }
    else
        printf("Adrien");

        
    return 0;
}

B-Tournament

C-Cherry and Chocolate

D-Country Meow

E-Eva and Euro coins

F-Frank

G-Pyramid

题意:

给你n层的的三角形,求正三角形个数

solution:

打表找规律,把每个点的坐标存进去,然后跑一边n^3求正三角形个数
打表代码

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
struct node
{
   
    double x,y;
}p[10005];
int cnt=0;
int main()
{
   
    p[cnt].x=0;p[cnt].y=0;cnt++;
    for(int i=1;i<=20;i++)
    {
   
        double pos=-i;
        for(int j=1;j<=i+1;j++)
        {
   
            p[cnt].x=pos;
            p[cnt].y=-i*sqrt(3);
            pos+=2;
            cnt++;
        }
        int c=0;
        for(int j=0;j<cnt;j++)
        {
   
            for(int k=j+1;k<cnt;k++)
            {
   
                for(int w=k+1;w<cnt;w++)
                {
   
                    double l1=(p[j].x-p[k].x)*(p[j].x-p[k].x)+(p[j].y-p[k].y)*(p[j].y-p[k].y);
                    double l2=(p[j].x-p[w].x)*(p[j].x-p[w].x)+(p[j].y-p[w].y)*(p[j].y-p[w].y);
                    double l3=(p[w].x-p[k].x)*(p[w].x-p[k].x)+(p[w].y-p[k].y)*(p[w].y-p[k].y);
                    //cout<<l1<<' '<<l2<<' '<<l3<<endl;
                    if(fabs(l1-l2)<1e-6&&fabs(l2-l3)<1e-6)c++;
                }
            }
        }
        printf("%d\n",c);
    }
    return 0;
}


然后找出C(n+3,4)求组合数的规律

#include<bits/stdc++.h>

using namespace std;
#define INF 0x3f3f3f3f
typedef pair<int,int>P;
typedef long long ll;
int t;
ll n;
const int mod=1e9+7;
ll fpow()
{
   
    ll a=24,ans=1;
    ll ti=mod-2;
    while(ti)
    {
   
        if(ti%2)ans=ans*a%mod;
        a=a*a%mod;
        ti/=2;
    }
    return ans;
}
int main()
{
   
    scanf("%d",&t);
    ll inv24=fpow();
    while(t--)
    {
   
        scanf("%lld",&n);
        n+=3;
        ll res=0;
        res=n*(n-1)%mod*(n-2)%mod*(n-3)%mod*inv24%mod;
        printf("%lld\n",res);
    }

}

H-Huge Discount

I- Magic Potion

题意:

给了n个heros,m个monsters,以及k个potion
每个英雄能杀死一个怪兽,用了potion后英雄能多杀一只怪兽(每个英雄只能用一次potion)
给了你n个集合,第i个集合里有ti个数,对应当前第i个英雄所能杀的怪兽的编号
问最多能杀多少只怪兽。

solution:

二分图最大匹配or网络流dinic
网络流dinic做法
给每个人和所杀怪兽之间连边,k个option与人连边,建立超级源点、超级终点
3 5 2
4 1 2 3 5
2 2 5
2 1 2

5 10 2
2 3 10
5 1 3 4 6 10
5 3 4 6 8 9
3 1 9 10
5 1 3 6 7 10

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef pair<int,int>P;
typedef long long ll;
int n,m,k;
int head[200050];
int cur[200050];
int deep[200050];
int cnt;
int S,T;
struct Edge
{
   
    int to,w,next;
}edge[400050];
void init()
{
   
    memset(head,-1,sizeof(head));
    cnt=0;
}
void add_edge(int u,int v,int w)
{
   
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
int dfs(int u,int flow)
{
   
    if(u==T)return flow;
    for(int& i=cur[u];i!=-1;i=edge[i].next)
    {
   
        if(deep[edge[i].to]==deep[u]+1&&edge[i].w!=0)
        {
   
            int d=dfs(edge[i].to,min(flow,edge[i].w));
            if(d>0)
            {
   
                edge[i].w-=d;
                edge[i^1].w+=d;
                return d;
            }
        }
    }
    return 0;
}
int bfs()
{
   
    queue<int> q;
    while(!q.empty())q.pop();
    memset(deep,0,sizeof(deep));
    deep[S]=1;
    q.push(S);
    do
    {
   
        int u=q.front();q.pop();
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
   
            if(deep[edge[i].to]==0&&edge[i].w>0)
            {
   
                deep[edge[i].to]=deep[u]+1;
                q.push(edge[i].to);
                if(edge[i].to==T)return 1;
            }
        }
    }while(!q.empty());
    if(deep[T]>0)return 1;
    return 0;
}
int Dinic()
{
   
    int ans=0;
    while(bfs())
    {
   
        for(int i=0;i<=T;i++)cur[i]=head[i];
        while(int d=dfs(S,INF))
        {
   
            ans+=d;
        }
    }
    return ans;
}
int main()
{
   
    scanf("%d%d%d",&n,&m,&k);
    init();
    S=0;T=m+n+2;
    int st=n+m+1;
    add_edge(S,st,k);
    add_edge(st,S,0);
    for(int i=1;i<=n;i++)
    {
   
        add_edge(S,i,1);
        add_edge(i,S,0);
        add_edge(st,i,1);
        add_edge(i,st,0);
        int kk;scanf("%d",&kk);
        for(int j=0;j<kk;j++)
        {
   
            int x;scanf("%d",&x);
            add_edge(i,x+n,1);
            add_edge(x+n,i,0);

        }

    }
    for(int i=1;i<=m;i++)
    {
   
        add_edge(i+n,T,1);
        add_edge(T,i+n,0);
    }
    printf("%d\n",Dinic());

}

J-Prime Game

题意:

求所有子区间内质因子个数和(子区间内相同的质因子算一个)

solution:

找规律,同一个质因子有一个对后面的贡献,以及前面没有出现该质因子是也会产生一个贡献,所以就是找规律求贡献

#include<bits/stdc++.h>

using namespace std;
#define INF 0x3f3f3f3f
typedef pair<int,int>P;
typedef long long ll;
int n,a[1000006];
vector<int> e[1000006];
int vis[1000006],prime[1000006],cnt=0;
int main()
{
   
    vis[1]=1;
    for(int i=2;i<=1000000;i++)
    {
   
        if(!vis[i])
        {
   
            prime[cnt++]=i;
            for(int j=i*2;j<=1000000;j+=i)
                vis[j]=1;
        }
    }
    scanf("%d",&n);
    for(int i=0;i<n;i++)scanf("%d",&a[i]);
    for(int i=0;i<n;i++)
    {
   
        int j=0;
        while(a[i]>1)
        {
   
            if(a[i]%prime[j]==0)
            {
   
                if(e[prime[j]].size()==0)
                    e[prime[j]].push_back(-1);
                e[prime[j]].push_back(i);
                while(a[i]%prime[j]==0)
                    a[i]/=prime[j];
            }
            else if(!vis[a[i]])
            {
   
                if(e[a[i]].size()==0)
                    e[a[i]].push_back(-1);
                e[a[i]].push_back(i);
                a[i]=1;
            }
            j++;
        }
    }
    ll res=0;
    for(int i=0;i<cnt;i++)
    {
   
        for(int j=1;j<e[prime[i]].size();j++)
        {
   
            res+=1ll*(e[prime[i]][j]-e[prime[i]][j-1])*(n-e[prime[i]][j]);
            //cout<<prime[i]<<' '<<res<<endl;
        }

    }
    printf("%lld",res);

}

K-Kangaroo Puzzle

L-Lagrange the Chef

M-Mediocre String Problem