返回顶部

2019 icpc 南昌

7 / 50 A 9102 !!!

99 / 175 B A Funny Bipartite Graph !!!

爆搜跑的飞快,网络流原地爆炸

就是对右边点每个点选边进行爆搜,复杂度3^n,为什么不对左边爆搜呢,因为不好确定左边到底选多少条边,枚举又得乘个8,但是右边最优策略就是只选一条边,多选没有意义
代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=25;
int n;
char a1[maxn][maxn],g1[maxn][maxn],m[maxn],flag[maxn];
vector<int>e[maxn];
vector<int>edge[maxn];
int ans=1e9;
int d[maxn],vis[maxn];
int js(int x,int n)
{
    if(n==0) return 0;
    int ans=1;
    for(int i=1;i<=n;i++) ans*=m[x];
    return ans;
}
void dfs(int u,int s)
{
    if(s>=ans) return;
    if(u==n+1)
    {
        ans=s;
        return;
    }
    for(int v:e[u])
    {
        if(vis[v]==0)
        {
            d[v]++;
            for(int i:edge[v]) vis[i]++;
            dfs(u+1,s+js(v,d[v])-js(v,d[v]-1));
            for(int i:edge[v]) vis[i]--;
            d[v]--;
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0;i<=n+1;i++) e[i].clear(),edge[i].clear();
        memset(d,0,sizeof(d));ans=1e9;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
        {
            scanf("%s",a1[i]+1);
            for(int j=1;j<=n;j++)
            {
                if(a1[i][j]=='1')
                {
                    //edge[i].push_back(j);
                    e[j].push_back(i);
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%s",g1[i]+1);
            for(int j=1;j<=n;j++)
            {
                if(g1[i][j]=='1')
                {
                    edge[i].push_back(j);
                }
            }
        }
        for(int i=1;i<=n;i++) scanf("%d",&m[i]);
        dfs(1,0);
        if(ans==1e9) printf("-1\n");
        else printf("%d\n",ans);
    }
}

26 / 35 C And and Pair ---

89 / 293 D Bitwise Tree +++

24 / 113 E Bob's Problem ---

41 / 270 F Dynamic Suffix Array ???

17 / 58 G Eating Plan ---

H Powers of Two ???

1 / 17 I Resistance ???

2 / 5 J Summon ???

polya定理,如果没有限制的话,答案就是\(\frac{1}{n}\)\(\sum_{k=1}^{n}\)\(m^{gcd(n,k)}\),但是有限制的话就要考虑限制了,无限制的情况,本质是确定了前gcd(n,k)个数后,后面的数也都确定了,所以我们枚举gcd(n,k),然后我们建立矩阵,第i行第j列等于1代表可以由i到j转化,i位的后俩位和j位的第二三列是相同的(四进制情况下),矩阵的gcd(n,k)次幂后,每一位值的和就是gcd(n,k)对应的答案,详情看代码

#include<stdio.h>
#include<string.h>
const int N=64;
#define mod 998244353
#define ll long long
struct mt{
    int a[N][N];
    mt (){memset(a, 0, sizeof a);}
    void E(){for(int i = 0; i < N; ++i) a[i][i] = 1;}
    void F(){for(int i = 0; i < N; ++i) for(int j = 0; j < N; ++j) a[i][j] = 1;}
    mt operator * (mt x){
        mt ans;
        for(int i = 0; i < N; ++i){
            for(int k = 0; k < N; ++k){
                if(!a[i][k]) continue;
                for(int j = 0; j < N; ++j){
                    ans.a[i][j]+=(ll)a[i][k]*x.a[k][j]%mod;
                    ans.a[i][j] %= mod;
                }
            }
        }return ans;
    }
}base, pbase[20];
#define maxn 100100
int phi[maxn],vis1[maxn],vis2[maxn],prime[maxn];
void inite(){
	phi[1]=1;
	int cnt=0;
	for(int i=2;i<=100000;i++){
		if(vis1[i]==0){
			phi[i]=i-1;
			prime[++cnt]=i;
		}
		for(int j=1;j<=cnt&&i*prime[j]<=100000;j++){
			vis1[i*prime[j]]=1;
			if(i%prime[j]==0){
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			else{
				phi[i*prime[j]]=phi[i]*phi[prime[j]];
			}
		}
	}
	for(int i=0;i<64;i++){
		for(int j=0;j<4;j++){
			int now=(i*4+j)%64;
			base.a[i][now]=1;
		}
	}
}
mt quickpow(ll cnt){
	mt ans;
	ans.E();
	for(int i=0;;i++){
		if(cnt%2==1){
			ans=ans*pbase[i];
		}
		cnt=cnt/2;
		if(cnt==0)break;
	}
	return ans;
}

int get(int a,int b,int c,int d){
	return a*64+b*16+c*4+d;
}
ll quickpow(ll a,ll b){
	ll ans=1;
	while(b!=0){
		if(b%2==1)ans=(ans*a)%mod;
		a=a*a%mod;
		b=b/2;
	}
	return ans;
}
int main(){
	inite();
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++){
		int now=0;
		for(int j=1;j<=4;j++){
			int x;
			scanf("%d",&x);
			now=now*4+x;
		}
		vis2[now]=1;
		base.a[now/4][now%64]=0;
	}
	pbase[0]=base;
	for(int i=1;i<20;i++)pbase[i]=pbase[i-1]*pbase[i-1];
	ll ans=0;
	for(int i=0;i<4;i++){
		int now=0;
		for(int cnt=1;cnt<=4;cnt++){
			now=now*4+i;
		}
		if(vis2[now]==0)ans++;
	}
	ans=(ans*phi[n])%mod;
	if(n%2==0){
		ll temp=0;
		for(int i=0;i<4;i++){
			for(int j=0;j<4;j++){
				int now1=get(i,j,i,j);
				int now2=get(j,i,j,i);
				if(vis2[now1]==0&&vis2[now2]==0)temp++;
			}
		}
		ans=(ans+temp*phi[n/2])%mod;
	}
	for(int i=3;i<=n;i++){
		if(n%i!=0)continue;
		mt res;
		res.E();
		res=res*quickpow(i);
		ll temp=0;
		for(int j=0;j<64;j++)temp=(temp+res.a[j][j])%mod;
		temp=temp*phi[n/i]%mod;
		ans=(ans+temp)%mod;
	}
	ans=(ans*quickpow(n,mod-2))%mod;
	printf("%lld\n",ans);
}

101 / 283 K Tree !!!

40 / 101 L Who is the Champion ---

0 / 5 M XOR Sum ???

posted @ 2021-01-17 22:06  League-of-cryer  阅读(129)  评论(0)    收藏  举报