Problem H. Pow
水题,jave的BigIntrger过一波
import java.util.*;
import java.math.*;
class Main{
public static void main(String argv[]){
Scanner s = new Scanner(System.in);
int T=s.nextInt();
while(T-- >0){
System.out.println(BigInteger.ONE.shiftLeft(s.nextInt()));
}
}
}
Problem G. Cyclic
打表找规律,
D a[100090];
const int mod= 998244353;
void init(){
a[1]=0,a[2]=0,a[3]=1,a[4]=1,a[5]=8,a[6]=36;
for(int i=7;i<=100000;i++)a[i]=((i-3)*a[i-1]%mod+(2*a[i-2]%mod+a[i-3])%mod*(i-2)%mod)%mod;
}
int main(){
init();
int t=read();
int n;
while(t--){
int n=read();
printf("%lld\n",a[n]);
}
}
Problem I. Count
题意:
求
解析:
我开始是知道辗转相减的,也用了,不过化解成了 做了半天。。。其实化成 就直接做出来了
首先 ,且当 时, 为偶数(欧拉函数),那么就是说, 时的答案为 (不知道欧拉函数的我就没办法了)
但是题目n的范围为2e7, 2*n是4e7, 什么概念, 线性筛会T,所以要处理一下
当i为奇数时,
;
当i为偶数时,
;(如果a是素数且n是a倍数 , 有
)
所以我们只需要处理2e7的欧拉函数即可
代码:
#define D long long
#define F double
#define mmm(a,b) memset(a,b,sizeof(a))
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
const int N=20000000;
const F pi=acos(-1);
const D mod=1e9+7;
const F _e=2.718281828459045;
const int MAXN = 2e7+5;
bool flag[MAXN];
D phi[MAXN];
D p[MAXN];
D cnt ;
void Get_phi(D m){
cnt = 0;
memset(flag, true, sizeof(flag));
phi[1] = 1ll;
for(D i=2ll; i<=m; i++) {
if(flag[i]) {
p[++cnt] = i;
phi[i] = i-1ll;//性质2
}
for(D j=1; j<=cnt&&i*p[j]<=m; j++){
flag[i*p[j]] = false;
if(i%p[j] == 0){
phi[i*p[j]] = p[j] * phi[i];//性质3
break;
}
else phi[i*p[j]] = (p[j]-1ll) * phi[i];//性质1
}
}
}
D sum[MAXN];
int main(){
D m=20000000;
Get_phi(m);
for(int i=1;i<=m;i++)
if(i%2)sum[i]=sum[i-1]+phi[i]/2;
else sum[i]=sum[i-1]+phi[i];
int t=read();
while(t--){
int n;
scanf("%d",&n);
printf("%lld\n",sum[n]);
}
}
Problem L.Videos
队友做的h,就直接上代码吧
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=400000;
const int maxm=1000000;
const int inf=0x3f3f3f3f;
int dis[maxn];
int vis[maxn],pre[maxn];
int head[maxn],cnt,viss[maxn],visss[maxm];
int n,m,sp,tp,k,W;
ll ans=0;
struct node{
int to,cap,cost,next;
}e[maxm];
void add(int from,int to,int cap,int cost){
e[cnt].to=to; e[cnt].cap=cap;
e[cnt].cost=cost; e[cnt].next=head[from];
head[from]=cnt++;
e[cnt].to=from; e[cnt].cap=0;
e[cnt].cost=-cost; e[cnt].next=head[to];
head[to]=cnt++;
}
bool spfa(int s,int t,int &flow,int &cost){
queue<int> q;
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
dis[s]=0; q.push(s);
vis[s]=1;
int d=inf;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(e[i].cap>0&&dis[v]>dis[u]+e[i].cost){
dis[v]=dis[u]+e[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
if(dis[t]==inf){
return false;
}
for(int i=pre[t];~i;i=pre[e[i^1].to]){
d=min(d,e[i].cap);
}
for(int i=pre[t];~i;i=pre[e[i^1].to]){
e[i].cap-=d;
e[i^1].cap+=d;
cost+=e[i].cost*d;
}
flow+=d;
return true;
}
int mcmf(int s,int t){
int flow=0,cost=0;
while(spfa(s,t,flow,cost)){
//cout<<flow<<" "<<cost<<endl;
}
return cost;
}
int gainp(int m,int n){
return 200+(m-1)*200+n;
}
int gainaim(int x){
if(x<=200||x>50000) return 0;
x-=200;
x=x/200+1;
if(!viss[x]) return x;
else return 0;
}
struct vid{
int st,en,val,ty,id;
bool operator <(const vid &a) const {
return en<a.en;
}
}vs[205];
vector<vid> vide[201];
void dfs(int x,int fa,int flag){
visss[x]=1;
int tflag=flag;
if(x==tp) return ;
for(int i=head[x];~i;i=e[i].next){
if(e[i].cap==0){
int aim=gainaim(e[i].to);
if(aim) {
if(vs[aim].ty!=flag)
ans+=vs[aim].val,viss[aim]=1;
else ans-=W,ans+=vs[aim].val;
flag=vs[aim].ty;
viss[aim]=1;
}
if(e[i].to==fa||visss[e[i].to]) continue;
dfs(e[i].to,x,flag);
flag=tflag;
}
}
}
int main(){
int t;
cin>>t;
while(t--){
memset(visss,0,sizeof(visss));
memset(viss,0,sizeof(viss));
memset(head,-1,sizeof(head));
ans=0;
scanf("%d%d%d%d",&n,&m,&k,&W);
for(int i=1;i<=n;i++){
vide[i].clear();
}
sp=0;tp=50001;
for(int i=1;i<=k;i++){
add(sp,i,1,0);
}
for(int i=1;i<=m;i++){
scanf("%d%d%d%d",&vs[i].st,&vs[i].en,&vs[i].val,&vs[i].ty);
vs[i].id=i;
vide[vs[i].st].push_back(vs[i]);
}
for(int i=1;i<=k;i++){
for(int j=1;j<=m;j++){
add(i,gainp(j,vs[j].st),1,0);
}
}
for(int i=1;i<=m;i++){
int now=vs[i].en;
for(int j=now;j<=n;j++){
for(int k=0;k<vide[j].size();k++){
vid x=vide[j][k];
if(x.ty==vs[i].ty){
add(gainp(i,vs[i].en),gainp(x.id,x.st),1,W);
}
else {
add(gainp(i,vs[i].en),gainp(x.id,x.st),1,0);
}
}
}
add(gainp(i,vs[i].st),gainp(i,vs[i].en),1,-vs[i].val);
if(vs[i].en!=n) add(gainp(i,vs[i].en),gainp(i,n),1,0);
add(gainp(i,n),tp,1,0);
}
cout<<-mcmf(sp,tp)<<endl;
//dfs(sp,-1,-1);
//printf("%lld\n",ans);
}
return 0;
}
Problem J. CSGO
题意:
有n件主武器和m件副武器,所有武器有一个价值S,已经K种属性,你选择一件主和一件副,得到的价值为 ,也就是S要大,两件武器属性差要大
解析:
对于一件武器i,它的K种属性对最后答案的贡献只有 种(0000,0001,0010…),0表示比另一个小所以要减,1表示比另一个大所以要加
用w[x]表示所有主武器的K种属性在状态为x(转为二进制)时的最大贡献
例子:K种属性为2,3,4,x为5(101)时,贡献为2-3+4=3
在维护好w[]后,对于副武器中的一个i的K种属性,也枚举 个状态,然后和之前主武器中的相反状态(每位异或)相加(当然为了方便不修改状态,主武器0减1加,副武器0加1减),维护答案取一个最大值就行了
有人会问了,加减不是由属性的大小关系决定的吗?
其实是没关系的,假设主武器3 6 4, 副武器4 5 5
最优的主武器状态肯定是010,答案为(-3+4)+(6-5)+(-4+5)=3
但是如果你用111去测呢?答案为(3-4)+(6-5)+(4-5)=-1
就是说,这种不合法的情况虽然也会加入计算,但是绝对不会是最优的情况,所以不会有影响
#include<bits/stdc++.h>
using namespace std;
#define D long long
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
int main(){
int t=read();
while(t--){
D n=read(),m=read(),k=read();
D w[40];
memset(w,0,sizeof(w));
for(D i=1;i<=n;i++){//0110 -> -++-
D s=read();
D ar[6];for(D j=1;j<=k;j++)ar[j]=read();
for(D j=0;j<(1<<k);j++){
D ans=s;
for(D h=1;h<=k;h++){
if(j&(1<<(h-1)))ans+=ar[h];
else ans-=ar[h];
}
w[j]=max(w[j],ans);
}
}
D A=0;
for(D i=1;i<=m;i++){//0110 -> -++-
D s=read();
D ar[6];for(D j=1;j<=k;j++)ar[j]=read();
for(D j=0;j<(1<<k);j++){
D ans=s;
for(D h=1;h<=k;h++){
if(j&(1<<(h-1)))ans-=ar[h];
else ans+=ar[h];
}
A=max(A,ans+w[j]);
}
}
printf("%lld\n",A);
}
}