Codeforces Round #236 (Div. 2) (全)

来源:互联网 发布:cad截图软件betterwmf 编辑:程序博客网 时间:2024/04/30 21:12

题目地址:   http://codeforces.com/contest/402

A. Nuts

题意: 给你4个数k,a,b,v ,  k表示每一个盒子最多可以分成多少部分,a 表示一共多少个nuts,b表示一共多少个divisors (x个可以把 盒子分成x+1部分),v表示每一部分最多能放多少个nuts.

要把所有的nuts全部放到盒子中去,使用<=b个divisors,求 使用的盒子的数量最小。

就是 把b个divisors尽可能的 往开始的盒子里面放,之后 求b个nuts可以最少占用几个盒子 即可。

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<string>using namespace std;#define INF 1000000000int k,a,b,v;int main(){    scanf("%d%d%d%d",&k,&a,&b,&v);    int xx=b/(k-1);    int left=b-xx*(k-1);    int ans=0;    if(xx*v*k>=a)    {        ans=(a/(k*v));        if(a%(k*v)) ans++;    }    else if(xx*v*k+(left+1)*v>=a)        ans=xx+1;    else    {        ans=xx+1;        int tmp=a-xx*v*k-(left+1)*v;        ans+=((tmp/v));        if(tmp%v) ans++;    }    printf("%d\n",ans);    return 0;}

B. Trees in a Row

题意: 开始给你n个树木的高度,可以进行 操作, 一次操作 是指 使得一棵树增加或者减小到任意整数高度,给你k , 要求进行某些操作后使得这些高度,形成等差数列,差值为k。

求最小的操作数,并且输出方案。 注意 一个树的高度不能为0!!!

直接暴力枚举每个树的高度 为正好不变 求其他 是否改变,求 最小的更改数目 就OK了。

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<string>using namespace std;#define INF 1000000000//typedef __int64 LL;#define N 1005int n,k;int num[N],fir;int main(){    scanf("%d%d",&n,&k);    for(int i=1;i<=n;i++)    {        scanf("%d",&num[i]);    }    int ans=INF;    for(int i=1;i<=n;i++)    {        int tmp=0;        int mi=(num[i]-(i-1)*k);        if(mi<=0) continue;        for(int j=1;j<i;j++)        {            int mm=num[i]-(i-j)*k;            if(mm!=num[j]) tmp++;        }        for(int j=i+1;j<=n;j++)        {            int mm=num[i]+(j-i)*k;            if(mm!=num[j]) tmp++;        }        if(tmp<ans)        {            ans=tmp; fir=num[i]-(i-1)*k;        }    }    printf("%d\n",ans);    for(int i=1;i<=n;i++)    {        if(fir+(i-1)*k==num[i]) continue;        if(fir+(i-1)*k>num[i])            printf("+ %d %d\n",i,abs(fir+(i-1)*k-num[i]));        else            printf("- %d %d\n",i,abs(num[i]-(fir+(i-1)*k)));    }    return 0;}

C. Searching for Graph

题意: 给你n 和p ,要你构造一个无向图,使得 一共有2*n+p条边,没有自回路和重边,对于任意选出的k个点,这k个点之间的 边的数目 <=2*k+p个

当初,看到过的人 写的比较快 就猜了一下,直接 依次 从 标号小的连接到 标号大的。事后证明是对的,确实如此可以,满足以上条件。

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<string>using namespace std;#define INF 1000000000//typedef __int64 LL;int t,n,p;int main(){    scanf("%d",&t);    while(t--)    {        int cou=0;        scanf("%d%d",&n,&p);        for(int i=1;i<=n;i++)        {            for(int j=i+1;j<=n;j++)            {                cou++;                printf("%d %d\n",i,j);                if(cou>=2*n+p) break;            }            if(cou>=2*n+p) break;        }    }    return 0;}

D. Upgrading Array

题意:给你一个数列a,一些bad素数 b(除了这些之外的素数都是good 素数),可以对数列a,进行多次操作: 对a的前缀数组[1,r],求出他们的GCD,之后全部约去,得到一个新的数组。 之后每一个数有一个值,假设p是x的最小的素数因子,则 这个值f(1)=0; f(x)=f(x/p)+1  (如果p是good素数), f(x)=f(x/p)-1   (如果p是bad素数), 求 可以得到的 数值之和 的 最大值。

其实,不必在意最小的素数因子, 一个数的 价值= 分解后的 素数因子中 good的数目- bad的数目。

贪心进行求解 即可,求出 每个位置 i ,的 1~i中的 数 的 GCD,【之后从后往前】判断每个GCD的 价值,如果>0不约去,<0约去,这样肯定是最优的,因为这样的GCD因子 约去 对于之前的 数的 价值都会增加。从而总价值增加。

code:

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<string>#include<vector>#include<cmath>#include<map>#include<set>using namespace std;#define INF 1000000000#define MOD 1000000007#define N 50005#define M 32000bool ispri[M];int num[N],n,m,gc[N];set<int> bad;vector<int> prime;void pr(){for(int i=2;i<M;i++){if(!ispri[i]){prime.push_back(i);for(int j=2*i;j<M;j+=i)ispri[j]=1;}}}int gcd(int x,int y){if(!y) return x;return gcd(y,x%y);}int cal(int x){int ret=0;for(int i=0;i<prime.size() && prime[i]<=x;i++){int now=prime[i];int xx=1;if(bad.find(now)!=bad.end()) xx=-1; while(x%now==0){ret+=xx;x/=now;}}if(x>1){ if(bad.find(x)!=bad.end()) ret--; else ret++;}return ret;}int main(){pr();scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&num[i]);}int tmp;for(int i=1;i<=m;i++){scanf("%d",&tmp); bad.insert(tmp);}gc[1]=num[1];for(int i=2;i<=n;i++){gc[i]=gcd(gc[i-1],num[i]);}int tot=0;int last=1;for(int i=n;i>=1;i--){tmp=cal(gc[i]/last);if(tmp<0){last=gc[i];tot+=cal(num[i]/gc[i]);}else            tot+=cal(num[i]/last);}printf("%d\n",tot);    return 0;}



E. Strictly Positive Matrix

题意:给一个矩阵A,保证Aij大于等于0,并且Aii不全为0。问是否存在k使得A^k中的每个元素大于0

其实,可以看做 离散数学中的可到达矩阵 的 概念, 和图论联系起来,如果存在K使得 A^K中的每个元素>=0,就是 矩阵A代表的 图, 是一个 强连通图。

就是 判断 这个图 是否是强连通 即可。

Tarjan算法。可参考  https://www.byvoid.com/blog/scc-tarjan/

code :

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<string>#include<vector>#include<cmath>#include<stack>#include<set>using namespace std;#define INF 1000000000#define N 2005int n,tot,hh[N*N],dfn[N],low[N],flag,ad=0,ins[N],cou;struct node{int u,next;}edge[N*N];stack<int > s;void init(){tot=0;memset(hh,-1,sizeof(hh));memset(dfn,0,sizeof(dfn));memset(ins,0,sizeof(ins));}void add(int x,int y){edge[tot].u=y; edge[tot].next=hh[x];hh[x]=tot++;}void tar(int u){if(flag) return ;dfn[u]=low[u]=++ad;s.push(u);ins[u]=1;for(int i=hh[u];i!=-1;i=edge[i].next){int v=edge[i].u;// printf("%d \n",v);if(!dfn[v]){tar(v);low[u]=min(low[u],low[v]);}else if(ins[v]){low[u]=min(low[u],dfn[v]);}}if(dfn[u]==low[u]){int m=s.top();  s.pop();cou++;if(cou>1) { flag=1; return ;}ins[m]=0;while(m!=u){m=s.top(); s.pop(); ins[m]=0;}}}void sol(){cou=0; flag=0;for(int i=1;i<=n;i++){if(!dfn[i]){tar(i);if(flag){printf("NO\n"); return ;}}}printf("YES\n");}int main(){scanf("%d",&n);int tmp;init();for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){scanf("%d",&tmp);if(tmp){add(i,j);}}}int mark=0;sol();    return 0;}


0 0