P102
zhx

a

【问题描述】
你是能看到第一题的 friends 呢。
——hja
两种操作:
1、加入一个数。
2、询问有多少个数是?的倍数。
【输入格式】
第一行一个整数?,代表操作数量。
接下来?行,每行两个数???,?。其中???表示是哪种操作,第二个?是操作的
参数。
【输出格式】
一行一个整数,代表所有询问答案的异或值。
【样例输入】
5
1 2
1 3
2 2
1 6
2 3
【样例输出】
3
【数据范围与规定】
对于第?组数据,? ≤ ? = 1000?。

#include<iostream>
#include<cstdio>
#include<cmath>
#define maxn 400010
using namespace std;
int n,opt,x,sum[maxn];
long long ans=;
int main(){
//freopen("a.in","r",stdin);
freopen("a.in","r",stdin);freopen("a.out","w",stdout);
scanf("%d",&n);
while(n--){
scanf("%d%d",&opt,&x);
if(opt==){//插入一个数
int i;
for(i=;i*i<x;i++){
if(x%i==){
sum[i]++;
sum[x/i]++;
}
}
int w=sqrt(x);
if(w*w==x)sum[w]++;
}
if(opt==)
ans=ans^sum[x];
}
cout<<ans;
fclose(stdin);fclose(stdout);
return ;
}

100分

b

【问题描述】
你是能看到第二题的 friends 呢。
——laekov
Hja 有一棵?个点的树,树上每个点有点权,每条边有颜色。一条路径的权
值是这条路径上所有点的点权和,一条合法的路径需要满足该路径上任意相邻
的两条边颜色都不相同。问这棵树上所有合法路径的权值和是多少。
【输入格式】
第一行一个数?。
一行?个数代表每个点的权值。
接下来? − 1行每行三个整数?,?,?,代表?到?之间有一条颜色为?的边。
【输出格式】
一行一个整数代表答案。
【样例输入】
6
6 2 3 7 1 4
1 2 1
1 3 2
1 4 3
2 5 1
2 6 2
【样例输出】
134
【数据范围与规定】
30%的数据,1 ≤ ? ≤ 1000。
数据随机 另外20%的数据,是一条链。
对于100%的数据,1 ≤ ? ≤ 3 × 10 5 ,1 ≤ ? ≤ 10 9 。

#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 300010
int n,w[maxn],num,head[maxn],s[maxn],col[maxn],nu[maxn];
bool vis[maxn];
long long ans;
struct node{
int to,pre,v;
}e[maxn*];
void Insert(int from,int to,int v){
e[++num].to=to;
e[num].v=v;
e[num].pre=head[from];
head[from]=num;
}
bool flag;
void dfs(int now,int father,int sum){
flag=;ans+=sum;
for(int i=head[now];i;i=e[i].pre){
int to=e[i].to;
if(e[i].v==father)continue;
flag=;
dfs(to,e[i].v,sum+w[to]);
}
}
int du[maxn];
int main(){
//freopen("Cola.txt","r",stdin);
freopen("b.in","r",stdin);freopen("b.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d",&w[i]);
int x,y,z;
for(int i=;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
Insert(x,y,z);Insert(y,x,z);
du[x]++;du[y]++;
}
bool fl=;
int st;
for(int i=;i<=n;i++){
if(du[i]==)st=i;
if(du[i]>){
fl=;
break;
}
}
if(fl){//是一条链
int cnt=;
s[]=w[st];
vis[st]=;
while(){
for(int i=head[st];i;i=e[i].pre){
if(vis[e[i].to])continue;
vis[e[i].to]=;
cnt=cnt+;
col[cnt]=e[i].v;
st=e[i].to;
}
s[cnt+]=s[cnt]+w[st];
if(du[st]==)break;
}
s[cnt+]=s[cnt]+w[st];
nu[]=;nu[]=;
for(int i=;i<=cnt;i++){
if(col[i]!=col[i-]){
nu[i+]=nu[i]+;
}
else nu[i+]=;
}
for(int i=;i<=cnt+;i++){
for(int j=;j<=nu[i];j++){
ans+=s[i]-s[i-j-];
}
}
cout<<ans;
return ;
}
for(int i=;i<=n;i++){
flag=;
dfs(i,,w[i]);
if(!flag)ans-=w[i];
}
ans/=;
cout<<ans;
fclose(stdin);fclose(stdout);
return ;
}

50分 爆搜+链的特判

#define ll long long
#include<iostream>
#define N 300005
#include<cstdio>
#define M 2*N
using namespace std;
int n,a[N],head[N],to[M],Next[M],e,col[M];
ll g[N],nu[N];
ll ans;
void buid(int u,int v,int c){
Next[++e]=head[u];head[u]=e;
to[e]=v,col[e]=c;
}
void dfs(int now,int f,int cf){
ll G=;
g[now]=a[now];nu[now]=;
int fl=;
for(int i=head[now];i;i=Next[i]){
int j=to[i];if(j==f) continue;
dfs(j,now,col[i]);
if(col[i]!=cf){
fl=;
nu[now]+=nu[j];
g[now]+=nu[j]*a[now]+g[j];
}
G+=nu[j]*a[now]+g[j];
}
ans+=G;
if(fl)return;
for(int i=head[now];i;i=Next[i]){
int j=to[i];
if(j==f) continue;
for(int I=i;I;I=Next[I]){
int J=to[I];
if(J==f) continue;
if(col[i]!=col[I])
ans+=g[j]*nu[J]+g[J]*nu[j]+a[now]*nu[j]*nu[J];
}
}
}
int main(){
freopen("b.in","r",stdin);
freopen("b.out","w",stdout); scanf("%d",&n);
for(int i=;i<=n;++i) scanf("%d",&a[i]);
for(int i=;i<n;++i){
int u,v,c;scanf("%d%d%d",&u,&v,&c);
buid(u,v,c);
buid(v,u,c);
}
dfs(,,);
cout<<ans<<endl;
return ;
}

100分 树形dp

c

【问题描述】
你是能看到第三题的 friends 呢。
——aoao
Hja 特别有钱,他买了一个? × ?的棋盘,然后 Yjq 到这个棋盘来搞事。一
开始所有格子都是白的,Yjq 进行?次行操作?次列操作,所谓一次操作,是将对
应的行列上的所有格子颜色取反。 现在 Yjq 希望搞事之后棋盘上有?个黑色格子,
问 Yjq 有多少种搞事的方法。
【输入格式】
第一行五个整数?,?,?,?,?。
【输出格式】
一行一个整数代表答案对10 9 + 7取模之后的值。
【样例输入】
2 2 2 2 4
【样例输出】
4
【数据规模与约定】
对于100%的数据,1 ≤ ?,?,?,? ≤ 100000,0 ≤ ? ≤ ? × ?,有部分分。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
using namespace std;
#define maxn 100010
#define mod 1000000007
int n,m,r,c,ans;
int v0[maxn],v1[maxn],v2[maxn],v3[maxn],v4[maxn];
long long s;
int mul(long long a,int b){
a*=b;
if (a>=mod) a%=mod;
return (int)a;
}
int Pow(int a,int b){
int res=;
while(b){
if(b&)res=mul(res,a);
a=mul(a,a);
b>>=;
}
return res;
}
void inc(int &a,int b){
a+=b;
if(a>=mod)a-=mod;
}
int main(){
freopen("c.in","r",stdin);freopen("c.out","w",stdout);
scanf("%d%d%d%d"LL,&n,&m,&r,&c,&s);
v1[]=;
for(int i=;i<=;i++)v0[i]=Pow(i,mod-); // v0[i] 存放的是 i 的逆元
int tmp=;
for(int i=;i<=(r>>);i++){ // v1[i] 即C(n+i-1, i)
v1[i]=tmp;
tmp=mul(tmp,mul(i+n,v0[i+]));
}
tmp=;
for(int i=;i<=(c>>);i++){ // v2[i] 即C(m+i-1, i)
v2[i]=tmp;
tmp=mul(tmp,mul(i+m,v0[i+]));
}
tmp=;
for(int i=;i<=n;i++){ // v3[i] 即C(n, i)
v3[i]=tmp;
tmp=mul(tmp,mul(n-i,v0[i+]));
}
tmp=;
for(int i=;i<=m;i++){ // v4[i] 即C(m, i)
v4[i]=tmp;
tmp=mul(tmp,mul(m-i,v0[i+]));
}
for(int i=r&;i<=min(n,r);i+=){ //枚举.....(r-6), (r-4), (r-2), r
if(i*!=n){
if(((s-(long long)i*m))%(n-i*))continue; // s = r0*m+c0*n-2*r0*c0 ==> (s-r0*m) = c0*(n-r0*2)
int b=(int)((s-(long long)i*m)/(n-i*)); // 计算 c0
if(b>c||b<||((c-b)&))continue; // 判断这个c0是否可能
int nowans=v3[i];
nowans=mul(nowans,v1[(r-i)>>]);
nowans=mul(nowans,v4[b]);
nowans=mul(nowans,v2[(c-b)>>]);
//答案就是首先在n行里面选r0行,在m列里面选c0的方案数,再乘上选(r-r0)/2个行的方案数(这些行被操作两次,相当于没有动),再乘上选(c-c0)/2个列的方案数
inc(ans,nowans);
}
else{ //在这种条件下呢,无论列数怎么变,黑色格子数量都不会变了,恒定为r0*m,(这个时候等式(s-r0*m) = c0*(n-r0*2)中n-r0*2为0,c0的值不唯一)
if((long long)i*m!=s)continue;
int nowans=v3[i];
nowans=mul(nowans,v1[(r-i)>>]); //这部分同上
int cnt=;
for(int b=(c&);b<=min(r,c);b+=) //因为列的数量不影响答案所以要枚举所有可能的列数分别计算一遍
inc(cnt,mul(v4[b],v2[(c-b)>>]));
inc(ans,mul(nowans,cnt)); // 这里应该是mul(nowans, cnt)吧?
}
}
printf("%d\n",ans);
return ;
}

100分

05-12 17:22