题目链接
A-大吉大利
做法:按位运算即可,统计每位为1的个数,个数为奇数个,该位贡献答案,然后往前进位。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=2e5+10;
ll a[N],n;
int main()
{
cin>>n;
rep(i,1,n) scanf("%lld",&a[i]);
ll pre=0,num=0;
ll ans=0;
for(ll j=0;j<=60;++j){
num=0;
rep(i,1,n)
{
if((a[i]>>j)&1ll)num++;
}
ll s=num*num;
s+=pre;
if(s%2) ans+=(1ll<<j);
pre=s/2;
}
cout<<ans;
}
B-三角形周长和
做法:枚举两个点,求其他点到这两个点的曼哈顿距离即可,x和y分别排序,用个前缀和就可以实现O(1)求了。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e3+10;
const ll mod=998244353;
ll x[N],y[N],n,pre[N],ans;
void cal(ll x[])
{
// rep(i,1,n)
// {
// printf("i:%d x:%lld\n",i,x[i]);
// }
//sort(x+1,x+1+n);
rep(i,1,n) pre[i]=(pre[i-1]+x[i]);
rep(i,1,n)
for(int j=i+1;j<=n-1;++j){
ans+=(pre[n]-pre[j]-(n-j)*x[i])%mod;
ans+=mod;
ans+=(pre[n]-pre[j]-(n-j)*x[j])%mod;
ans%=mod;
ans+=(n-j)*(x[j]-x[i]);
ans%=mod;
}
}
int main()
{
cin>>n;
rep(i,1,n)
{
scanf("%lld%lld",&x[i],&y[i]);
x[i]+=1e9+10,y[i]+=1e9+10;
}
sort(x+1,x+1+n);
sort(y+1,y+1+n);
cal(x);
cal(y);
cout<<ans<<endl;
}
C-操作集锦
求本质不同的子序列
思路:设前i个数字的子序列数为f(i)。
1.如果第i个数字在前i个数字里都没有出现过,那么,原来i-1个数字里面的子序列也是前i个数字的子序列,总共是f(i-1),而在原来i-1个数字的子序列每个的背后加一个a[i]也是新的子序列,总共是f(i-1)个,然后最后一个数字单独也可以组成一个新的子序列,是1个,因此这时f(i)=f(i)+f(i)+1。
2.如果第i歌数字在前面i个数字里面出现过,那么f(i)=f(i)+f(i)-f(a[i]最后一次出现的位置-1)。因为这时候,单独一个a[i]的情况已经被计算过,于是没有了+1,而往a[i]最后一次出现的位置-1加上一个a[i]的情况也已经被计算过,一次要减掉。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e3+10;
const ll mod=1e9+7;
char s[N];
int n,m;
ll dp[N][N],vis[30],last[N];
void add(ll &x,ll y)
{
x=(x+y)%mod;
}
int get(char c)
{
return c-'a';
}
int main()
{
cin>>n>>m>>s+1;
if(m==0){
printf("1");
return 0;
}
//rep(i,1,n) dp[1][s[i]-'a'
for(int i=1;i<=n;++i){
int id=get(s[i]);
for(int j=1;j<=m&&j<=n;++j){
add(dp[i][j],dp[i-1][j]);
}
for(int j=1;j<=m&&j<=n;++j){
add(dp[i][j+1],dp[i-1][j]);
}
if(last[id]==0) add(dp[i][1],1);
else{
for(int j=2;j<=m&&j<=n;++j){
dp[i][j]=(dp[i][j]-dp[last[id]-1][j-1]+mod)%mod;
}
}
last[id]=i;
}
//ll ans=0;
//rep(i,1,n) printf("i:%d %lld\n",i,dp[i][2]);
cout<<dp[n][m]<<endl;
}
/*
4 2
abab
5 2
abcc
5 3
abccc
*/
D-斩杀线计算大师
做法:参考来自:传送门
exgcd不了解?
学习 exgcd 参考博客:传送门
简单易懂
#include<bits/stdc++.h> using namespace std; #define ll long long const int mod=998244353; ll exgcd(ll a,ll b,ll &x,ll &y){ if(b==0){x=1;y=0; return a; } ll r=exgcd(b,a%b,x,y); ll temp=x; x=y; y=temp-(a/b)*y; return r; } ll gcd(ll a,ll b){ if(a%b==0)return b; return gcd(b,a%b); } int main(){ ll t,i,j,n,k,m=0,a,b,c; cin>>a>>b>>c>>k; ll g=gcd(b,c); for(i=0;i<k/a;i++){ if((k-a*i)%g!=0)continue; ll x,y; ll cc=exgcd(b,c,x,y); t=(k-a*i)/cc;//乘上t才是目前 b,c的其中一个解 ll x1=x*t,y1=y*t,c1=c/g; //printf("x1:%lld y1:%lld\n",x1,y1); x1=(x1%c1+c1)%c1;//最小正整数解,类似于取模 模数为c1 y1=(k-a*i-b*x1)/c; if(x1<0||y1<0)continue; cout<<i<<" "<<x1<<" "<<y1; break; } }
E-旗鼓相当的对手
做法:启发式合并一下,mp[u][x]为u这个节点深度为x的节点权值之和,num[u][x]为u这个节点深度为x的节点个数。
这里我少了步骤,就是判断u和v的大小,然后swap一下,是数据水了,
赛后我多加了一个数组dep[i]代表偏移量,记录i节点往上走的时候的偏移量,实现真正的启发式合并:第二份代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=2e5+10;
int n,k,a[N];
vector<int>G[N];
map<int,ll>mp[N],num[N];
ll ans[N];
void dfs(int u,int f)
{
for(int v:G[u])
{
if(v==f) continue;
dfs(v,u);
ll val=0;
for(auto x:mp[v]){
int d=k-x.first-1;
if(d<=0) continue;
if(mp[u][d]==0) continue;
val+=num[u][d]*mp[v][x.first];
val+=num[v][x.first]*mp[u][d];
}
for(auto x:mp[v]){
mp[u][x.first+1]+=x.second;
num[u][x.first+1]+=num[v][x.first];
}
ans[u]+=val;
}
num[u][0]++;
mp[u][0]+=a[u];
}
int main()
{
cin>>n>>k;
rep(i,1,n) scanf("%d",&a[i]);
rep(i,2,n)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,1);
rep(i,1,n)
printf("%lld ",ans[i]);
}
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=2e5+10;
int n,k,a[N];
vector<int>G[N];
map<int,ll>mp[N],num[N];
ll ans[N],dep[N];
void dfs(int u,int f)
{
for(int v:G[u])
{
if(v==f) continue;
dfs(v,u);
ll val=0;
dep[v]++;
if(mp[u].size()<mp[v].size())
{
swap(mp[u],mp[v]);
swap(num[u],num[v]);
swap(dep[u],dep[v]);
}
for(auto x:mp[v]){
int d=k-(x.first+dep[v])-dep[u];
if(mp[u][d]==0) continue;
val+=num[u][d]*mp[v][x.first];
val+=num[v][x.first]*mp[u][d];
}
for(auto x:mp[v]){
mp[u][x.first+dep[v]-dep[u]]+=x.second;
num[u][x.first+dep[v]-dep[u]]+=num[v][x.first];
}
ans[u]+=val;
}
num[u][-dep[u]]++;
mp[u][-dep[u]]+=a[u];
}
int main()
{
cin>>n>>k;
rep(i,1,n) scanf("%d",&a[i]);
rep(i,2,n)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,1);
rep(i,1,n)
printf("%lld ",ans[i]);
}