第 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());
}
}