A题:求质数的原根,比赛的时候是直接暴力过掉的,赛后看了题解以及原根的定义,直接输出n-1的欧拉函数值就可以了,具体的证明过程表示看不懂,那位大神看懂了教教我。
B题:一开始题意没看懂,纠结了半天,最后总算过了。
C题:看错题意了,赛后看别人解题才知道操作1是前面a个全部加x,开两个数组分别记录当前值和增量就可以了。
D题:比赛的时候卡在前面了,没时间写了,记忆化搜索每一种状态。
E题:看了解题表示没看懂,不过后来灵感突发总算想通了,不然可得憋坏了,如果有限制条件,被限制严格大于后者的必须至少取大于1个,也就是说,后者取0个,前者也必须至少取1个。先将限制条件转化成硬币大小,然后完全背包。这题再算t时超int了,直接从负数被减成正数了,让我贡献了好几个RE。。。
F题:很经典的dp题,根据题目得到公式,将公式变形,分析奇偶性。
G题:求三元组的补集,也就是胜两场的方案,再拿总数减去即为所求,方案数用线段树维护,跟扫描线差不多。
codeE:
#include<cstdio>
#include<cstring>
const int MOD=1000000007;
const int nsize=333;
int n,q,t,x,y,temp,flag;
int next[nsize],v[nsize],a[nsize],dp[100010];
int main()
{
while (~scanf("%d%d%d",&n,&q,&t))
{
memset(v,1,sizeof(v));
memset(dp,0,sizeof(dp));
memset(next,0,sizeof(next));
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
for (int i=0;i<q;i++)
{
scanf("%d%d",&x,&y);
if (x>0&&x<333) next[x]=y;
if (y>0&&y<333) v[y]=0;
}
flag=0,dp[0]=1;
for (int j,i=1;i<=n;i++)
{
if (v[i])
{
v[i]=0;
for (j=i;next[j]>0;j=temp)
{
temp=next[j];
a[temp]+=a[j];
next[j]=0;
}
v[j]=1;
}
}
for (int i=1;i<=n;i++)
{
if (next[i])
{
flag=1;
break;
}
}
for (int i=1;i<=n;i++)
{
if (!v[i]) t-=a[i];
if (t<0) flag=1;
}
if (flag)
{
printf("0\n");
continue;
}
for (int i=1;i<=n;i++)
{
for (int j=a[i];j<=t;j++)
{
dp[j]+=dp[j-a[i]];
dp[j]%=MOD;
}
}
printf("%d\n",dp[t]);
}
return 0;
}
codeF:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int NS=111111;
struct Line
{
int x,y;
bool operator < (const Line &cmp) const {
return x<cmp.x;
}
}line[NS<<1];
LL res;
int n,k,tx,ty,top;
int a[NS],xr[NS<<2],sum[NS<<2];
void Pushdown(int rt,int l,int r)
{
if (xr[rt])
{
int mid=(l+r)>>1,ls=rt<<1,rs=ls|1;
xr[ls]^=1,xr[rs]^=1;
xr[rt]=0;
sum[ls]=mid-l+1-sum[ls];
sum[rs]=r-mid-sum[rs];
}
}
void update(int L,int R,int l,int r,int rt)
{
if (L<=l&&r<=R)
{
xr[rt]^=1;
sum[rt]=r-l+1-sum[rt];
return ;
}
int mid=(l+r)>>1;
Pushdown(rt,l,r);
if (L<=mid) update(L,R,l,mid,rt<<1);
if (R>mid) update(L,R,mid+1,r,rt<<1|1);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
int query(int L,int R,int l,int r,int rt)
{
if (L<=l&&r<=R) return sum[rt];
Pushdown(rt,l,r);
int mid=(l+r)>>1,ans=0;
if (L<=mid) ans+=query(L,R,l,mid,rt<<1);
if (R>mid) ans+=query(L,R,mid+1,r,rt<<1|1);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
return ans;
}
int main()
{
while (~scanf("%d%d",&n,&k))
{
top=0;
memset(xr,0,sizeof(xr));
memset(sum,0,sizeof(sum));
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
for (int i=0;i<k;i++)
{
scanf("%d%d",&tx,&ty);
tx=lower_bound(a+1,a+n+1,tx)-a;
ty=upper_bound(a+1,a+n+1,ty)-a-1;
if (tx<ty)
{
line[top].x=tx,line[top++].y=ty;
line[top].x=ty+1,line[top++].y=tx;
}
}
res=1LL*n*(n-1)*(n-2)/6;
sort(line,line+top);
for (int j=0,i=1;i<=n;i++)
{
for (;j<top&&line[j].x<=i;j++)
if (line[j].x>line[j].y)
update(line[j].y,line[j].x-1,1,n,1);
else update(line[j].x,line[j].y,1,n,1);
tx=ty=0;
if (i>1) tx=i-1-query(1,i-1,1,n,1);
if (i<n) ty=query(i+1,n,1,n,1);
tx+=ty;
res-=1LL*tx*(tx-1)/2;
}
printf("%I64d\n",res);
}
return 0;
}