A
//考虑计算最后四位 momo 的方案数,有一个状态数 n*62*62 的 dp,但是每次有用的只有 n*62 个,暴力转移即可
//前面的方案容斥一下就好了
#include <bits/stdc++.h>
using namespace std;
const int N=1000005;
const int Mod=998244353;
char s[N];int a[N];
int f[65][65][3];
int pre[N][65],suf[65];
int to(char x){
if (x>='0'&&x<='9') return x-'0';
if (x>='a'&&x<='z') return 10+x-'a';
return 36+x-'A';
}
void add(int&x,int y){
x=(x+y<Mod?x+y:x+y-Mod);
}
int main() {
scanf ("%s",s+1);int n=strlen(s+1);
for (int i=1;i<=n;i++) a[i]=to(s[i]);
for (int i=1;i<=n;i++){
for (int j=0;j<62;j++) pre[i][j]=pre[i-1][j];
pre[i][a[i]]++;
}
int ans=0;
for (int i=n;i>=1;i--){
int x=a[i],y;
for (y=0;y<62;y++)
if (x!=y){
add(f[x][y][0],f[y][x][1]);
add(f[x][y][1],f[y][x][2]);
add(f[x][y][2],suf[y]);
}
int tot=1ll*(i-1)*(i-2)/2ll%Mod;
for (int j=0;j<62;j++) add(tot,Mod-1ll*pre[i-1][j]*(pre[i-1][j]-1)/2%Mod);
for (y=0;y<62;y++){
int tmp=f[x][y][0];f[x][y][0]=0;
int dif=(1ll*(i-1-pre[i-1][x])*pre[i-1][x]%Mod+1ll*(i-1-pre[i-1][y])*pre[i-1][y]%Mod)%Mod;
dif=(dif+Mod-1ll*pre[i-1][x]*pre[i-1][y]%Mod)%Mod;
dif=(tot-dif+Mod)%Mod;
add(ans,1ll*tmp*dif%Mod);
}
suf[a[i]]++;
}
printf ("%d",ans);
return 0;
}
B
/*
离线,考虑一个矩形如果在时刻 t 内部出现了被删掉的点,那么它的贡献是前缀 [1,t-1]
所以只需要计算有多少个矩形在时刻 t 被删掉,然后做前缀和就是答案
那么枚举上下行边界,计算每个列最小值出现次数,这是经典问题,对左右维护能延申的单调栈
时间复杂度 O(n^2m)
*/
#include <bits/stdc++.h>
using namespace std;
const int N=505;
int a[N][N],mn[N],L[N],R[N],s[N],top=0;
long long ans[N*N];
int main() {
freopen ("a.in","r",stdin);
int n,m;scanf ("%d%d",&n,&m);
for (int i=1;i<=n*m;i++){
int x,y;scanf ("%d%d",&x,&y);
a[x][y]=i;
}
for (int i=1;i<=n;i++){
memset (mn,0x3f,sizeof(mn));
for (int j=i;j<=n;j++){
for (int k=1;k<=m;k++) L[k]=1,R[k]=m,mn[k]=min(mn[k],a[j][k]);
top=0;
for (int k=1;k<=m;k++) {
while (top&&mn[s[top]]>mn[k]) R[s[top--]]=k-1;
s[++top]=k;
}
top=0;
for (int k=m;k>=1;k--) {
while (top&&mn[s[top]]>mn[k]) L[s[top--]]=k+1;
s[++top]=k;
}
for (int k=1;k<=m;k++) ans[mn[k]-1]+=1ll*(k-L[k]+1)*(R[k]-k+1);
}
}
for (int i=n*m-1;i>=0;i--) ans[i]+=ans[i+1];
for (int i=1;i<=n*m;i++) printf ("%lld\n",ans[i]);
return 0;
}
C
/*
我们可以确定每个随机的结果是什么
预处理 now[i][j] 表示第 i 次操作时,第 j 位是原种子哪些位 0/1 异或起来的结果
显然,若一个模数的后 x 位都是 0,那么取模的结果在二进制下就是原数后面的那些位
这样对于所有为 2,4,8,16... 倍数的模数,可以确定一些方程,这样方程的个数在 n=50 时共有 47 个
使用线性基维护这些方程,暴力枚举自由元,直接 check 即可
这样看上去是 2^17*n 的,但是实际上如果不是那个种子,check 几项就会出现问题,远远达不到 n 的复杂度
*/
#include <bits/stdc++.h>
using namespace std;
const int N=100005;
#define ll unsigned long long
int n;
void Rand(ll&x){x^=x<<13;x^=x>>7;x^=x<<17;}
int a[N],p[N];
int val[N];
bool check(ll x){
for (int i=1;i<=n;i++){
Rand(x);
if (x%i!=val[i]) return false;
}
return true;
}
bitset <64> bit[64];
bool ans[64];
void dfs(int x){
if (x==64){
ll v=0;for (int i=0;i<64;i++) v|=(1ull<<i)*ans[i];
if (check(v)) {cout<<v;exit(0);}
return;
}
if (bit[x][x]) {
bitset <64> st=bit[x];bool f=ans[x];
for (int i=x-1;i>=0;i--)
if (bit[x][i]) bit[x]^=bit[i],ans[x]^=ans[i];
dfs(x+1);bit[x]=st,ans[x]=f;
}else{
bit[x][x]=1;
ans[x]=1;
dfs(x+1);
ans[x]=0;
dfs(x+1);
bit[x][x]=0;
}
}
void insert(bitset <64> now,bool v){
for (int i=63;i>=0;i--)
if (now[i]){
if (!bit[i][i]) {bit[i]=now,ans[i]=v;break;}
else now^=bit[i],v^=ans[i];
}
}
bitset <64> now[64];
int main() {
freopen ("a.in","r",stdin);
// freopen ("a.out","w",stdout);
scanf ("%d",&n);
for (int i=1;i<=n;i++){
scanf ("%d",&a[i]);
p[a[i]]=i;
}
for (int i=n;i>=1;i--){
val[i]=p[i];
p[a[i]]=p[i];
swap(a[i],a[p[i]]);
}val[1]=1;
for (int i=1;i<=n;i++) val[i]--;
for (int i=0;i<64;i++) now[i][i]=1;
for (int i=1;i<=n;i++){
for (int j=63;j>=13;j--) now[j]^=now[j-13];
for (int j=0;j<=63-7;j++) now[j]^=now[j+7];
for (int j=63;j>=17;j--) now[j]^=now[j-17];
if (i&1) continue;
for (int t=0;;t++){
insert(now[t],(val[i]>>t)&1);
if (i&(1<<(t+1))) break;
}
}
dfs(0);
return 0;
}
D
//枚举两条路径的交集,三分分配权值
#include <bits/stdc++.h>
using namespace std;
const int N=5005;
int Head[N],Next[N<<1],Adj[N<<1],tot=0;
void addedge(int u,int v){
Next[++tot]=Head[u],Head[u]=tot,Adj[tot]=v;
Next[++tot]=Head[v],Head[v]=tot,Adj[tot]=u;
}
queue <int> Q;
int dis[N][N];
const int INF=10000;
void bfs(int x){
Q.push(x);dis[x][x]=0;
while (!Q.empty()){
int t=Q.front();Q.pop();
for (int e=Head[t];e;e=Next[e])
if (dis[x][Adj[e]]==INF)
dis[x][Adj[e]]=dis[x][t]+1,Q.push(Adj[e]);
}
}
int n,m,k;
double check(int d1,int d2,int x,int y){
double sum=0;
if (d1){
int p1=1+x/d1,c1=x%d1;
sum+=1.0*((d1-c1)*1.0/p1+c1*1.0/(p1+1));
}else sum+=d1;
if (d2){
int p2=1+y/d2,c2=y%d2;
sum+=2.0*((d2-c2)*1.0/p2+c2*1.0/(p2+1));
}else sum+=d2;
return sum;
}
double calc(int x,int y){
int l=0,r=k;
while ((r-l)>=6){
int m1=(l+(r-l)/3),m2=(r-(r-l)/3);
if (check(x,y,m1,k-m1)<check(x,y,m2,k-m2)) r=m2;
else l=m1;
}
double ans=1e9;
for (int i=l;i<=r;i++) ans=min(ans,check(x,y,i,k-i));
return ans;
}
int Min[N];
int main (){
scanf ("%d%d%d",&n,&m,&k);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
dis[i][j]=10000;
for (int i=1;i<=m;i++){
int u,v;scanf ("%d%d",&u,&v);
addedge(u,v);
}int s1,t1,s2,t2;
scanf ("%d%d%d%d",&s1,&t1,&s2,&t2);
for (int i=1;i<=n;i++) bfs(i);
double ans=calc(dis[s1][t1]+dis[s2][t2],0);
memset (Min,0x3f,sizeof(Min));
for (int s=1;s<=n;s++)
for (int t=s+1;t<=n;t++){
int d=dis[s1][s]+dis[t][t1]+dis[s2][s]+dis[t][t2];
d=min(dis[s1][t]+dis[s][t1]+dis[s2][t]+dis[s][t2],d);
d=min(dis[s1][s]+dis[t][t1]+dis[s2][t]+dis[s][t2],d);
d=min(dis[s1][t]+dis[s][t1]+dis[s2][s]+dis[t][t2],d);
Min[dis[s][t]]=min(Min[dis[s][t]],d);
}
for (int i=0;i<=n;i++)
if (Min[i]!=Min[n+1]) ans=min(ans,calc(Min[i],i));
printf ("%.12f",ans);
return 0;
}
E
坑
F
#include <bits/stdc++.h>
using namespace std;
const int N=4e5+5;
struct Node{
int x,y,id;
}a[N];
bool cmp1(Node a,Node b){
return a.x==b.x?a.y<b.y:a.x<b.x;
}
bool cmp2(Node a,Node b){
return a.y==b.y?a.x<b.x:a.y<b.y;
}
bool ans1[N],ans2[N];
bool sgn(int x){return x<0?0:1;}
int main(){
freopen ("a.in","r",stdin);
int n,m;scanf ("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf ("%d%d",&a[i].x,&a[i].y),a[i].id=i;
for (int i=1;i<=m;i++) scanf ("%d%d",&a[n+i].x,&a[n+i].y),a[n+i].id=-i;
sort(a+1,a+n+m+1,cmp1);
for (int i=2;i<=n+m;i++)
if (a[i-1].x==a[i].x&&sgn(a[i-1].id)!=sgn(a[i].id)) {
if (a[i-1].id<0) ans2[-a[i-1].id]=true;else ans1[a[i-1].id]=true;
if (a[i].id<0) ans2[-a[i].id]=true;else ans1[a[i].id]=true;
}
sort(a+1,a+n+m+1,cmp2);
for (int i=2;i<=n+m;i++)
if (a[i-1].y==a[i].y&&sgn(a[i-1].id)!=sgn(a[i].id)) {
if (a[i-1].id<0) ans2[-a[i-1].id]=true;else ans1[a[i-1].id]=true;
if (a[i].id<0) ans2[-a[i].id]=true;else ans1[a[i].id]=true;
}
for (int i=1;i<=n;i++) putchar(ans1[i]+'0');puts("");
for (int i=1;i<=m;i++) putchar(ans2[i]+'0');
return 0;
}
G
/*
对每个加进来的 i 考虑, 从上一个 a_i 出现的位置开始产生一段为 1 的贡献
考虑扫描线右端点,对左端点维护线段树
模 2 意义下相当于区间反转,查询所有子区间的答案相当于历史和,线段树维护即可
*/
#include <bits/stdc++.h>
using namespace std;
const int N=500005;
struct Node{
bool rev;
int c0,c1;
int tg0,tg1;
long long sum;
}t[N<<2];
#define mid ((l+r)>>1)
void pushup(int root){
t[root].c0=t[root<<1].c0+t[(root<<1)|1].c0;
t[root].c1=t[root<<1].c1+t[(root<<1)|1].c1;
t[root].sum=t[root<<1].sum+t[(root<<1)|1].sum;
}
void pushdown(int root){
if (t[root].rev){
swap(t[root<<1].c0,t[root<<1].c1);
swap(t[(root<<1)|1].c0,t[(root<<1)|1].c1);
swap(t[root<<1].tg0,t[root<<1].tg1);
swap(t[(root<<1)|1].tg0,t[(root<<1)|1].tg1);
t[root<<1].rev^=1;
t[(root<<1)|1].rev^=1;
t[root].rev=0;
}
if (t[root].tg0){
t[root<<1].tg0+=t[root].tg0;
t[(root<<1)|1].tg0+=t[root].tg0;
t[root<<1].sum+=1ll*t[root<<1].c0*t[root].tg0;
t[(root<<1)|1].sum+=1ll*t[(root<<1)|1].c0*t[root].tg0;
t[root].tg0=0;
}
if (t[root].tg1){
t[root<<1].tg1+=t[root].tg1;
t[(root<<1)|1].tg1+=t[root].tg1;
t[root<<1].sum+=1ll*t[root<<1].c1*t[root].tg1;
t[(root<<1)|1].sum+=1ll*t[(root<<1)|1].c1*t[root].tg1;
t[root].tg1=0;
}
}
void update(int root,int l,int r,int L,int R){
if (r<L||l>R) return;
if (L<=l&&r<=R) {
t[root].rev^=1;
swap(t[root].c0,t[root].c1);
swap(t[root].tg0,t[root].tg1);
return;
}
pushdown(root);
update(root<<1,l,mid,L,R);
update((root<<1)|1,mid+1,r,L,R);
pushup(root);
}
long long query(int root,int l,int r,int L,int R){
if (r<L||l>R) return 0;
if (L<=l&&r<=R) return t[root].sum;
pushdown(root);
return query(root<<1,l,mid,L,R)+query((root<<1)|1,mid+1,r,L,R);
}
void build(int root,int l,int r){
if (l==r) {t[root].c0=1;return;}
build(root<<1,l,mid);
build((root<<1)|1,mid+1,r);
pushup(root);
}
#undef mid
int a[N],lst[N];
long long ans[N];
struct Query{
int l,r,id;
}q[N];
bool cmp(Query a,Query b){
return a.r<b.r;
}
int main() {
int n;scanf ("%d",&n);
for (int i=1;i<=n;i++) scanf ("%d",&a[i]);
int m;scanf ("%d",&m);
for (int i=1;i<=m;i++){
scanf ("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
build(1,1,n);
int now=1;
for (int i=1;i<=m;i++){
while (now<=q[i].r){
update(1,1,n,lst[a[now]]+1,now);
t[1].sum+=t[1].c1;
t[1].tg1++;
lst[a[now]]=now;
now++;
}
ans[q[i].id]=query(1,1,n,q[i].l,q[i].r);
}
for (int i=1;i<=m;i++) printf ("%lld\n",ans[i]);
return 0;
}
H
坑
I
坑
J
坑
K
/*
还有四张牌未知,对方只要选一张连起来,就能抽出顺子,所以只能用顺子打败他
那么枚举对方手上的顺子是什么,判断是否合法即可
*/
#include <bits/stdc++.h>
using namespace std;
const int N=15;
int c[4][N];
char s[5][2];
int main() {
int T;scanf ("%d",&T);
while (T--){
memset (c,0,sizeof(c));
cin>>s[0]>>s[1]>>s[2]>>s[3]>>s[4];
for (int i=0;i<5;i++){
int t=0;
if (s[i][0]=='T') t=10;
else if (s[i][0]=='J') t=11;
else if (s[i][0]=='Q') t=12;
else if (s[i][0]=='K') t=13;
else if (s[i][0]=='A') t=14;
else t=s[i][0]-'0';
int p=(s[i][1]=='C'?0:(s[i][1]=='D'?1:(s[i][1]=='H'?2:3)));
c[p][t]=1;
}
int flag=-1;
for (int i=0;i<4;i++){
if (c[i][14]&&c[i][2]&&c[i][3]&&c[i][4]&&c[i][5]) {flag=5;break;}
for (int j=2;j+4<=14;j++)
if (c[i][j]&&c[i][j+1]&&c[i][j+2]&&c[i][j+3]&&c[i][j+4]){
flag=j+4;break;
}
if (flag!=-1) break;
}
if (flag==-1) {puts("check");continue;}
for (int i=0;i<2;i++){
int t=0;
if (s[i][0]=='T') t=10;
else if (s[i][0]=='J') t=11;
else if (s[i][0]=='Q') t=12;
else if (s[i][0]=='K') t=13;
else if (s[i][0]=='A') t=14;
else t=s[i][0]-'0';
int p=(s[i][1]=='C'?0:(s[i][1]=='D'?1:(s[i][1]=='H'?2:3)));
c[p][t]=-10;
}
for (int i=0;i<4;i++){
for (int j=2;j+4<=14;j++)
if (c[i][j]+c[i][j+1]+c[i][j+2]+c[i][j+3]+c[i][j+4]>=1)
if (j+4>flag){flag=-1;break;}
if (flag==-1) break;
}
if (flag==-1) puts("check");
else puts("allin");
}
return 0;
}
L
#include <bits/stdc++.h>
using namespace std;
const int N=1000005;
int p[N],tot=0;bool notp[N];
void getp(){
for (int i=2;i<=1000;i++){
if (!notp[i]) p[++tot]=i;
for (int j=1;p[j]*p[j]<=1000&&j<=tot;j++){
notp[i*p[j]]=true;
if (i%p[j]==0) break;
}
}
}
const int Mod=1e9+7;
inline int qpow(int a,int b){
int ans=1;
while (b){
if (b&1) ans=1ll*ans*a%Mod;
a=1ll*a*a%Mod,b>>=1;
}
return ans;
}
int val[N];
int main(){
getp();
int n;scanf ("%d",&n);
for (int i=1;i<=n;i++){
int x;scanf ("%d",&x);
for (int j=1;p[j]*p[j]<=x&&j<=tot;j++){
if (x%p[j]==0) {
int c=0;
while (x%p[j]==0) x/=p[j],c++;
val[p[j]]+=(c&1);
}
}
val[x]++;
}int ans=1;
for (int i=2;i<=1000000;i++) ans=1ll*ans*qpow(i,min(val[i],n-val[i]))%Mod;
printf ("%d",ans);
return 0;
}