为出题人点赞
T1.
找规律(良心出题人啊)。
假设 a [ i ] ≠ b [ i ] a[i]\neq b[i] a[i]=b[i] 一共有 t m p tmp tmp 对,一定是 0 / 1 0/1 0/1 组合,那么剩下 0 / 1 0/1 0/1 的数量就是 c n t 0 / c n t 1 − t m p cnt_0/cnt_1-tmp cnt0/cnt1−tmp 。又因为 c n t 0 / c n t 1 − t m p cnt_0/cnt_1-tmp cnt0/cnt1−tmp 一定是偶数,所以统计 0 / 1 0/1 0/1 出现次数的奇偶性就能求出 t m p tmp tmp 。
时间复杂度 O ( n + q ) O(n+q) O(n+q) 。
T2.
组合数 / dp 计数。
我们考虑枚举线段的左右端点,并规定端点必选,这条线段的整点有 N = gcd ( i , j ) N=\gcd(i,j) N=gcd(i,j) 个。同时求出 k = ⌈ d / ( i / N ) 2 + ( j / N ) 2 ⌉ k=\lceil d/\sqrt{(i/N)^2+(j/N)^2}\rceil k=⌈d/(i/N)2+(j/N)2⌉ 。
那么方案数为 2 ∗ ( N − 1 N − 1 − ( n − 1 ) ∗ ( k − 1 ) ) 2*\binom{N-1}{N-1-(n-1)*(k-1)} 2∗(N−1−(n−1)∗(k−1)N−1) 。 对横竖的情况特判即可。
#include<bits/stdc++.h>
#define db double
#define ll long long
#define mkp make_pair
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define fi first
#define se second
using namespace std;
const int mod=1e9+7;
const int Maxn=505;
inline int read() {
int x=0,f=1; char c=getchar();
while(c<'0'||c>'9') {
c=getchar();
}
while(c>='0'&&c<='9') {
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
return x;
}
int gcd(int x,int y) {
return y==0?x:gcd(y,x%y);
}
int T;
ll C[Maxn][Maxn],res;
int n,r,c,d;
void add(ll &x,ll y) {
x+=y;
if(x>=mod) x-=mod;
}
int main() {
// freopen("data.in","r",stdin);
for(int i=0;i<=501;i++) {
C[i][0]=1;
}
for(int i=1;i<=501;i++) {
for(int j=1;j<=501;j++) {
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
scanf("%d",&T);
while(T--) {
scanf("%d%d%d%d",&n,&r,&c,&d);
if(n==1) {
printf("%d\n",(r+1)*(c+1));
continue;
}
res=0;
for(int i=0;i<=r;i++) {
for(int j=0;j<=c;j++) {
if(i==0&&j==0) continue;
int N=gcd(i,j),k=ceil(sqrt(ceil(1.0*d*d/(1.0*(i/N)*(i/N)+1.0*(j/N)*(j/N)))));
if((n-1)*k>N) continue;
if(i==0||j==0) res=(res+C[N-1-(n-1)*(k-1)][n-2]*(r-i+1)%mod*(c-j+1)%mod)%mod;
else res=(res+2*C[N-1-(n-1)*(k-1)][n-2]%mod*(r-i+1)%mod*(c-j+1)%mod)%mod;
}
}
printf("%lld\n",res);
}
}
T3.
大水题。
可以发现,一个节点 u u u 可以将子树中的两个序列给拼成一个序列,贪心策略为在 u u u 的子树内拼接成尽可能大的序列,再往父节点转移即可。
写一个启发式合并不就完了嘛。(暴力神器)
时间复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n) 。
#include<bits/stdc++.h>
#define db double
#define ll long long
#define mkp make_pair
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define fi first
#define se second
using namespace std;
const int mod=1e9+7;
const int Maxn=1e5+5;
inline int read() {
int x=0,f=1; char c=getchar();
while(c<'0'||c>'9') {
c=getchar();
}
while(c>='0'&&c<='9') {
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
return x;
}
int n,id[Maxn],dp[Maxn];
vector<int> g[Maxn];
priority_queue<int> q[Maxn];
void merge(int x,int y) {
int tx=id[x],ty=id[y];
if(q[tx].size()>q[ty].size()) {
swap(tx,ty);
swap(x,y);
}
while(q[tx].size()) {
q[ty].push(q[tx].top());
q[tx].pop();
}
id[x]=id[y];
}
void dfs(int x,int fa) {
for(auto y:g[x]) {
if(y==fa) continue;
dfs(y,x);
merge(x,y);
}
int du=2;
dp[x]=1;
while(du&&q[id[x]].size()) {
dp[x]+=q[id[x]].top();
q[id[x]].pop();
du--;
}
q[id[x]].push(dp[x]);
}
int main() {
// freopen("tree2.in","r",stdin);
int T=read();
while(T--) {
n=read();
for(int i=1;i<=n;i++) {
g[i].clear();
while(q[i].size()) q[i].pop();
id[i]=i;
}
for(int i=1;i<n;i++) {
int u=read(),v=read();
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
printf("%d\n",dp[1]);
}
}