今天开头就写着几个大字
信心题
浅览题目 好像都不会诶
我肯定是打开方式不对 于是我又重新开了一遍
发现依旧不会做 于是乱搞
1.祖孙询问
【问题描述】
已知一棵n个节点的有根树。有m个询问。每个询问给出了一对节点的编号x和y,询问x与y的祖孙关系。
【输入格式】
输入第一行包括一个整数n表示节点个数。
接下来n行每行一对整数对a和b表示a和b之间有连边。如果b是-1,那么a就是树的根。
第n+2行是一个整数m表示询问个数。
接下来m行,每行两个正整数x和y。
【输出格式】
对于每一个询问,输出1:如果x是y的祖先,输出2:如果y是x的祖先,否则输出0。
【样例输入】
10
234 -1
12 234
13 234
14 234
15 234
16 234
17 234
18 234
19 234
233 19
5
234 233
233 12
233 13
233 15
233 19
【样例输出】
1
0
0
0
2
【数据规模】
对于30%的数据,n,m≤1000。
对于100%的.据,n,m≤40000,每个节点的编号都不超过40000。
恩 对于树结构的东西我一般都不怎么会
一看 好的 暴力还是可以的
然后想想 其实dfs 一下处理记录处理的顺序 然后就有一些规律了
void dfs(int x){
timein[x] =cur++;
for(int i=head[x]; i!=-1 ;i=e[i].next){
if(timein[e[i].v]==0)
{
dfs(e[i].v);
}
}
timeout[x] = cur++;
}
for(int i=1 ;i<=m ;i++)
{
int x=read(),y=read();
if(x==-1){printf("1\n");continue;}
if(y==-1){printf("2\n");continue;}
if(timein[x] < timein[y] && timeout[x] >timeout[y]){printf("1\n");continue;}
if(timein[x] > timein[y] && timeout[x] <timeout[y]){printf("2\n");continue;}
printf("0\n");
}
以上就是我的大致思路。。。
其实我觉得应该可以过的
但没有 其实dfs 可以改一下的
当然这是很明显的LCA问题了
但我不会 或者说 记不得
然后重新看了看
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,zz,head[40002],root;
struct bian{int to,nx;} e[80002];
int fa[40002][20],h[40002];//2^16=65536
void insert(int x,int y)
{
zz++; e[zz].to=y; e[zz].nx=head[x]; head[x]=zz;
zz++; e[zz].to=x; e[zz].nx=head[y]; head[y]=zz;
}
void init()
{
int i,x,y;
scanf("%d",&n);
for(i=1;i<=n;i++)
{scanf("%d%d",&x,&y);
if(y==-1) root=x;
else insert(x,y);
}
}
void dfs(int x)
{
int i,p;
for(i=1;i<=15;i++)
{if(h[x]<(1<<i)) break;
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for(i=head[x];i;i=e[i].nx)
{p=e[i].to;
if(p==fa[x][0]) continue;
h[p]=h[x]+1; fa[p][0]=x;
dfs(p);
}
}
int lca(int x,int y)
{
if(h[x]<h[y]) swap(x,y);
int i,c;
c=h[x]-h[y];
for(i=15;i>=0;i--)
{if(c&(1<<i)) x=fa[x][i];}
for(i=15;i>=0;i--)
{if(fa[x][i]!=fa[y][i])
{x=fa[x][i]; y=fa[y][i];}
}
if(x==y) return x;
else return fa[x][0];
}
void work()
{
int i,x,y,t;
scanf("%d",&m);
dfs(root);
for(i=1;i<=m;i++)
{scanf("%d%d",&x,&y);
if(x==y) printf("0\n");
else
{t=lca(x,y);
if(t==x) printf("1\n");
else if(t==y) printf("2\n");
else printf("0\n");
}
}
}
int main(){
.......
}
dfs 好像可以 如果担心爆就bfs吧
2.比赛
【问题描述】
有两个队伍A和B,每个队伍都有n个人。这两支队伍之间进行n场1对1比赛,每一场都是由A中的一个选手与B中的一个选手对抗。同一个人不会参加多场比赛,每个人的对手都是随机而等概率的。例如A队有A1和A2两个人,B队有B1和B2两个人,那么(A1 vs B1,A2 vs B2)和(A1 vs B2,A2 vs B1)的概率都是均等的50%。
每个选手都有一个非负的实力值。如果实力值为X和Y的选手对抗,那么实力值较强的选手所在的队伍将会获得(X-Y)^2的得分。
求A的得分减B的得分的期望值。
【输入格式】
第一行一个数n表示两队的人数为n。
第二行n个数,第i个数A[i]表示队伍A的第i个人的实力值。
第三行n个数,第i个数B[i]表示队伍B的第i个人的实力值。
【输出格式】
输出仅包含一个实数表示A期望赢B多少分。答案保留到小数点后一位(注意精度)。
【样例输入】
2
3 7
1 5
【样例输出】
20.0
【数据规模】
对于30%的数据,n≤50。
对于100%的.据,n≤50000;A[i],B[i]≤50000。
恩
我坚信暴力一定都会
然后排序再暴力一定可以优化
然后其实排序之后拿个指针记录就可以线性完成
我们算A的所以把B给预处理了
S【】记前缀和 SQ【】记前缀平方和 (*long long 很重要)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline int read(){ // int
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void init(){
freopen("mat.in","r",stdin);
freopen("mat.out","w",stdout);
}
int n;
int a[50005],b[50005];
double ans = 0.0;
long long s[50005],sq[50005];
inline long long sqr(long long x){
return x*x;
}
void readdata(){
n=read();
for(int i=1 ;i<=n ;i++)
a[i]=read();// A power-range
for(int i=1 ;i<=n ;i++)
b[i]=read();// B power-range
//have a sort to get up-arr
sort(a+1 ,a+n+1);
sort(b+1 ,b+n+1);
for(int i=1 ;i<=n ;i++) //维护前缀
{
sq[i] = sqr(b[i]) + sq[i-1]; // b[i]^2
s[i] = b[i] + s[i-1]; // b[i]
}
}
// liner-work()
void work(){
int L=0;// L+1
double tem = 0.0;
for(int i=1 ;i<=n ;i++) // enumeration
{ tem = 0.0;
while(L<n && a[i] > b[L+1])//
{
L++;
}
//二次项展开合并
tem += L * sqr(a[i]) - 2 * s[L] * a[i] + sq[L];
tem -= (n - L) * sqr(a[i]) - 2 * (s[n] - s[L]) *a[i] + (sq[n] - sq[L]);
tem /= n;
ans+=tem;
}
}
int main(){
init();
readdata();
work();
printf("%.1lf",ans);
}
(那些无聊的注释直接无视)
3.数字
【问题描述】
一个数字被称为好数字当他满足下列条件:
1. 它有2*n个数位,n是正整数(允许有前导0)。
2. 构成它的每个数字都在给定的数字集合S中。
3. 它前n位之和与后n位之和相等或者它奇数位之和与偶数位之和相等
例如对于n=2,S={1,2},合法的好数字有1111,1122,1212,1221,2112,2121,2211,2222这样8种。
已知n,求合法的好数字的个数mod 999983。
【输入格式】
第一行一个数n。
接下来一个长度不超过10的字符串,表示给定的数字集合。
【输出格式】
一行一个数字表示合法的好数字的个数mod 999983。
【样例输入】
2
0987654321
【样例输出】
1240
【数据规模】
对于20%的数据,n≤7。
对于100%的.据,n≤1000,|S|≤10。
题解:
ANS=前n位之和与后n位之和相等的方案数+奇数位之和与偶数位之和相等的方案数-前n位之和与后n位之和相等且奇数位之和与偶数位之和相等的方案数
前2个需要+的方案数都很好求,直接递推,重点是最后一个要满足2个条件的方案数怎么求,其实也很简单:
因为前n位之和=后n位之和,奇数位之和=偶数位之和
所以前n位中奇数位之和=后n位中偶数位之和 且
前n位中偶数位之和=后n位中奇数位之和
现在只要求上面这个问题的方案数,由于两个等式中的元素无交集,也是十分好算的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define mod 999983
#define ll long long
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n;
char ch[15];
int a[15];
int f[1005][9005];
ll ans;
ll cal(int x)
{
ll ans=0;
for(int i=0;i<=x*9;i++)
if(f[x][i])
ans=(ans+((ll)f[x][i]*f[x][i]))%mod;
return ans;
}
int main()
{
//freopen("num.in","r",stdin);
//freopen("num.out","w",stdout);
n=read();
scanf("%s",ch);
int l=strlen(ch);
for(int i=0;i<l;i++)
a[i+1]=ch[i]-'0';
f[0][0]=1;
for(int i=0;i<n;i++)
for(int j=0;j<=n*9;j++)
if(f[i][j])
for(int k=1;k<=l;k++)
f[i+1][j+a[k]]=(f[i+1][j+a[k]]+f[i][j])%mod;
ans=2*cal(n)-cal(n/2)*cal(n-n/2);
printf("%d",(ans%mod+mod)%mod);
return 0;
}