https://codeforc.es/contest/1443/problem/E
观察q是1e5,x是1e5,所以最多后移15位,所以我们暴力模拟这个进位过程以及修改前缀和即可,老实说代码挺难写的.代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+5;
ll fac[20];
ll sum[N];
bool vis[N];
int main()
{
int n,m;//个数 操作
scanf("%d%d",&n,&m);
for(ll i=1;i<=n;i++) sum[i]+=sum[i-1]+i;
fac[0]=1;
for(ll i=1;i<=15;i++) fac[i]=fac[i-1]*i;
int st=max(1,n-14);
ll cnt=1,now=1;//初始位子为1.
for(int i=1;i<=m;i++)
{
int l,r,x,op;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&l,&r);
printf("%lld\n",sum[r]-sum[l-1]);
}
else
{
scanf("%d",&x);cnt+=x;
now=cnt;
for(int i=st;i<=n;i++) vis[i]=false;
for(int i=st;i<=n;i++)
{
ll temp=0;
for(int j=st;j<=n;j++)
{
if(!vis[j])
{
temp+=fac[n-i];
if(temp>=now)
{
now-=(temp-fac[n-i]);
sum[i]=sum[i-1]+j;
vis[j]=true;
break;
}
}
}
}
}
}
return 0;
}
https://codeforc.es/contest/1445/problem/E
题目是给你n个人.m组关系.以及k组,要你在k组中任选两组构成二分图.问你方案数?
一个dsu即可解决的图论问题,当你不懂这个的时候,确实会觉得挺难的,注释一下可撤销并查集只是为了初始化而已...思路是这样的:先处理组内不能构成二分图的,然后再处理每条边(都是可能不能组成二分图的),再拿答案-它即可.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+51;
int c[N];
bool ok[N];//判断这组是不是有用.
struct node{
int n1;//a
int n2;//b
int c1;//min(c[a],c[b])
int c2;//max(c[a],c[b])
ll val;//存信息的.
}v[N];
int fa[N<<1],n;
stack<pair<int,int> >roll;//第一维存现在的信息,第二维存父亲信息.
bool cmp(node a,node b)
{
return a.val<b.val;
}
ll find(int x)
{
int r=x;ll cnt=0;//cnt记录路径奇偶性.
while(fa[r]!=r)
{
r=fa[r],cnt++;
}
ll ans=cnt*N+r;
if(cnt%2==0) x=fa[x],--cnt;
while(cnt>16)
{
int i=fa[x];
fa[x]=r;
x=fa[i];
cnt-=2;
}//奇数直接连根.偶数缩点.
return ans;
}
bool join(int a,int b)//假如有奇数环就无法加入.
{
ll fx=find(a),fy=find(b);
int ra=fx%N,rb=fy%N;
int la=fx/N,lb=fy/N;
if(ra==rb)
{
return (la+lb)%2==1;
}
else
{
roll.push(pair<int,int>(ra,fa[ra]));
if((la+lb)%2)
{
fa[ra]=++n,fa[n]=rb;
}
else fa[ra]=rb;
return true;
}
}
void roll_back()
{
while(roll.size())
{
pair<int,int>pr=roll.top();
roll.pop();
fa[pr.first]=pr.second;
}
}
int main()
{
int m,id=0;ll k;
scanf("%d%d%lld",&n,&m,&k);
for(int i=1;i<=N*2-4;i++) fa[i]=i;
for(int i=1;i<=n;i++) scanf("%d",c+i);
//for(int i=1;i<=m;i++) scanf("%d%d",a+i,b+i);
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
if(c[a]==c[b])//在同一组的.
{
if(!join(a,b)&&!ok[c[a]])
{
k--;
ok[c[a]]=1;
}
}
else//在不同组的.
{
v[id].n1=a;
v[id].n2=b;
v[id].c1=min(c[a],c[b]);
v[id].c2=max(c[a],c[b]);
v[id].val=1ll*v[id].c1*N+v[id].c2;
id++;
}
}ll ans=k*(k-1)/2;
while(!roll.empty())roll.pop();
sort(v,v+id,cmp);
bool flag=false;//false代表两个组可能组成二分图.
for(int i=0;i<id;i++)
{
int a=v[i].n1;int b=v[i].n2;
if(ok[c[a]]||ok[c[b]]) continue;
if(i>0&&v[i].val!=v[i-1].val)
{
flag=0;
roll_back();
}
if(!join(a,b))
{
if(!flag) ans--;
flag=1;
}
}
printf("%lld\n",ans);
return 0;
}
/*
5 5 2
1 2 1 2 1
1 2
2 3
3 4
4 5
5 1
0
*/
300ms可过...

京公网安备 11010502036488号