链接: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);
}
题意:
给一棵树,你可以选择任意的(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;
}