第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(济南)

A Matrix Equation

分析:其实很好列出n*n个方程组

最后答案就是pow(2,方程组自由解的个数)

但是很明显复杂度是过不了的

仔细观察可以发现 c矩阵一列是单独的一组n元方程组

所以可以对于每列进行高斯消元 复杂度n的4方

但是此时还是不能过200

有个关键的结论 相加模2 等价于 异或!!!!!

异或矩阵是能够用bitset优化 复杂度/64

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 200 + 5;
const int mod = 998244353;
int f[maxn][maxn] , g[maxn][maxn];
ll ksm (ll a , ll b){ ll ans = 1 , base = a;
while (b){if (b & 1) ans = ans * base % mod;b >>= 1;base = base * base % mod;}return ans;}
bitset<maxn> a[maxn];
int n;
ll guess (int x)
{
    // 计算系数
    for (int i = 1 ; i <= n ; i++){
        for (int j = 1 ; j <= n ; j++){
            a[i][j] = f[i][j];
        }
        a[i][i] = (f[i][i] != g[i][x]);
    }
    // 跑高斯消元
    int r , c , free = 0;
    for (r = c = 1 ; r <= n && c <= n ; r++ , c++){
        int p = 0;
        for (int j = r ; j <= n ; j++){
            if (a[j][c]){
                p = j;
                break;
            }
        }
        if (!p){
            r--;
            free++;
            continue;
        }
        swap(a[r] , a[p]);
        for (int j = 1 ; j <= n ; j++){
            if (j == r) continue;
            if (a[j][c] == 0) continue;
            a[j] ^= a[r];
        }
    }
    return ksm(2 , free);
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1 ; i <= n ; i++)
        for (int j = 1 ; j <= n ; j++)
            cin >> f[i][j];
    for (int i = 1 ; i <= n ; i++)
        for (int j = 1 ; j <= n ; j++)
            cin >> g[i][j];
    ll ans = 1;
    for (int i = 1 ; i <= n ; i++) ans = (ans * guess(i))%mod;
    cout << ans << endl;
    return 0;
}

C Stone Game

签到题

#include<iostream>
using namespace std;
typedef long long ll;

int main()
{
    ll t1, t2, t3;
    cin >> t1 >> t2 >> t3;
    ll p1, p2, p3;
    if (t1 > t2)
    {
        p1 = t2 * 2;
        t1 -= t2;
        p2 = t1 / 3 * 3;
        if (t1 % 3 == 2)
            p3 = 1;
        else
            p3 = 0;
    }
    else
    {
        p1 = t1 * 2;
        t2 -= t1;
        p2 = t2 / 3 * 6;
        if (t2 % 3 == 2)
            p3 = 4;
        else
            p3 = 0;
    }
    cout << p1 + p2 + p3;
}

D Fight against involution

分析:

考虑按照R从小到大进行排序 依次处理

对于每个同学 成绩一定不能变差 同一个成绩的同学们一起变化[多个区间取长度最小的]

所以一定得大于等于前一个同学们的成绩 如果等于前一个同学们的成绩 当前同学们的成绩就会上升

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=1e5+5;
ll ans;
int n;
struct node{
	ll L,R;
}a[maxn];
bool cmp(node aa,node bb){
	if(aa.R!=bb.R)return aa.R<bb.R;
	else return aa.L>bb.L;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i].L,&a[i].R);
	sort(a+1,a+1+n,cmp);
	ll lim=0;
	for(int i=1;i<=n;i++){
		if(a[i].R==a[i-1].R)
		ans+=lim;
		else {
			lim=max(a[i].L,lim);
			ans+=lim;
		}
	}
	cout<<ans;
     return 0;
}

G Xor Transformation

分析:

其实我们可以直接找到一个数 直接xor变成Y

但是有个问题 这个数可能是大于X 与题意不符

所以考虑把最高位提出来 xor满足交换律

细节:1<<i 可能会超常数1的范围(常数默认int) 所以一定是1ll<<i

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
unsigned ll x,y,t,t1,t2;
int main(){
	cin>>x>>y;
	for(ll i=0;i<64;i++){
		 t1=(x>>i)&1,t2=(y>>i)&1;
		if(!t2){
			if(t1)t|=1ll<<i; 
		}
		else {
			if(!t1)t|=1ll<<i;
		}
	}
	if(t<x){
		cout<<1<<endl;
		cout<<t<<endl;
	}
	else {
		cout<<2<<endl;
		unsigned ll tp;
		for(ll i=63;i>=0;i--)
			if((t>>i)&1){
				tp=i;
				break;
			}
		cout<<(t^(1ll<<tp))<<" "<<(1ll<<tp);
	}
     return 0;
}

M Cook Pancakes!

签到题

#include<iostream>
using namespace std;


int main()
{
    int n, k;
    cin >> n >> k;
    if (n < k)
        cout << 2;
    else {
        int t1 = n * 2 / k;
        int t2 = n * 2 % k;
        cout << t1 + (t2 != 0);
    }
}

L Bit Sequence

分析:

数据范围很明显的数位dp

因为m大小不是很大 所以dp到最后一位可以直接遍历m

问题在于需要存储哪些状态

100是小于2的七次方也就是128 所以加上一个小于m的值最多会影响第八位小后的那些连续的1

我们把这些连续的1的奇偶存起来

如果是奇数的话加上那个小于m的值进位后还是奇数,不影响

但是偶数的话会变成奇数,改变了奇偶性

还有就是后七位要存起来,第八位以后的一的个数也要存起来

pos是位置,h是后七位的值,g是第八位之后的连续1的个数,c是第八位之后的1的奇偶性,flag是限制

__builtin 的用法:

__builtin_popcount(x) 返回 x 二进制下 1 的个数

__builtin_parity(x) 返回 x 的 1 的个数的奇偶性

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long
ll dp[70][128][2][2][2];
ll w[150],a[150];
int m;
ll x;
ll get(int h,int g,int c){
	int ans=1;
	if(g==1)g=0;
	else g=1;
	for(int i=0;i<m;i++){
		if(i+h>=128){
			if((__builtin_parity((i+h)%128)^c^g)!=a[i])ans=0;
		}
		else{
			if((__builtin_parity((i+h)%128)^c)!=a[i])ans=0;
		}
	}
	return ans;
}
ll dfs(int pos,int h,int g,int c,int flag){
	if(pos==0){
		return get(h,g,c);
	}
	if(dp[pos][h][g][c][flag]!=-1)return dp[pos][h][g][c][flag];
	int maxn=1;
	if(flag==1)maxn=w[pos];
	ll ans=0;
	for(int i=0;i<=maxn;i++){
		if(pos>=8){
			if(i==1){
				ans=ans+dfs(pos-1,h,g^1,c^i,flag&(i==maxn));
			}
			else{
				ans=ans+dfs(pos-1,h,0,c^i,flag&(i==maxn));
			}
		}
		else{
			ans=ans+dfs(pos-1,2*h+i,g,c,flag&(i==maxn));
		}
	}
	dp[pos][h][g][c][flag]=ans;
	return ans;
}
ll solve(){
	int cnt=0;
	while(x!=0){
		w[++cnt]=x%2;
		x=x/2;
	}
	return dfs(cnt,0,0,0,1);
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		memset(dp,-1,sizeof(dp));
		scanf("%d %lld",&m,&x);
		for(int i=0;i<m;i++){
			scanf("%d",&a[i]);
		}
		printf("%lld\n",solve());
	}
}
posted @ 2022-10-24 20:30  wzx_believer  阅读(109)  评论(0编辑  收藏  举报