关于题目
来自曾老的集训期间的特别的周末作业
HMK 1 for NOIP (130/300)
数列的价值(100/100)
题目描述
有一个数列 {ai} ,数列中有 n 个数。对于一个数列,它的价值为 x1^x2^…^xn 。
现在去掉第 i 个数 ai,则它的价值变为 wi 。求 max{wi} 。
输入格式
一行一个正整数 n 。
接下来一行 n 个数,表示这个数列 {ai} 。
输出格式
输出一个数,即输出答案。
样例数据 1
输入 [复制]
3
1 5 2
输出
7
备注
【样例解释】
5 ^ 2 = 7
1 ^ 2 = 3
1 ^ 5 = 4
【数据范围】
对于前 30% 的数据:n<=1000;
对于 100% 的数据:n<=106;ai 和答案均在 int 范围。
签到题,记得加优化。
MY/STD.CPP
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
int n;
long long a[1000050],sum,ans=0;
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
cin >> n; cin>>a[1]; sum=a[1];
for(int i=2;i<=n;i++)cin>>a[i],sum^=a[i];
for(int i=1;i<=n;i++)
ans=max(ans,sum^a[i]);
cout << ans << endl;
}
图(30/100)
题目描述
给定一张无向图,求满足以下条件的点对 (x,y) 数目:对任意点 z (z!=x,y),边 (x,z) 和 (y,z) 同时存在或同时不存在。
输入格式
一行两个整数 n,m ,分别表示这幅图点数和边的数量。
接下来 m 行,每行两个整数,表示这两个点之间存在一条无向边。保证没有重边和自环。
输出格式
输出一行一个整数,表示答案。
样例数据 1
输入 [复制]
3 3
1 2
2 3
1 3
输出
3
备注
【数据范围】
对于前 30% 的数据:n,m<=500;
对于 100% 的数据:n,m<=106 。
题读错了。。。看成那两个点必须和所有其他点连边。。。
MY.CPP
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int kkk=1000050;
int n,m,u,v;
int cnt=0;
struct node{int u,v;}side[2*kkk];
void add(int u,int v)
{
side[++cnt].u = u;
side[cnt].v = v;
}
long long ans=0;
int jud[kkk];
int main()
{
cin >> n >> m;
for(int i=1;i<=m;i++)
{
cin >> u >> v;
add(u,v);
jud[u]++;jud[v]++;
}
for(int i=1;i<=n;i++)
if(jud[i]>=n-2)
ans++;
if(ans)
{
ans = ans*(ans-1)/2;
for(int i=1;i<=m;i++)
if((jud[side[i].u]>=n-2)&&(jud[side[i].v]>=n-2))
if((jud[side[i].u]<n-1)||(jud[side[i].v]<n-1))
ans -= 1;
}
cout << ans << endl;
}
题解用到了哈希??有点迷
STD.CPP
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
inline ll Read()
{
ll X=0,w=1; char ch=0;
while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
ll a[1000005],b[1000005],v[1000005],n,m,x,y,r,j,ans;
void get_ans()
{
j=1;
for(int i=1;i<=n;++i)
if(b[i]!=b[j])
ans+=(i-j)*(i-j-1)/2,j=i;
ans+=(n-j)*(n-j+1)/2;
}
int main()
{
n=Read();m=Read();ans=0;
for(int i=1;i<=n;++i)v[i]=r=r*233+17;
for(int i=1;i<=m;++i)
{
x=Read(),y=Read();
a[x]^=v[y],a[y]^=v[x];
}
for(int i=1;i<=n;i++) b[i]=a[i];
sort(b+1,b+n+1); get_ans();
for(int i=1;i<=n;++i) b[i]=a[i]^v[i];
sort(b+1,b+n+1); get_ans();
printf("%lld\n",ans);
}
树链
题目描述
给出一棵树,在这个树上有 m 条链,每条链有一定的价值。现在请你选出若干条链,其中任意两条链所经过的点都无交集,使得得到的价值总和最大。
输入格式
一行两个整数 n,m 。n 表示树的节点树,节点标号为 1,…,n。m 表示链的数量。
接下来 n-1 行,每行两个数 x,y,表示 x,y 间有一条树边。
接下来 m 行,每行三个数 u,v,w。其中 u,v 表示链的两个端点,w 表示这条链具有的价值。
输出格式
输出一行一个整数,即为答案。
样例数据 1
输入 [复制]
7 3
1 2
1 3
2 4
2 5
3 6
3 7
2 3 4
4 5 3
6 7 3
输出
6
备注
【样例解释】
选择第 2,3 条链,价值和为 6 。
【数据范围】
对于前 30% 数据:n,m<=1000;
对于 100% 数据:n,m<=100000;w<=1000。
完全没头绪。。后来才发现是树形Dp。。
STD.CPP
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<cctype>
#include<vector>
using namespace std;
const int N =200005;
int T,n,m,tot,idx,x,y,c[N],l[N],r[N],dp[N],sum[N];
int first[N],deep[N],nxt[N],to[N],f[N][20];
struct node{int x,y,w,lca;}p[N];
vector<int>chain[N];
inline void init(){
tot=idx=0;
memset(f,0,sizeof(f));
memset(first,0,sizeof(first));
memset(c,0,sizeof(c));
}
inline int Readint(){
int i=0,f=1;char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';
return i*f;
}
inline void Insert(int pos,int val){
for(int i=pos;i<=n+1;i+=i&(-i))
c[i]+=val;
}
inline int query(int pos){
int ret=0;
for(int i=pos;i;i-=i&(-i)){
ret+=c[i];
}
return ret;
}
inline void add(int x,int y){
nxt[++tot]=first[x];
first[x]=tot;
to[tot]=y;
}
inline void dfs(int u,int fa){
l[u]=++idx;
for(int i=1;i<=18;i++){
f[u][i]=f[f[u][i-1]][i-1];
if(!f[u][i-1]) break;
}
for(int i=first[u];i;i=nxt[i]){
if(to[i]!=fa){
deep[to[i]]=deep[u]+1;
f[to[i]][0]=u;
dfs(to[i],u);
}
}
r[u]=idx+1;
}
inline int lca(int a,int b){
if(deep[a]<deep[b]) swap(a,b);
int k=deep[a]-deep[b];
for(int i=18;i>=-1;i--)
if(k&(1<<i)) a=f[a][i];
if(a==b) return a;
for(int i=18;i>=-1;i--)
if(f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i];
return f[a][0];
}
inline void solve(int u){
dp[u]=sum[u]=0;
for(int i=first[u];i;i=nxt[i]){
int v=to[i];
if(v!=f[u][0]){
solve(v);
sum[u]+=dp[v];
}
}
dp[u]=sum[u];
for(int i=0;i<chain[u].size();i++){
int x=p[chain[u][i]].x;
int y=p[chain[u][i]].y;
int tmp=query(l[x])+query(l[y]);
dp[u]=max(dp[u],tmp+sum[u]+p[chain[u][i]].w);
}
Insert(l[u],sum[u]-dp[u]);
Insert(r[u],dp[u]-sum[u]);
}
int main()
{
for(int i=1;i<=n;i++) chain[i].clear();
n=Readint(),m=Readint();
for(int i=1;i<n;i++){
x=Readint(),y=Readint();
add(x,y); add(y,x);
}
dfs(1,0);
for(int i=1;i<=m;i++){
p[i].x=Readint(),p[i].y=Readint();
p[i].w=Readint();
p[i].lca=lca(p[i].x,p[i].y);
chain[p[i].lca].push_back(i);
}
solve(1);
cout<<dp[1]<<endl;
return 0;
}
感想
多做Dp。。多练题。。。现在只能这样了。。。orz