期望得分 100+30+100+30=260
实际得分 100+10+90+30=230
(因为开了define int long long导致TLE痛失30分)
做题过程:拿到题看完T1很有感觉但感觉暴力不好敲,就看T2发现T2也只会暴力,索性直接开T3,觉得就是一个spfa板子,之后开了T4,写了一个n^2的暴力dp但不会优化,就去开T1,发现T1的实质就是算为一位1的个数为奇数的方案数,30分钟切掉,最后看T2,感觉会30的暴力,本想用平衡树来维护集合的,但是我对自己的平衡树基本功并不自信于是用了小根堆优化,4个点就这样过去了
T1:
一共有n 张卡牌,每张卡牌上有一个正整数 ,每次可以从中选出 k张卡牌。一种选取方案的幸运值为这 k张卡牌上数的按位异或和。求所有选取方案的幸运值之和,对998244353取模。
题解上面陈述过了
Code
#include<bits/stdc++.h>
#define re register
#define inl inline
#define int long long
using namespace std;
int read(){
int sum=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){sum=(sum<<3)+(sum<<1)+(c^48);c=getchar();}
return sum*f;
}
const int mod=998244353;
const int N=1e5+10;
int n,a[N],k,ans;
int r[50],res[N],res2[50];
inl int ksm(int a,int b){
int tmp=1;
while(b){
if(b&1) tmp=tmp*a%mod;
b>>=1,a=a*a%mod;
}
return tmp;
}
int C(int x,int y){
if(y>x) return 0;
if(y==0||x==y) return 1;
return (res[x]*ksm(res[y],mod-2)%mod)*ksm(res[x-y],mod-2)%mod;
}
signed main(){
freopen("card.in","r",stdin);freopen("card.out","w",stdout);
n=read(),k=read();
for(re int i=1;i<=n;i++){
a[i]=read();
int x=a[i],t=0;
while(x){
if(x&1) r[t]++;
x>>=1,t++;
}
}
//for(re int i=0;i<=32;i++) cout<<r[i]<<" ";
res[0]=res2[0]=1;
for(re int i=1;i<=32;i++) res2[i]=(res2[i-1]*2)%mod;
for(re int i=1;i<=n;i++) res[i]=(res[i-1]*i)%mod;
for(re int i=0;i<=32;i++){
for(re int j=1;j<=min(r[i],k);j+=2){
ans=(ans+(C(r[i],j)*C(n-r[i],k-j)%mod)*res2[i]%mod)%mod;
}
}
printf("%lld\n",ans);
return 0;
}
T2
思路:容斥原理
当加入一个数时根据正难则反原理,我i们只需要计算原集合的数字个数减去不是质数对的个数,对于不是我们可以将一个数因数分解,再根据容斥即可得解
ans+=tot-cnt[p1]-cnt[p2]+cnt[p1*p2]..........发现系数为莫比乌斯函数,
Code
#include<bits/stdc++.h>
#define re register
#define inl inline
#define ll long long
using namespace std;
int read(){
int sum=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){sum=(sum<<3)+(sum<<1)+(c^48);c=getchar();}
return f*sum;
}
const int N=5e5+10;
bool vis[N],in[N];
int prime[N],mu[N],c[N],cnt,n,q,a[N];
ll ans=0;
vector<int> g[N];
void get(int n){
mu[1]=1;
for(re int i=2;i<=n;i++){
if(!vis[i]) prime[++cnt]=i,mu[i]=-1;
for(re int j=1;prime[j]*i<=n;j++){
vis[prime[j]*i]=1;
if(i%prime[j]==0) break;
else mu[prime[j]*i]=-mu[i];
}
}
}
inl void init(){
get(N-1);
for(re int i=1;i<N;i++){
for(re int j=i;j<N;j+=i){
g[j].push_back(i);
}
}
}
int main(){
freopen("pair.in","r",stdin);
freopen("pair.out","w",stdout);
init();
n=read(),q=read();
for(re int i=1;i<=n;i++) a[i]=read();
while(q--){
int id=read(),x;
x=a[id];
if(!in[id]){
int num=g[x].size();
for(re int i=0;i<num;i++){
int u=g[x][i];
ans+=mu[u]*c[u];
c[u]++;
}
}
else{
int num=g[x].size();
for(re int i=0;i<num;i++){
int u=g[x][i];
c[u]--;
ans-=mu[u]*c[u];
}
}
in[id]=!in[id];
printf("%lld\n",ans);
}
return 0;
}
T3有两种方法,一种就是spfa,另一种是将连通块单独跑dijkstra,再用topo走最短路
Code(dijkstra+toposort)
#include<bits/stdc++.h>
#define re register
#define inl inline
#define ll long long
using namespace std;
int read(){
int sum=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){sum=(sum<<3)+(sum<<1)+(c^48);c=getchar();}
return f*sum;
}
const int N=5e5+10;
const int inf=2e9;
int t,y,p,s,cnt,head[N],dep,col[N],sta[N],dfn[N],low[N],vis[N],sum,top,cnt2,head2[N];
vector<int> block[N];
int dis[N],ind[N];
struct Node{
int to,w,nxt;
}e[N<<1],r[N<<1];
inl void add(int u,int v,int w){
e[++cnt].to=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt;
}
inl void add2(int u,int v,int w){
r[++cnt2].to=v;r[cnt2].w=w;r[cnt2].nxt=head2[u];head2[u]=cnt2;
}
inl void tarjan(int u){
dfn[u]=low[u]=++dep;
sta[++top]=u;
for(re int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
else if(!col[v]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
col[u]=++sum;
block[sum].push_back(u);
while(sta[top]!=u){
col[sta[top]]=sum;
block[sum].push_back(sta[top--]);
}
top--;
}
}
queue<int> h;
struct node{
int u,d;
bool operator <(const node &lzb) const{
return d>lzb.d;
}
};
priority_queue<node> q;
inl void dijkstra(){
while(!q.empty()){
node tmp=q.top();q.pop();
int u=tmp.u;
if(vis[u]) continue;
vis[u]=1;
for(re int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(dis[u]<inf&&dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
q.push((node){v,dis[v]});
}
}
for(re int i=head2[u];i;i=r[i].nxt){
int v=r[i].to;
if(dis[u]<inf&&dis[v]>dis[u]+r[i].w){
dis[v]=dis[u]+r[i].w;
}
ind[col[v]]--;
if(!ind[col[v]]) h.push(col[v]);
}
}
}
inl void topsort(int u){
for(re int i=1;i<=t;i++) dis[i]=2e9;
for(re int i=1;i<=sum;i++){
if(!ind[i]) h.push(i);
}
dis[u]=0;
while(!h.empty()){
int tmp=h.front();h.pop();
for(re int i=0;i<block[tmp].size();i++){
int v=block[tmp][i];
q.push((node){v,dis[v]});
}
dijkstra();
}
}
signed main(){
freopen("roadplane.in","r",stdin);
freopen("roadplane.out","w",stdout);
t=read(),y=read(),p=read(),s=read();
for(re int i=1;i<=y;i++){
int u=read(),v=read(),w=read();
add(u,v,w);add(v,u,w);
}
for(re int i=1;i<=t;i++){
if(!dfn[i]) tarjan(i);
}
for(re int i=1;i<=p;i++){
int u=read(),v=read(),w=read();
add2(u,v,w);
if(col[u]!=col[v]) ind[col[v]]++;
}
topsort(s);
for(re int i=1;i<=t;i++){
if(dis[i]==2e9) puts("NO PATH");
else printf("%d\n",dis[i]);
}
return 0;
}
T4;就会暴力的30~
总结:以后就不开define long long了(,dp优化与数论还需要多练练,但要更注意细节问题,争取日后不挂分!