A-LightOJ - 1035
唯一分解定理问题,将给定的n for一遍,每个数进行分解,最后输出即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <functional>
#include <vector>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn=3e5+50;
const int inf=1e9;
const int MOD=1e9+7;
const int p=1e9+6;
int pri[100]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
//给定数据范围小,打表就行
int num[107];
void init(int n)
{
for(int i=1;n>=pri[i]&&i<=25;i++)//开始没写i<=25 RE了一次
{
while(n%pri[i]==0)
{
num[pri[i]]++;
n/=pri[i];
}
}
if(n>0) num[n]++;
}
int main()
{
int t;
scanf("%d",&t);
for(int ca=1;ca<=t;ca++)
{
int n;
scanf("%d",&n);
memset(num,0,sizeof(num));
for(int i=2;i<=n;i++)
{
init(i);
}
int sign=0;
for(int i=1;i<=25;i++)
if(num[pri[i]]!=0) sign++;
int sign1=1;
printf("Case %d: %d = ",ca,n);
for(int i=1;i<=25;i++)
{
if(num[pri[i]]!=0&&sign!=sign1) {printf("%d (%d) * ",pri[i],num[pri[i]]);sign1++;}
else if(num[pri[i]]!=0&&sign==sign1) printf("%d (%d)\n",pri[i],num[pri[i]]);
}
}
return 0;
}
B-HDU-2049
组合数+错排
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <functional>
#include <vector>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn=3e5+50;
const int inf=1e9;
const int MOD=1e9+7;
const int p=1e9+6;
int num[107];
ll quick_pow(ll n,ll m)
{
ll base=n%MOD;
ll ans=1;
while(m>0)
{
if(m&1) ans=ans*base%MOD;
base=base*base%MOD;
m>>=1;
}
return ans;
}
ll C(int n,int m)
{
n=min(n,m-n);
int ans=1;
for(int i=1;i<=n;i++)
ans=ans*(m-n+i)*quick_pow(i,MOD-2)%MOD;
return ans;
}
ll D(int n)
{
if(n==2) return 1;
if(n==1) return 0;//这里板子背错了,开始写的if(n==2||n==1) return 1;直接给我WA了
return (n-1)*(D(n-1)+D(n-2));
}
int main()
{
int t;
scanf("%d",&t);
for(int ca=1;ca<=t;ca++)
{
int n,m;
scanf("%d%d",&n,&m);
printf("%lld\n",C(m,n)*D(m));
}
return 0;
}
C-HDU-6470
矩阵快速幂问题
由题意求出递推公式 f(n)=f(n-2)×2+f(n-1)+n³,并构建转移状态矩阵
比赛的时候很早就构造出来了,也很早就完成了代码整体的输入,但是死活过不了样例,第一个都过不去。。。
然后一直debug到比赛结束,之后继续de,最后终于发现是矩阵乘法写反了Orz
A×B≠B×A
不要太绝望
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <functional>
#include <vector>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn=3e5+50;
const int inf=1e9;
const int MOD=123456789;
const int p=1e9+6;
struct node
{
ll a[10][10];
};
node operator*(node x,node y)
{
node tmp;
for(int i=1;i<=6;i++)
for(int j=1;j<=6;j++)
{
tmp.a[i][j]=0;
for(int k=1;k<=6;k++)
{
tmp.a[i][j]+=x.a[i][k]*y.a[k][j]%MOD;
tmp.a[i][j]%=MOD;
}
}
return tmp;
}
node operator^(node x,ll b)
{
node tmp;
memset(tmp.a,0,sizeof(tmp.a));
for(int i=1;i<=6;i++)
tmp.a[i][i]=1;
while(b>0)
{
if(b&1) tmp=tmp*x;
x=x*x;
b>>=1;
}
return tmp;
}
int main()
{
node zhuanyi;
node chushi;
int t;
scanf("%d",&t);
memset(zhuanyi.a,0,sizeof(zhuanyi.a));
memset(chushi.a,0,sizeof(chushi.a));
zhuanyi.a[1][1]=zhuanyi.a[2][1]=zhuanyi.a[3][3]=zhuanyi.a[4][4]=zhuanyi.a[5][5]=zhuanyi.a[6][6]=zhuanyi.a[1][3]=zhuanyi.a[1][6]=zhuanyi.a[3][6]=zhuanyi.a[4][6]=zhuanyi.a[5][6]=1;
zhuanyi.a[1][2]=zhuanyi.a[4][5]=2;
zhuanyi.a[1][4]=zhuanyi.a[3][4]=zhuanyi.a[3][5]=zhuanyi.a[1][5]=3;
chushi.a[1][1]=2,chushi.a[2][1]=1,chushi.a[3][1]=8,chushi.a[4][1]=4,chushi.a[5][1]=2,chushi.a[6][1]=1;
while(t--)
{
ll n;
scanf("%lld",&n);
node tmp;
int tt;
tt=1;
tmp=(zhuanyi^(n-2))*chushi;//就是这里写反了 死活没忘这个方向想QAQ
printf("%d\n",tmp.a[1][1]);
return 0;
}
转移态矩阵的构造我是之前看大佬的博客学会的
这里附上链接
D-HDU-1799
比赛的时候没看懂题
嵌套m层循环,问最后操作次数是多少
其实就是求组合数
因为模数较小,不能使用逆元处理
根据公式C(n,m) = C(n - 1,m) + C(n - 1,m - 1)打表处理
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <functional>
#include <vector>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn=3e5+50;
const int inf=1e9;
const int MOD=1007;
const int p=1e9+6;
int C[2007][2007];
void init()
{
C[0][0]=1;
for(int i=1;i<=2000;i++)
{
C[i][0]=1;
for(int j=1;j<=2000;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
}
}
int main()
{
init();
int t;
scanf("%d",&t);
while(t--)
{
int m,n;
scanf("%d%d",&n,&m);
printf("%d\n",C[m][n]);
}
return 0;
}
E-CFgym
平均数是固定的
学长给的标程
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
double a[maxn];
struct node {
int id;//锅的序号
double y;//当前分锅人数下的方差-再加入一个人分锅的方差,具体推导见最下方
int cnt;//计数,一个问题几个人背锅
bool friend operator<(node a, node b) {//用来维护优先队列,队列顶端是y的最大值,此时对队列顶端处理可以让方差减小的值最大,即每个人的贡献最大
return a.y < b.y;
}
};
priority_queue<node> q;
int main() {
int t, n, m;
scanf("%d", &t);
for (int cas = 1; cas <= t; cas++) {
scanf("%d%d", &n, &m);
double av = 0;
for (int i = 1; i <= n; i++) {
scanf("%lf", &a[i]);
av += a[i];//求锅的和
q.push({i, a[i] * a[i] - a[i] * a[i] / 2, 1});//中间的式子可以写成a[i]*a[i]*(1.0/1-1.0/2)
}
av /= m;//锅分给每个人的平均值
for (int i = 1; i <= m - n; i++) {
node tmp = q.top(), tt;
q.pop();
tt.cnt = tmp.cnt + 1; //该问题分锅人数+1
tt.id = tmp.id;
tt.y = a[tmp.id] * a[tmp.id] * (1.0 / tt.cnt - 1.0 / (tt.cnt + 1));
q.push(tt);
}
double ans = 0;
while (!q.empty()) {
node tt = q.top();
ans += tt.cnt * (av - a[tt.id] / tt.cnt) * (av - a[tt.id] / tt.cnt);
q.pop();
}
printf("Case #%d: ", cas);
printf("%.10f\n", ans / m);
}
return 0;
}
/*
因为每个问题至少要有一人背锅,所以只要考虑剩下的m-n个人即可。
因为要让方差尽可能小,所以我们需要让每次一个人产生的贡献尽可能大。
所以每次让一个人为他加入前后方差之差最大的那个问题背锅就是最优的。
化简前后方差的差值:
num*(a/num-x)^2-(num+1)*(a/(num+1)-x)^2 (num为分锅人数,a为锅的大小,x为均值)
最后得到的表达式为(a^2)*(1/num-1/(num+1))-x² 由于x²为固定值,是一个常数,
维护队列的时候让(a^2)*(1/num-1/(num+1))最大即可
用优先队列或者set维护a^2/(num*(num+1))即可.
*/
F-HDU-5981
学长说是金牌题
暂时不用研究了
放两篇题解
https://blog.csdn.net/Jaihk662/article/details/77435217
https://blog.csdn.net/lych_cys/article/details/53149585
赛况记录:
A - RE1次(少写条件);
B - WA1次(背错板子);
C - 未完成(矩阵乘法Orz);
D - 未完成 (没看懂题意);
E - 未完成 ;
F - 未完成 (还好没细想233);
附contest链接