• ecfinal2020 部分题解


    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;
    }
    
  • 相关阅读:
    maven项目中各文件都没有报错,但是项目名称有红叉
    executeFind()方法和execute()方法区别
    数据库查询
    getHibernateTemplate出现的所有find方法的总结
    HQL和SQL的区别
    Java创建对象的方式
    xml中的<![CDATA[]]>和转义字符
    DWRUtil.addOptions
    dwr
    response.setHeader("Cache-Control","no-cache");的作用
  • 原文地址:https://www.cnblogs.com/ehuohz/p/15592196.html
Copyright © 2020-2023  润新知