目录
A.迷宫
相当于若干条链合并成一条长链,合并的时候如果有冲突放在后面的空位上。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
struct Edge{
int v,nxt;
Edge(int v=0,int nxt=0):v(v),nxt(nxt){}
}e[N*2];
int p[N],edn,n;
void add(int u,int v){
e[++edn]=Edge(v,p[u]);p[u]=edn;
e[++edn]=Edge(u,p[v]);p[v]=edn;
}
int d[N];
int dfs(int u,int f,int de){
d[u]=de;
for(int i=p[u];~i;i=e[i].nxt){
int v=e[i].v;
if(v==f) continue;
dfs(v,u,de+1);
}
}
int cnt[N],a[N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int u,v;
memset(p,-1,sizeof(p));edn=-1;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);
}
dfs(1,-1,0);
for(int i=1;i<=n;i++){
if(a[i]) cnt[d[i]]++;
}
int ans=0;
for(int i=1;i<=n;i++){
if(cnt[i]){
if(i>ans) ans=i-1;
ans+=cnt[i];
}
}
printf("%d\n",ans);
}
C.斐波那契数列
Fib(n)&(Fib(n)-1)=Fib(n)-lowbit(n),所以原式等于.
斐波那契前n项和为,所以前者可以用矩阵快速幂来计算。
根据洪华敦老师的结论:
- 只有n是3的倍数时,F[n]才是偶数
- 当n=3k时,若k是奇数,则lowbit(F[n])=2,否则lowbit(F[n])=lowbit(4k)
所以我们只需要计算n为6的倍数的情况,也就是要算出,这可以通过枚举二进制位来计算。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e3+7;
const ll mod=998244353;
void mul(ll a[2][2],ll b[2][2]){
ll c[2][2];
for(ll i=0;i<2;i++){
for(ll j=0;j<2;j++){
c[i][j]=0;
for(ll k=0;k<2;k++){
c[i][j]=(c[i][j]+a[i][k]*b[k][j]%mod)%mod;
}
}
}
memcpy(a,c,sizeof(c));
}
void qpow(ll a[2][2],ll p[2][2],ll b){
while(b){
if(b&1) mul(a,p);
mul(p,p);b>>=1;
}
}
ll solve(ll x){
ll res=0;
for(ll i=0;(1ll<<i)<=x;i++){
if(x&(1ll<<i)) res=(res+((x>>(i+1))+1)*(1ll<<i))%mod;
else res=(res+(x>>(i+1))*(1ll<<i))%mod;
}
return res;
}
ll de[6]={0,1,2,4,5,6};
int main()
{
int t;
scanf("%d",&t);
while(t--){
ll n;
scanf("%lld",&n);
ll a[2][2]={1,1,0,0};
ll p[2][2]={0,1,1,1};
qpow(a,p,n+1);
ll ans=(a[0][0]-1+mod)%mod;
ll tmp=n/6;
ans=(ans-tmp*6%mod+mod)%mod;
ans=(ans-8*solve(tmp)+mod)%mod;
ans=(ans-de[n%6]+mod)%mod;
printf("%lld\n",ans);
}
}
E.线性探查法
按照题意建树,然后拓扑排序。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+7;
int b[N],n;
int p[N],edn;
int d[N];
struct Edge{
int v,nxt;
Edge(int v=0,int nxt=0):v(v),nxt(nxt){}
}e[N*N];
void add(int u,int v){
e[++edn]=Edge(v,p[u]);p[u]=edn;
}
struct Node{
int id,val;
Node(int id,int val):id(id),val(val){}
bool operator<(const Node x)const{
return val>x.val;
}
};
priority_queue<Node>q;
int tot;
int tmp[N];
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&b[i]);
}
memset(p,-1,sizeof(p));edn=-1;
for(int i=0;i<n;i++){
tot=0;
int st=i;
if((b[i]%n)!=i){
for(int j=(i+1)%n;j!=i;j=(j+1)%n){
if(b[j]%n==i){
st=j;break;
}
}
if(st==i) continue;
tmp[++tot]=st;
}
for(int j=(st+1)%n;j!=st;j=(j+1)%n){
if(b[j]%n==i) tmp[++tot]=j;
}
if(tot==0) continue;
int pos=1;
add(i,tmp[pos]);d[tmp[pos]]++;
for(int j=(i+1)%n;j!=i;j=(j+1)%n){
if(j!=tmp[pos]){
add(j,tmp[pos]);
d[tmp[pos]]++;
}
else{
pos++;j--;
if(pos>tot) break;
}
}
}
for(int i=0;i<n;i++){
if(d[i]==0) q.push(Node(i,b[i]));
}
bool fst=true;
while(!q.empty()){
Node t=q.top();q.pop();
if(fst) fst=false;
else printf(" ");
printf("%d",t.val);
for(int i=p[t.id];~i;i=e[i].nxt){
int v=e[i].v;
d[v]--;
if(d[v]==0) q.push(Node(v,b[v]));
}
}
printf("\n");
}
F.逆序对!
对于两个数字a和b,假设a和b二进制最高的不同位是第k位。当两者同时异或一个c,且c在第k位的值为1,则a和b异或c会改变两者的大小关系。
对于本题n^2枚举两个数a[i],a[j] (i < j),计算这两个数对答案的贡献。
- 如果a[i]<a[j],则必须异或一个第k位为1的值才有贡献
- 如果a[i]>a[j],则必须异或一个第k位为0的值才有贡献
第k位为1或0可以乘法O(1)来计算。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e3+7;
const ll mod=998244353;
ll b[N],c[50];
ll n,m;
ll solve(ll x,ll y){
bool xx,yy;
for(ll i=30;i>=0;i--){
if(x&(1<<i)) xx=true;
else xx=false;
if(y&(1<<i)) yy=true;
else yy=false;
if(xx!=yy) return i;
}
}
int main()
{
scanf("%lld%lld",&n,&m);
for(ll i=0;i<=30;i++){
c[i]=(1<<i)*(m>>(i+1))%mod;
if(m&(1<<i)) c[i]=(c[i]+(m&((1<<i)-1))+1)%mod;
}
ll ans=0;
for(ll i=1;i<=n;i++){
scanf("%lld",&b[i]);
for(ll j=1;j<i;j++){
ll p=solve(b[j],b[i]);
if(b[j]<b[i]) ans=(ans+c[p])%mod;
else ans=(ans+m-c[p]+mod)%mod;
}
}
printf("%lld\n",ans);
}
G.抢红包机器人
按照题意建树,枚举机器人暴力搜索,取最小值
#include<bits/stdc++.h>
using namespace std;
const int N=1e2+7;
int n,m,num;
int mp[N][N];
bool vis[N];
int tt[N];
int bfs(int s){
queue<int>q;
int res=1;
q.push(s);vis[s]=true;
while(!q.empty()){
int u=q.front();q.pop();
for(int v=1;v<=n;v++){
if(mp[u][v]&&!vis[v]){
q.push(v);res++;
vis[v]=true;
}
}
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d",&num);
for(int j=1;j<=num;j++){
scanf("%d",&tt[j]);
if(j!=1){
mp[tt[j]][tt[j-1]]=1;
}
}
}
int ans=n;
for(int i=1;i<=n;i++){
memset(vis,false,sizeof(vis));
ans=min(ans,bfs(i));
}
printf("%d\n",ans);
}