2017 多校联合训练 2 题解

Problem 1002

这个Hash好难……其实要用到抽屉原理。

这道题当时做出的队伍很少。

我们取出1000*1000矩阵的所有8*8的矩阵,放到一个map里面。

然后我们去大矩阵里分块去找这些map里存过的东西……如果找到了那就有了答案。

也就是说根据原来map里存下的信息判断位置即可。

因为大矩阵是完全随机的,所以冲突概率很小。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define fi		first
#define se		second


typedef long long LL;
typedef pair <int, int> PII;

const int N = 1e3 + 10;

int T, flag, ca = 0;
char s[N][N];
unordered_map <LL, PII> mp;


inline unsigned sfr(unsigned h, unsigned x) {
	return h >> x;
}
int f(LL i, LL j) {
	LL w = i * 1000000ll + j;
	int h = 0;
	for(int k = 0; k < 5; ++k) {
		h += (int) ((w >> (8 * k)) & 255);
		h += (h << 10);
		h ^= sfr(h, 6);
	}
	h += h << 3;
	h ^= sfr(h, 11);
	h += h << 15;
	return sfr(h, 27) & 1;
}


int main(){

	scanf("%d", &T);
	while (T--){
		rep(i, 1, 1e3) scanf("%s", s[i] + 1);
		mp.clear();
		rep(i, 1, 992){
			rep(j, 1, 992){
				LL tmp = 0;
				rep(k, 0, 7){
					rep(l, 0, 7){
						tmp <<= 1;
						tmp |= (s[i + k][j + l] == '1');
					}
				}

				mp[tmp] = PII(i, j);
			}
		}

		flag = 1;
		for (int i = 1; i <= 1e6 && flag; i += 984){
			for (int j = 1; j <= 1e6 && flag; j += 984){
				LL tmp = 0;
				rep(k, 0, 7){
					rep(l, 0, 7){
						tmp <<= 1;
						tmp |=  f(i + k, j + l);
					}
				}

				if (mp.find(tmp) != mp.end()){
					PII ans = mp[tmp];
					flag = 0;
					printf("Case #%d :%d %d
", ++ca, i - ans.fi + 1, j - ans.se + 1);
				}
			}
		}
	}

	return 0;
}

Problem 1003

这道题其实很简单……

我们对b数组升序排序,显然要从前面开始取。

做的时候维护后缀最大值,那么就可以O(1)知道原a数列的要取的数了。

因为从前面开始取,这样之后生成的数也就越大,对整个局面肯定更有利。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)    for (int i(a); i <= (b); ++i)
#define dec(i, a, b)    for (int i(a); i >= (b); --i)

typedef long long LL;

const int N  = 250010;
const LL mod = 1e9 + 7;

int b[N], n;
LL a[N], c[N], d[N], ans;

int main(){

	while (~scanf("%d", &n)){
		rep(i, 1, n) scanf("%lld", a + i);
		rep(i, 1, n) scanf("%d", b + i);

		sort(b + 1, b + n + 1);
		ans = 0;

		rep(i, 1, n) c[i] = a[i] - (LL)i;
		d[n] = c[n];
		dec(i, n - 1, 1) d[i] = max(d[i + 1], c[i]);

		LL now = -1e10;

		rep(i, 1, n){
			LL cnt = max(d[b[i]], now);
			ans = (ans + cnt) % mod;
			now = max(now, cnt - i - n);
		}

		printf("%lld
", ans);


	}
	return 0;
}

Problem 1004

Problem 1005

Problem 1006

通过打表找规律 

发现当n为偶数时,答案为2*(4^((n+1)/2)-1)*(2^n-1)^(m-2)

当n为奇数时,较复杂,还要减去一个数,当然减去的那个数也有规律

最后快速幂+乘法逆元即可

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll n,m;
ll pow_mod(ll a,ll b)
{
    ll ans=1;
    while (b)
    {
        if (b&1) ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
int main()
{
    int _;
    scanf("%d",&_);
    while (_--)
    {
        scanf("%lld%lld",&n,&m);
        if (m==1)
        {
            puts("1");
            continue;
        }
        ll p=(n+1)/2;
        ll fs=pow_mod(4ll,p);
        fs=(fs-1+mod)%mod;
        fs=fs*pow_mod(3,mod-2)%mod;
        if (n%2==0) fs=(fs*2)%mod;
        //cout<<fs<<endl;
        if (m==2)
        {
            printf("%lld
",fs);
            continue;
        }
        ll g=(pow_mod(2ll,n)-1+mod)%mod;
        if (n&1)
        {
            p--;
            ll jian=pow_mod(4,p);
            jian=((jian-1)+mod)%mod;
            jian=jian*2%mod;
            jian=jian*pow_mod(3,mod-2)%mod;
            ll times=m-2;
            ll xx=(g-1+mod)%mod;
            ll yy=jian;
            ll nfs=(fs*xx-yy+mod)%mod;
            ll ans=nfs*pow_mod(g,times)%mod;
            ans=(ans+yy)%mod;
            ans=ans*pow_mod(xx,mod-2)%mod;
            printf("%lld
",ans);
        }
        else
        {
            ll times=m-2;
            ll ans=fs*pow_mod(g,times)%mod;
            printf("%lld
",ans);
        }
    }
    return 0;
}
View Code

Problem 1008

每个数先单独算出期望然后相加

这里设置数量为13为临界点

数量小于13的数用容斥做

数量大于13的数,用全部的矩阵个数减去全不含的矩阵个数

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
using namespace std;
int _,n,m;
int w[105][105],c[105][105];
int fg[10010],a[105],b[105];
vector<pair<int,int>> s[10010];
int calc(int x)
{
    int ans=0;
    int i,j;
    for (i=1;i<=n;i++)
    {
        int tmp,tot=0,sum=0;
        for (j=1;j<=m;j++)
        {
            if (w[i][j]!=x)
                c[i][j]=c[i-1][j]+1;
            else
                c[i][j]=0;
            tmp=1;
            while (tot&&a[tot]>=c[i][j])
            {
                tmp+=b[tot];
                sum-=a[tot]*b[tot];
                tot--;
            }
            tot++;
            a[tot]=c[i][j];
            b[tot]=tmp;
            sum+=a[tot]*b[tot];
            ans+=sum;
        }
    }
    return ans;
}
int calc2(int x)
{
    int siz=s[x].size();
    int tot=0;
    int i,j;
    for (i=1;i<(1<<siz);i++)
    {
        bool flag=false;
        int p1=n+500,p2=-1,p3=m+500,p4=-1;
        for (j=0;j<siz;j++)
        {
            if (i>>j&1)
            {
                flag=1-flag;
                p1=min(p1,s[x][j].first);
                p2=max(p2,s[x][j].first);
                p3=min(p3,s[x][j].second);
                p4=max(p4,s[x][j].second);
            }
        }
        if (flag)
            tot+=p1*(n-p2+1)*p3*(m-p4+1);
        else
            tot-=p1*(n-p2+1)*p3*(m-p4+1);
    }
    return tot;
}
int main()
{
    scanf("%d",&_);
    while (_--)
    {
        scanf("%d%d",&n,&m);
        int i,j;
        for (i=1;i<=n;i++)
            for (j=1;j<=m;j++)
                scanf("%d",&w[i][j]);
        int tot=0;
        memset(fg,0,sizeof(fg));
        for (i=1;i<=n;i++)
            for (j=1;j<=m;j++)
            {
                if (fg[w[i][j]]) continue;
                fg[w[i][j]]=++tot;
            }
        for (i=1;i<=tot;i++)
            s[i].clear();
        for (i=1;i<=n;i++)
            for (j=1;j<=m;j++)
            {
                w[i][j]=fg[w[i][j]];
                s[w[i][j]].push_back({i,j});
            }
        double ans=0;
        int zans=n*(n+1)*m*(m+1)/4;
        for (i=1;i<=tot;i++)
        {
            if (s[i].size()>13)
                ans+=(zans-calc(i))*1.0/zans;
            else
                ans+=calc2(i)*1.0/zans;
        }
        printf("%.9f
",ans);
    }
    return 0;
}
View Code

Problem 1009

令F[i]表示是i的倍数时的方案数

可通过处理前缀和

然后再通过莫比乌斯反演算出答案

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int inf=(1<<30)-1;
 4 const int maxn=100010;
 5 #define REP(i,n) for(int i=(0);i<(n);i++)
 6 #define FOR(i,j,n) for(int i=(j);i<=(n);i++)
 7 typedef long long ll;
 8 bool vis[maxn];  
 9 int p[maxn];  
10 int cnt;  
11 int g[maxn],u[maxn]; 
12 int n;
13 int a[maxn];
14 int F[maxn];
15 const int Mo=1e9+7;
16 int pow(int a,int b,int c)
17 {
18     int ans=1;
19     while(b)
20     {
21         if(b&1) ans=1ll*ans*a%c;
22         a=1ll*a*a%c;
23         b>>=1;
24     }
25     return ans;
26 }
27 void Init()  
28 {  
29     memset(vis,0,sizeof(vis));  
30     u[1] = 1;  
31     cnt = 0;  
32     for(int i=2;i<maxn-5;i++)  
33     {  
34         if(!vis[i])  
35         {  
36             p[cnt++] = i;  
37             u[i] = -1;    
38         }  
39         for(int j=0;j<cnt&&i*p[j]<maxn-5;j++)  
40         {  
41             vis[i*p[j]] = 1;  
42             if(i%p[j])  
43             {  
44                 u[i*p[j]] = -u[i];  
45             }  
46             else  
47             {  
48                 u[i*p[j]] = 0;   
49                 break;  
50             }  
51         }  
52     }   
53 }  
54 int main()
55 {
56     Init();
57     int T;scanf("%d",&T);
58     int Cas=0;
59     while(T--)
60     {
61         scanf("%d",&n);
62         ll ans=1;
63         int mn=1e5;
64         memset(a,0,sizeof(a));
65         memset(F,0,sizeof(F));
66         for(int i=1;i<=n;i++) {
67             int x;scanf("%d",&x);
68             ans=ans*x%Mo;
69             a[x]++;
70         }
71         for(int i=1;i<=mn;i++)
72         a[i]+=a[i-1];
73         for(int i=1;i<=mn;i++) 
74         if(!a[i-1]) 
75         {
76             F[i]=1;
77             for(int j=1;i*j<=mn;j++)
78             F[i]=1ll*F[i]*pow(j,a[min(i*(j+1)-1,mn)]-a[i*j-1],Mo)%Mo;
79         }
80         ll tmp=0;
81         for(int i=1;i<=mn;i++)
82         {
83             tmp=(tmp+1ll*u[i]*F[i]%Mo)%Mo;
84         }
85         ans=(ans-tmp+Mo)%Mo;
86         printf("Case #%d: %lld
",++Cas,ans);
87     }
88     return 0;
89 }
View Code

Problem 1011

这个题思路很明显。

正多边形肯定只有正方形。

那么枚举一下就可以了。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

typedef long long LL;

const int N = 603;

int f[N][N];
int n;
int ans;

struct Point{
	int x, y;
} p[N];

int solve(Point a, Point b){
	int x = a.x - b.x;
	int y = a.y - b.y;
	int ret = 0;
	if (a.x + y >= 0 && a.y >= x && b.x + y >= 0 && b.y >= x && f[a.x + y][a.y - x] && f[b.x + y][b.y - x]) ++ret;
	if (a.x >= y && a.y + x >= 0 && b.x >= y && b.y + x >= 0 && f[a.x - y][a.y + x] && f[b.x - y][b.y + x]) ++ret;
	return ret;
}


int main(){

	while (~scanf("%d", &n)){
		memset(f, 0, sizeof f);
		rep(i, 1, n){
			int x, y;
			scanf("%d%d", &x, &y);
			x += 100;
			y += 100;
			p[i].x = x;
			p[i].y = y;
			f[x][y] = 1;
		}

		ans = 0;
		rep(i, 1, n - 1)
			rep(j, i + 1, n)
				ans += solve(p[i], p[j]);

		printf("%d
", ans / 4);
	}

	return 0;
}
原文地址:https://www.cnblogs.com/cxhscst2/p/7441880.html