思维题

链接:Wrong Answer

Wrong Answer

解析:

构造题

官方题解:

第一个数放-1,后面长为len,和为sum,每个都不为负数

k=(sum−1)(len+1)−sum⋅len=sum−len−1

随便代入一个len,构造输出,因为|ai|≤10^6,len>1000

ac:
 

#include<bits/stdc++.h>
#define ll long long
#define MAXN 2005*2
using namespace std;
 
void print(int k,int n)
{
    printf("-1 ");
    for(int i=0;i<k;i++)
    {
        if(n>=1000000)
        {
            printf("1000000 ");
            n=n-1000000;
        }
        else
        {
            printf("%d ",n);
            n=0;
        }
    }
}
 
int main()
{
    ll n;
    cin>>n;
    printf("2000\n");
    int k=1999;
    n=k+1+n;
    print(k,n);
}

Add on a Tree

题意:

给一棵树,你可以选择任意的(u,v),赋值给(u,v)的简单路径

如果可以将这棵树设计成任意的权值样,呢么输出YES,否则输出NO

解析:

图中不能出现入度为2的点

假设有a,b,c三点连接一个d点(父节点)

让(a,d)权值,边为x,可以选择(a,c):+0.5x   (a,b):+0.5x   (b,c):-0.5x

这样仅(a,d)边权值发生变化,其他的都不变,所以一定要有权值大于等于3的结点

如果入度为1,呢么他是叶子结点.

ac:

#include<bits/stdc++.h>
#define MAXN 1000005
using namespace std;
int in[MAXN];

int main()
{
    int n,u,v;
    scanf("%d",&n);
    for(int i=0;i<n-1;i++)
    {
        scanf("%d%d",&u,&v);
        in[u]++;
        in[v]++;
    }
    for(int i=1;i<=n;i++)
        if(in[i]==2)
        {
            printf("NO\n");
            return 0;
        }
    printf("YES\n");
    return 0;
}

http://codeforces.com/contest/1230/problem/C

题意:

有21种多米诺骨可以当边使用,如图所示

给你一个n个点,m条边的无向图,让你将多米诺骨牌作为边加入图中,一个点上的值相同才能连接

问最多可以放多少多米诺骨牌

解析:

1.如果可连接的点<=6的情况下,直接输出m

2.模拟将i点和j点当做同一点,因为多米诺股票最多就边为6,然后计算即可,如果标记的i-j是一条边,最后sum还要+1

ac:

#include<bits/stdc++.h>
using namespace std;
int mm[10][10];
int vv[10][10];
int in[10];

int main()
{
    int n,m,u,v;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        mm[u][v]=mm[v][u]=1,in[u]++,in[v]++;
    }
    int d=0;
    for(int i=1;i<=7;i++)
        if(in[i])d++;
    if(d<=6)
    {
        printf("%d\n",m);
        return 0;
    }
    int ans=0;
    for(int i=1;i<=7;i++)
    {
        for(int j=1;j<=7;j++)
        {
            int sign=mm[i][j];//模拟i当j,然后把连j的边全部删除,如果i-j是一条边,最后可以多一条重边
            
            for(int k=1;k<=7;k++)
                for(int l=1;l<=7;l++)
                    vv[k][l]=mm[k][l];
            for(int k=1;k<=7;k++)
            {
                if(vv[j][k]==1||vv[k][j]==1){
                    vv[j][k]=vv[k][j]=0;
                    vv[i][k]=vv[k][i]=1;
                }
            }
            int sum=0;
            for(int k=1;k<=7;k++)
            {
                for(int l=k+1;l<=7;l++)
                {
                    if(vv[k][l]==1||vv[l][k]==1)
                    {
                        sum++;
                        vv[k][l]=vv[l][k]=0;
                    }
                }
            }
            
            ans=max(ans,sum+sign);
        }
    }
    printf("%d\n",ans);
    return 0;
}

代码:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;
 
int d[10][10];
 
int main()
{
    int n, m, a, b;
    cin >> n >> m;
    for(int i = 0; i < m; i++){
        cin >> a >> b;
        d[a][b] = 1;
        d[b][a] = 1;
    }
    if(n < 7){ 
        cout << m << endl;
    }
    else {
        int ans = INF;
        for(int i = 1; i <= 7; i++){  //假设i和j是数字相同的顶点
            for(int j = i + 1; j <= 7; j++){
                int cnt = 0;
                for(int k = 1; k <= 7; k++){
                    if(d[i][k] && d[j][k]) cnt++;  // cnt记录如果这样有多少条边要被放弃
                }
                ans = min(ans, cnt);
            }
        }
        cout << m - ans << endl;
    }
    return 0;
}

http://codeforces.com/contest/1229/problem/A

题意:

有n个人,每个人有一个能力可能有(0-59种能力),b[i]是能力的权值

a[i]来描述能力,将a[i]转化为二进制,如果第i位为1,则他会第i个技能

如果一个人的能力比另外一个人强,只要存在一个技能,他会,另一个人不会,两个人可以互相都比对方强

你可以选择一些元素组成一个集合,该集合中,不存在一个人比其他任何人都强

解析:

在一个集合中,不能存在一个技能只有一个人会的情况

=> 首先我们选择一些元素,这些元素的a[i]相同,我们选择一些a[i]相同的元素加入集合,如果所以a[i]都唯一,呢么集合为空

-> 我们选择这些包含相同a[i]的,然后选择一些a[i]包含在呢些集合中的

集合中有:11100*2,000111*2,

可以选择10100,000110,会的技能被任一元素的a[i]包含,不能选择001100,不能被单独一个包含

用|运算可以快速取得结果, a[i]|v[i]==v[i],a[i]被v[i]包含,a[i]会的v[i]都会

ac:

#include<bits/stdc++.h>
#define ll long long
#define MAXN 10005
using namespace std;
struct node
{
    ll a,b;
    friend bool operator<(node x,node y)
    {
        return x.a<y.a;
    }
}ee[MAXN];
ll vis[MAXN];
set<ll> st;

int main()
{
    ll n;
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
        scanf("%lld",&ee[i].a);
    for(ll i=1;i<=n;i++)
        scanf("%lld",&ee[i].b);
    if(n==1)
    {
        printf("0\n");
        return 0;
    }
    sort(ee+1,ee+n+1);
    for(ll i=1;i<=n;i++)
    {
        if(ee[i].a==ee[i+1].a&&i+1<=n)
            st.insert(ee[i].a);
    }
    set<ll>::iterator it;
    ll ans=0;
    for(it=st.begin();it!=st.end();it++)
    {
        ll v=*it;
        for(int i=1;i<=n;i++)
        {
            if((v|ee[i].a)==v&&vis[i]==0)
            {
                ans+=ee[i].b;
                vis[i]=1;
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}

https://codeforces.com/contest/1199/problem/D

题意

长n的数组,q次操作

最后单点查询n次

q:1 x v  将x修改为v

q: 2 x    修改小于x的所以a[i]为x

解析:

可以用线段树,也可以有o(n)的算法

因为每次区间修改都是整个区间修改,具有单调性

所以我们可以记录每次修改的值,从后往前贪心区间极小值

#include<bits/stdc++.h>
#define MAXN 200005
using namespace std;
int a[MAXN],pos[MAXN],maxs[MAXN];

int main()
{
    int n,m,x,v;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),pos[i]=1;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&x);
        if(x==1){
            scanf("%d%d",&x,&v);
            a[x]=v;
            pos[x]=i;
        }
        else{
            scanf("%d",&x);
            maxs[i]=x;
        }
    }
    for(int i=m;i>=1;i--)
        maxs[i]=max(maxs[i+1],maxs[i]);
    for(int i=1;i<=n;i++)
        a[i]=max(a[i],maxs[pos[i]]);//选择(pos[i],m)里最大的
    for(int i=1;i<n;i++)
        printf("%d ",a[i]);
    printf("%d\n",a[n]);
    return 0;
}

对局匹配:http://lx.lanqiao.cn/problem.page?gpid=T454

题意:

小明喜欢在一个围棋网站上找别人在线对弈。这个网站上所有注册用户都有一个积分,代表他的围棋水平。
小明发现网站的自动对局系统在匹配对手时,只会将积分差恰好是K的两名用户匹配在一起。如果两人分差小于或大于K,系统都不会将他们匹配。
现在小明知道这个网站总共有N名用户,以及他们的积分分别是A1, A2, ... AN。
小明想了解最多可能有多少名用户同时在线寻找对手,但是系统却一场对局都匹配不起来(任意两名用户积分差不等于K)
解析:

将数组划分成k组,每组内每个数相差k,这样1个组内的元素和别的组的元素不可能构成差为k

{a,a+k,2k+a,3k+a.....},保存个数

1.{0,k,2k,3k....}

2.{1,k+1,2k+1,3k+1,....}

3.{2,k+2,2k+2,3k+2,...}

....

然后我们就从每个组中选取最多的,累加每个组可以选取的最多个数

累加每个组不相邻的最大权值和

ac:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 1e5+5;
int dp[N],ct[N],val[N],n,k,x;

int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        int ans=0,maxs=0;
        memset(ct,0,sizeof(ct));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            ct[x]++;
            maxs=max(maxs,x);
        }
        if(k==0)
        {
            for(int i=0;i<N;i++)
                if(ct[i]) ans++;
        }
        else{
            for(int i=0;i<k;i++)
            {
                int now=0;
                for(int j=i;j<=maxs;j+=k)
                    val[++now]=ct[j];
                dp[0]=0,dp[1]=val[1];
                for(int j=2;j<=now;j++)
                    dp[j]=max(dp[j-1],dp[j-2]+val[j]);
                ans += dp[now];
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

https://www.cnblogs.com/caturra/p/9308624.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值