K题 NIO’s Sword
题意:给出n个数,要求从1到n以此得出这n个数,每轮可以进行一种操作,将x变成(10∗x+y)%n,x最开始是0,y每次由自己随意指定,问最少操作多少次可以得到这n个数
思路:可以发现每次击败敌人需要升级次数最多不会超过n的位数,这点通过鸽巢原理可知,那么就可以从1开始枚举需要添加几位数字,如果添加i位数字就能击败敌人,那么一定存在一个x使得y*Now+x同余1,y是一个由i位9构成的常数并且x∈[0, y],其实也就是攻击力的增量和1同余的意思,于是就可以从1开始枚举要添加几位数字了,O(1)判断出是否能击败敌人,最终统计一下答案即可,最后要注意n = 1的情况答案是0而不是1。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int ten[10] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
signed main()
{
int n;
cin >> n;
if(n == 1) puts("0");
else{
int ans = 0;
for(int i = 0; i < n; i++){
int Now = i;
for(int j = 1; j <= 7; j++){//添加j位
int l = (ten[j]-1)*Now%n, r = l+ten[j]-1;
if(!(l > 1 && r < n+1 || l == 0 && r == 0)){
ans += j;
break;
}
}
}
cout << ans << endl;
}
return 0;
}
N题 Particle Arts
思路:n个粒子,每个粒子有一个能量ai。两两随机碰撞,假如两个例子的能量分别为a和b,那么碰撞一次两粒子的能量分别变为a&b,a|b。求所有粒子能量稳定后的方差。分析两个粒子碰撞后的结果可以发现,对于a和b的二进制位,假如第i位两者都是1,那么碰撞后形成的两个粒子能量的第i位都是1,如果第i位两者都是0,那么碰撞后形成的两个粒子能量的第i位都是0,如果碰撞前a粒子和b粒子能量第i位一个是1一个是0,那么碰撞后形成的粒子第i位也是一个1一个0,但是1是在或运算后的那个粒子上,那么容易发现,每次碰撞都会使得一个粒子的能量变大(也可能不变),而且碰撞后二进制位上1的个数不变,只是有可能从1个粒子转移到另一个粒子上,由于碰撞了无数次,那么肯定使得二进制上的1尽可能地集中在了少数上,最后的稳定态也就是对于任意的i和j,都有(ai|aj,ai&aj)=(ai,aj)或者 (ai|aj,ai&aj)=(aj,ai) 。 所以我们只需要统计一开始给定的n个数中每一位上1出现的次数即可,最后对n个数进行分配,每次都尽可能把1分配在一个数上,最后求一下期望即可。需要注意的一点就是由于数比较大,所以可能会爆long long,所以建议直接用__int128计算。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int cnt[200];
long long a[N],b[N];
int main()
{
long long n;
cin>>n;
for(int i=1;i<=n;i++)
{
int t;
scanf("%lld",&a[i]);
for(int j=0;j<15;j++)
cnt[j]+=(a[i]>>j&1);
}
__int128 ans=0,ans1=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<15;j++)
if(cnt[j])
{
b[i]|=(1<<j);
cnt[j]--;
}
ans+=b[i];
ans1+=b[i]*b[i];
}
__int128 anss=ans1*n+ans*ans-2*ans*ans;
__int128 t=__gcd(anss,(__int128)n*n);
long long up = anss/t;
long long down = n*n/t;
printf("%lld/%lld",up,down);
return 0;
}
D题 Jobs(Easy Vision)
题意:有n个公司,第i个公司有mi个工作,每个工作对三个能力分别有数值要求,必须三个能力都达到要求才能胜任这份工作。一个人只要能胜任一个公司的任意一份工作即可。由于只需要知道能否胜任某个公司的某个工作而不是全部的工作都要胜任,而且我们要存储多个公司的信息,对于第i个公司我们用第i位二进制位去维护该信息,然后直接O(1)查询即可。
#include<bits/stdc++.h>
using namespace std;
const int N=405,mod=998244353;
int f[N][N][N],s[2000005];
int lastans=0,seed;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main(){
int n,m;
n=read();
m=read();
for(int i=1;i<=n;i++){
int t;
t=read();
for(int j=1;j<=t;j++){
int a,b,c;
a=read();
b=read();
c=read();
f[a][b][c]|=(1<<i);
}
}
for(int i=1;i<=400;i++)
for(int j=1;j<=400;j++)
for(int k=1;k<=400;k++)
f[i][j][k]|=f[i][j][k-1]|f[i][j-1][k]|f[i-1][j][k];
seed=read();
std::uniform_int_distribution<> u(1,400);
std::mt19937 rng(seed);
s[0]=1;
for(int i=1;i<=m;i++)
s[i]=1ll*s[i-1]*seed%mod;
long long anss = 0;
for(int i=1;i<=m;i++){
int IQ=(u(rng)^lastans)%400+1; // The IQ of the i-th friend
int EQ=(u(rng)^lastans)%400+1; // The EQ of the i-th friend
int AQ=(u(rng)^lastans)%400+1; // The AQ of the i-th friend
lastans=0;
for(int i=1;i<=n;i++)
lastans+=f[IQ][EQ][AQ]>>i&1;
anss = (anss+1ll*lastans*s[m-i]%mod)%mod;
}
printf("%lld\n", anss);
return 0;
}