寒假集训记录
集训:
贪心与二分:
之前求最长上升子序列都是用做的,现在发现做法的妙处了!同时复习了一下二分,收获很多的一道题
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 50007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m,k,ans1,ans2;
int a[N],mx[N];
bool Solve()
{
//freopen("test.in","r",stdin);
int in;
while(scanf("%lld",&in)!=EOF)
a[++n]=in;
mx[0]=inf;
for(int i=1;i<=n;++i)
{
int l=0,r=ans1+1,mid;
while(l<r-1)
{
mid=l+((r-l)>>1);
if(mx[mid]>=a[i])
l=mid;
else
r=mid;
}
ans1=max(ans1,l+1);
mx[l+1]=a[i];
}
memset(mx,0,sizeof(mx));
for(int i=1;i<=n;++i)
{
int l=0,r=ans2+1,mid;
while(l<r-1)
{
mid=l+((r-l)>>1);
if(mx[mid]<a[i])
l=mid;
else
r=mid;
}
ans2=max(ans2,l+1);
mx[l+1]=a[i];
}
printf("%lld\n%lld",ans1,ans2);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
先手推乱搞出大臣的排队顺序,然后发现要高精。。。于是去题解里面搬了个板子美滋滋~
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 1007
#define M 10007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Node
{
int l,r;
}a[N];
int T=1,n;
void H_cpy(int *num1,int *num2)
{
for(int i=0;i<M;++i) num1[i]=num2[i];
}
bool H_cmp(int *num1,int *num2)
{
for(int i=M-1;i>=0;--i)
{
if(num1[i]>num2[i]) return 1;
if(num1[i]<num2[i]) return 0;
}
return 0;
}
void H_time(int *num1,int val)
{
for(int i=M-2;i>=0;--i) num1[i]*=val;
for(int i=0;i<M-1;++i)
{
num1[i+1]+=(num1[i]/10);
num1[i]%=10;
}
}
void H_div(int *num1,int *num2,int val)
{
memset(num2,0,sizeof(num2));
int x=0;
for(int i=M-1;i>=0;--i)
{
x=x*10+num1[i];
num2[i]=x/val;
x%=val;
}
}
void H_print(int *num1)
{
bool flag=0;
for(int i=M-1;i>=0;--i)
{
if(!flag)
{
if(num1[i]) flag=1;
else continue;
}
printf("%d",num1[i]);
}
}
bool Cmp(Node x,Node y)
{
return x.l*x.r<y.l*y.r;
}
int ans[M],now[M],tmp[M];
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=0;i<=n;++i)
scanf("%lld%lld",&a[i].l,&a[i].r);
sort(a+1,a+1+n,Cmp);
now[0]=1;
H_time(now,a[0].l);
for(int i=1;i<=n;++i)
{
H_div(now,tmp,a[i].r);
if(H_cmp(tmp,ans))
H_cpy(ans,tmp);
H_time(now,a[i].l);
}
H_print(ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
细节没把握好导致多了几遍,思路很简单的一道题
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 300007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m,k;
int a[N],b[N];
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld%lld",&n,&m,&k);
for(int i=1;i<=k;++i)
scanf("%lld",&a[i]);
sort(a+1,a+1+k);
for(int i=1;i<=k;++i)
b[i]=a[i]-a[i-1]-1;
sort(b+2,b+1+k);
int ans=a[k]-a[1]+1;
for(int i=1;i<n;++i)
{
if(k-i+1==1)
break;
ans-=b[k-i+1];
}
printf("%lld\n",ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
我真的不配这道题,感谢给我的方法以及对相关问题的思考,目前理解的还不深,每天会来啃一啃。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 20007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Node
{
int l,r;
}a[N];
int T=1,n,m,k;
bool Cmp(Node x,Node y)
{
if(min(x.l,y.r)==min(x.r,y.l))
return x.l<y.l;
return min(x.l,y.r)<min(x.r,y.l);
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld%lld",&a[i].l,&a[i].r);
sort(a+1,a+1+n,Cmp);
int ans=a[1].l+a[1].r,now=a[1].l+a[1].r,sum=a[1].l;
for(int i=2;i<=n;++i)
{
sum+=a[i].l;
now=max(now,sum)+a[i].r;
ans=max(ans,now);
}
printf("%lld\n",ans);
return true;
}
signed main()
{
scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
好久没写交互题了,一写就是一坨屎山,交了半天交过去了,但是不知道为啥我之前写二分写第五个点会,不想太看屎山了,就这样吧
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 300007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,cnt,ans[2];
void Judge(int l,int r,int now)
{
int n=r-l+1;
if(n&1)
{
if(now==2)
{
printf("1 %lld ",n/2);
for(int i=1;i<=n/2;++i)
printf("%lld ",l+i-1);
printf("%lld ",n/2);
for(int i=n/2+1;i<n;++i)
printf("%lld ",l+i-1);
printf("\n");
char in;
cin>>in;
if(in=='=')
{
if(n==3)
{
ans[++cnt]=l;
ans[++cnt]=l+1;
return;
}
Judge(l,l+n/2-1,1);
Judge(l+n/2,l+n-1,1);
return;
}
if(in=='<')
{
if(n==3)
{
ans[++cnt]=l;
ans[++cnt]=r;
return;
}
printf("1 1 %lld 1 %lld\n",r-1,r);
char in1;
cin>>in1;
if(in1=='=')
Judge(l,l+n/2-1,2);
if(in1=='>')
{
ans[++cnt]=r;
Judge(l,l+n/2-1,1);
}
return;
}
if(in=='>')
{
if(n==3)
{
ans[++cnt]=l+1;
ans[++cnt]=r;
return;
}
printf("1 1 %lld 1 %lld\n",l,r);
char in1;
cin>>in1;
if(in1=='=')
Judge(l+n/2,l+n-1,2);
if(in1=='>')
{
ans[++cnt]=r;
Judge(l+n/2,l+n-1,1);
}
return;
}
}
else
{
printf("1 %lld ",n/3);
for(int i=1;i<=n/3;++i)
printf("%lld ",l+i-1);
printf("%lld ",n/3);
for(int i=n/3+1;i<=n/3*2;++i)
printf("%lld ",l+i-1);
printf("\n");
char in;
cin>>in;
if(in=='=')
{
if(n==3)
{
ans[++cnt]=r;
return;
}
Judge(l+n/3*2,r,1);
return;
}
if(in=='<')
{
if(n==3||n==4||n==5)
{
ans[++cnt]=l;
return;
}
Judge(l,l+n/3-1,1);
return;
}
if(in=='>')
{
if(n==3||n==4||n==5)
{
ans[++cnt]=l+1;
return;
}
Judge(l+n/3,l+n/3*2-1,1);
return;
}
}
}
else
{
if(now==2)
{
printf("1 %lld ",n/2);
for(int i=1;i<=n/2;++i)
printf("%lld ",l+i-1);
printf("%lld ",n/2);
for(int i=n/2+1;i<=n;++i)
printf("%lld ",l+i-1);
printf("\n");
char in;
cin>>in;
if(in=='=')
{
if(n==2)
{
ans[++cnt]=l,ans[++cnt]=r;
return;
}
Judge(l,l+n/2-1,1);
Judge(l+n/2,l+n-1,1);
return;
}
if(in=='<')
{
Judge(l,l+n/2-1,2);
return;
}
if(in=='>')
{
Judge(l+n/2,l+n-1,2);
return;
}
}
else
{
if(n==2)
{
printf("1 %lld ",n/2);
for(int i=1;i<=n/2;++i)
printf("%lld ",l+i-1);
printf("%lld ",n/2);
for(int i=n/2+1;i<=n;++i)
printf("%lld ",l+i-1);
printf("\n");
char in;
cin>>in;
if(in=='<')
ans[++cnt]=l;
else
ans[++cnt]=r;
return;
}
printf("1 %lld ",n/3);
for(int i=1;i<=n/3;++i)
printf("%lld ",l+i-1);
printf("%lld ",n/3);
for(int i=n/3+1;i<=n/3*2;++i)
printf("%lld ",l+i-1);
printf("\n");
char in;
cin>>in;
if(in=='=')
{
if(n==3)
{
ans[++cnt]=r;
return;
}
Judge(l+n/3*2,r,1);
return;
}
if(in=='<')
{
if(n==3||n==4||n==5)
{
ans[++cnt]=l;
return;
}
Judge(l,l+n/3-1,1);
return;
}
if(in=='>')
{
if(n==3||n==4||n==5)
{
ans[++cnt]=l+1;
return;
}
Judge(l+n/3,l+n/3*2-1,1);
return;
}
}
}
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
Judge(1,n,2);
printf("2 %lld %lld\n",min(ans[1],ans[2]),max(ans[1],ans[2]));
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
KMP与Trie:
考察对的魔改的一个题,用栈来模拟删除操作
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 0x3f3f3f3f
#define inc 0xcfcfcfcf
#define N 1000007
#define mod 1000000007
using namespace std;
int T=1,n,m,k,cnt;
int a[N],fail[N];
int stk[N],pos[N];
void Kmp(string t,string p)
{
int lt=t.size(),lp=p.size();
int j=0;
for(int i=1;i<lp;i++)//fail指针
{
j=fail[i];
while(j&&p[i]!=p[j])
j=fail[j];
if(p[i]==p[j])
fail[i+1]=j+1;
else
fail[i+1]=0;
}
j=0;
for(int i=0;i<lt;i++)
{
while(j&&t[i]!=p[j])
j=fail[j];
if(t[i]==p[j])
j++;
pos[i]=j;
stk[++cnt]=i;
if(j==lp)
{
cnt-=lp;
j=pos[stk[cnt]];
}
}
}
bool Solve()
{
string in1,in2;
cin>>in1>>in2;
Kmp(in1,in2);
for(int i=1;i<=cnt;++i)
printf("%c",in1[stk[i]]);
return true;
}
signed main()
{
scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
改了半天终于改对了
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n;
int fail[N*10];
string a[N];
int Get_fail(string p)
{
//memset(fail,0,sizeof(fail));
int lp=p.size();
int j=0;
for(int i=1;i<lp;i++)
{
j=fail[i];
while(j&&p[i]!=p[j])
j=fail[j];
if(p[i]==p[j])
fail[i+1]=j+1;
else
fail[i+1]=0;
}
return fail[lp];
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
cin>>a[i];
string ans=a[1];
for(int i=2;i<=n;++i)
{
string x,y,z;
int len1=ans.size(),len2=a[i].size();
if(len1>=len2)
{
for(int j=len1-len2;j<len1;++j)
x+=ans[j];
y=a[i];
z=y+"@"+x;
int now=Get_fail(z);
for(int j=now;j<len2;++j)
ans+=a[i][j];
}
else
{
x=ans;
for(int j=0;j<len1;++j)
y+=a[i][j];
z=y+"@"+x;
int now=Get_fail(z);
for(int j=now;j<len2;++j)
ans+=a[i][j];
}
}
cout<<ans<<endl;
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
将前缀重复一次,变成当前子串最长公共前后缀问题,用fail指针求解
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 0x3f3f3f3f
#define inc 0xcfcfcfcf
#define N 1000007
#define mod 1000000007
using namespace std;
int T=1,n,m,k;
int a[N],fail[N];
void Kmp(string p)
{
int lp=p.size();
int j=0;
for(int i=1;i<lp;i++)//fail指针
{
j=fail[i];
while(j&&p[i]!=p[j])
j=fail[j];
if(p[i]==p[j])
fail[i+1]=j+1;
else
fail[i+1]=0;
}
}
bool Solve()
{
scanf("%lld",&n);
string in;
cin>>in;
Kmp(in);
int ans=0;
/*for(int i=1;i<=n;++i)
{
printf("%lld ",fail[i]);
}*/
for(int i=1;i<=n;++i)
{
int now=i;
while(fail[now]) now=fail[now];
if(fail[i])
fail[i]=now;
ans+=i-now;
}
printf("%lld\n",ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
之前没学,离谱的是不吸氧过不了板子题,大概是string的功劳吧~~
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 0x3f3f3f3f
#define inc 0xcfcfcfcf
#define N 20000007
#define mod 1000000007
using namespace std;
int T=1,n,m,k;
int etd[N],nxt[N];
void Get_nxt(string s)//nxt[i]表示以s[i]开头的后缀与整串的lcp
{
int len=s.size();
int pos=0,k=1,l;//k为 i+nxt[i]-1最大的那个i
nxt[0]=len;
while(pos+1<len&&s[pos]==s[pos+1]) ++pos;
nxt[1]=pos;
for(int i=2;i<len;++i)
{
pos=k+nxt[k]-1;
l=nxt[i-k];
if(i+l<=pos) nxt[i]=l;
else
{
int j=max((int)0,pos-i+1);
while(i+j<len&&s[i+j]==s[j]) ++j;
nxt[i]=j;
k=i; //刷新了最大值
}
}
}
void Get_etd(string t,string p)
{
int lt=t.size(),lp=p.size();
int pos=0,k=0,l;
while(pos<lt&&pos<lp&&t[pos]==p[pos]) ++pos;
etd[0]=pos;
for(int i=1;i<lt;++i)
{
pos=k+etd[k]-1;
l=nxt[i-k];
if(i+l<=pos) etd[i]=l;
else
{
int j=max((int)0,pos-i+1);
while(i+j<lt&&j<lp&&t[i+j]==p[j]) ++j;
etd[i]=j;
k=i;
}
}
}
void Ex_kmp(string t,string p)
{
Get_nxt(p);
Get_etd(t,p);
int ans=nxt[0]+1;
for(int i=1;i<p.size();++i)
ans^=(i+1)*(nxt[i]+1);
printf("%lld\n",ans);
ans=etd[0]+1;
for(int i=1;i<t.size();++i)
ans^=(i+1)*(etd[i]+1);
printf("%lld\n",ans);
}
bool Solve()
{
string in1,in2;
cin>>in1>>in2;
Ex_kmp(in1,in2);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
虽然可以直接map,但是太无聊了,这里给出另外两种水题法
法一:字符串哈希(虽然和map没两样)
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 300007
#define M 500007
#define mod 1000000007
#define K_1 19260817
#define K_2 1433223
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n;
int a[N];
map<int,int> mp1,mp2;
int Hash1(string s)
{
int ans=0;
for(int i=0;i<s.size();++i)
ans=ans*K_1+s[i],ans%=mod;
return ans;
}
int Hash2(string s)
{
int ans=0;
for(int i=0;i<s.size();++i)
ans=ans*K_2+s[i],ans%=mod;
return ans;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
{
string in;
cin>>in;
mp1.insert(make_pair(Hash1(in),1));
mp2.insert(make_pair(Hash2(in),1));
}
scanf("%lld",&n);
for(int i=1;i<=n;++i)
{
string in;
cin>>in;
int now1=Hash1(in),now2=Hash2(in);
if(mp1[now1]==1&&mp2[now2]==1)
{
printf("OK\n");
++mp1[now1];
++mp2[now2];
continue;
}
if(mp1[now1]>1&&mp2[now2]>1)
{
printf("REPEAT\n");
++mp1[now1];
++mp2[now2];
continue;
}
printf("WRONG\n");
}
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
法二:字典树(常规方法吧属于是)
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 300007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Trie
{
int ch[27],vis;
bool is;
}tr[N];
int T=1,n,cnt;
void Insert(string s)
{
int now=0;
for(int i=0;i<s.size();++i)
{
int nxt=s[i]-'a';
if(tr[now].ch[nxt])
now=tr[now].ch[nxt];
else
{
tr[now].ch[nxt]=++cnt;
now=cnt;
}
}
tr[now].is=true;
}
int Search(string s)
{
int now=0;
for(int i=0;i<s.size();++i)
{
int nxt=s[i]-'a';
if(tr[now].ch[nxt])
now=tr[now].ch[nxt];
else
return 3;
}
if(tr[now].is)
{
if(!tr[now].vis)
{
++tr[now].vis;
return 1;
}
else
return 2;
}
else
return 3;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
{
string in;
cin>>in;
Insert(in);
}
scanf("%lld",&n);
for(int i=1;i<=n;++i)
{
string in;
cin>>in;
int opt=Search(in);
if(opt==1)
printf("OK\n");
if(opt==2)
printf("REPEAT\n");
if(opt==3)
printf("WRONG\n");
}
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
属实是好题,一开始求fail然后用kmp来求出现次数,本来是抱有侥幸心理看看能不能水过,果然第九个点T了,于是看题解发现用exkmp,但是我又不想改了,后面想想dp也能求出现次数,于是美美A掉
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,cnt;
int fail[N],ans[N],stk[N],f[N];
void Get_fail(string p)
{
int lp=p.size();
int j=0;
for(int i=1;i<lp;i++)//fail指针
{
j=ans[i];
while(j&&p[i]!=p[j])
j=ans[j];
if(p[i]==p[j])
ans[i+1]=j+1;
else
ans[i+1]=0;
}
}
bool Solve()
{
//freopen("test.in","r",stdin);
string in;
cin>>in;
Get_fail(in);
int now=in.size();
while(now)
{
stk[++cnt]=now;
now=ans[now];
}
for(int i=in.size();i;--i)
{
++f[i];
f[ans[i]]+=f[i];
}
printf("%lld\n",cnt);
while(cnt)
printf("%lld %lld\n",stk[cnt],f[stk[cnt]]),--cnt;
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
时隔三年已经忘记了异或问题可以用01Trie来做了,帮助回顾的好题,主要思路是求出每个点到任一点(这里统一为节点1)的路径异或和,并插入01字典树,然后由异或性质,每次定一个节点,寻找另一个节点使得两点异或和最大,往字典树相反方向走即可。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt,val;
}edge[N<<1];
struct Trie
{
int ch[2];
}tr[N*10];
int T=1,n,ecnt,tcnt;
int head[N],dis[N];
void Add(int u,int v,int w)
{
edge[++ecnt]=(Edge){v,head[u],w};
head[u]=ecnt;
}
void Insert(int val)
{
int now=0;
int bts[40];
for(int i=1;i<=34;++i)
{
bts[i]=val&1;
val>>=1;
}
for(int i=34;i;--i)
{
if(tr[now].ch[bts[i]])
now=tr[now].ch[bts[i]];
else
{
tr[now].ch[bts[i]]=++tcnt;
now=tcnt;
}
}
}
void Dfs(int u,int fa,int val)
{
int num=0;
dis[u]=val;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==fa)
continue;
++num;
Dfs(v,u,val^edge[i].val);
}
}
int Search(int val)
{
int now=0;
int bts[40];
for(int i=1;i<=34;++i)
{
bts[i]=val&1;
val>>=1;
}
for(int i=34;i;--i)
{
if(!bts[i])
{
if(tr[now].ch[1])
{
bts[i]=1;
now=tr[now].ch[1];
}
else
now=tr[now].ch[0];
}
else
{
if(tr[now].ch[0])
now=tr[now].ch[0];
else
{
bts[i]=0;
now=tr[now].ch[1];
}
}
}
int ans=0;
for(int i=34;i;--i)
ans<<=1,ans+=bts[i];
return ans;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<n;++i)
{
int u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
Add(u,v,w);
Add(v,u,w);
}
Dfs(1,0,0);
for(int i=1;i<=n;++i)
Insert(dis[i]);
int ans=0;
for(int i=1;i<=n;++i)
ans=max(ans,Search(dis[i]));
printf("%lld\n",ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
涨知识了,注释标记这行如果写成if(mp[j][in])最后一个点会MLE,好像原因是这样操作每次会新开一个点
点击查看代码
#include<bits/stdc++.h>
//#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 1007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m;
map<string,int> mp[N];
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
int num;
string in;
scanf("%d",&num);
for(int j=1;j<=num;++j)
cin>>in,mp[i][in]=1;
}
scanf("%d",&m);
for(int i=1;i<=m;++i)
{
string in;
cin>>in;
for(int j=1;j<=n;++j)
if(mp[j].count(in))//标记
printf("%d ",j);
printf("\n");
}
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
![P7717 「EZEC-10」序列 ] 阅读理解 ](https://www.luogu.com.cn/problem/P7717)
这题可能理解的还不深,注释的地方改成31,32就WA了,之后再想想把
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 500007
#define M 37
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt,val;
}edge[N<<1];
struct Trie
{
int ch[2];
}tr[N*100];
int T=1,n,m,k,ecnt,tcnt,ans=1;
int head[N],dis[N];
bool vis[N];
void Add(int u,int v,int w)
{
edge[++ecnt]=(Edge){v,head[u],w};
head[u]=ecnt;
}
void Insert(int val)
{
int now=0;
for(int i=30;i>=0;--i)//改成31,32就会错
{
int nxt=(val>>i)&1;
if(!tr[now].ch[nxt])
tr[now].ch[nxt]=++tcnt;
now=tr[now].ch[nxt];
}
}
void Dfs(int u,int fa,int val)
{
dis[u]=val;
vis[u]=1;
Insert(dis[u]);
if(!ans)
return;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==fa)
continue;
if(vis[v])
{
if((val^edge[i].val)!=dis[v])
{
ans=0;
return;
}
continue;
}
Dfs(v,u,val^edge[i].val);
}
}
int Search(int now,int val,int pos)
{
if(val>k)
return 0;
if(pos<0)
return 1;
if(tr[now].ch[0]&&tr[now].ch[1])
return (Search(tr[now].ch[0],val+(1<<pos),pos-1)+Search(tr[now].ch[1],val+(1<<pos),pos-1))%mod;
int nxt=max(tr[now].ch[0],tr[now].ch[1]);
if((val+(1<<pos))<=k)
return (Search(nxt,val+(1<<pos),pos-1)+(1<<pos))%mod;
return Search(nxt,val,pos-1)%mod;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld%lld",&n,&m,&k);
for(int i=1;i<=m;++i)
{
int u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
Add(u,v,w);
Add(v,u,w);
}
for(int i=1;i<=n;++i)
{
if(vis[i])
continue;
Dfs(i,0,0);
ans*=Search(0,0,30);//改成31,32就会错
ans%=mod;
if(!ans)
break;
for(int j=0;j<=tcnt;++j)
tr[j].ch[0]=tr[j].ch[1]=0;
tcnt=0;
}
printf("%lld\n",ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
树状数组与线段树
经验太少了,这个题麻烦的就是取模操作,想着不能用标记实现,于是卡住
思路是区间取模时,搜索区间最大值,如果最大值小于要取模的数,就不需要继续下去,否则就暴力单点取模,维护最大值和区间和即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 500007
#define mod 1000000007
#pragma GCC optimize(2)
#pragma GCC optimize(3)
using namespace std;
struct Tree
{
int mx,sum;
}tr[N<<2];
int T=1,n,m,k;
int a[N];
void Pushup(int now)
{
tr[now].mx=max(tr[now<<1].mx,tr[now<<1|1].mx);
tr[now].sum=tr[now<<1].sum+tr[now<<1|1].sum;
}
void Build(int now,int l,int r)
{
if(l==r)
{
tr[now].sum=a[l];
tr[now].mx=a[l];
return;
}
int mid=l+((r-l)>>1);
Build(now<<1,l,mid);
Build(now<<1|1,mid+1,r);
Pushup(now);
}
int Search_sum(int now,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr)
return tr[now].sum;
int mid=l+((r-l)>>1);
if(rr<=mid)
return Search_sum(now<<1,l,mid,ll,rr);
if(ll>mid)
return Search_sum(now<<1|1,mid+1,r,ll,rr);
return Search_sum(now<<1,l,mid,ll,mid)+Search_sum(now<<1|1,mid+1,r,mid+1,rr);
}
void Update(int now,int l,int r,int pos,int val)
{
if(l==pos&&l==r)
{
tr[now].mx=val;
tr[now].sum=val;
return;
}
int mid=l+((r-l)>>1);
if(pos<=mid)
Update(now<<1,l,mid,pos,val);
else
Update(now<<1|1,mid+1,r,pos,val);
Pushup(now);
}
void Update_mod(int now,int l,int r,int ll,int rr,int val)
{
if(ll<=l&&r<=rr)
{
if(tr[now].mx<val)
return;
if(l==r)
{
int tmp=tr[now].mx;
tr[now].mx=tmp%val;
tr[now].sum=tmp%val;
return;
}
}
int mid=l+((r-l)>>1);
if(rr<=mid)
{
Update_mod(now<<1,l,mid,ll,rr,val);
Pushup(now);
return;
}
if(ll>mid)
{
Update_mod(now<<1|1,mid+1,r,ll,rr,val);
Pushup(now);
return;
}
Update_mod(now<<1,l,mid,ll,mid,val);
Update_mod(now<<1|1,mid+1,r,mid+1,rr,val);
Pushup(now);
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
Build(1,1,n);
for(int i=1;i<=m;++i)
{
int opt,l,r,x;
scanf("%lld",&opt);
if(opt==1)
{
scanf("%lld%lld",&l,&r);
printf("%lld\n",Search_sum(1,1,n,l,r));
}
if(opt==2)
{
scanf("%lld%lld%lld",&l,&r,&x);
Update_mod(1,1,n,l,r,x);
}
if(opt==3)
{
scanf("%lld%lld",&l,&x);
Update(1,1,n,l,x);
}
}
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
乐,以为上面这题暴力修改挺罕见的,没想到是一种套路化的了。。
这题思路是预处理出d[i],注意到d[1]=1,d[2]=2,因此如果一个区间全是1,2的话,就不用再修改了,于是套上面那题模板
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 300007
#define M 1000007
#define mod 1000000007
#pragma GCC optimize(2)
#pragma GCC optimize(3)
using namespace std;
struct Tree
{
int mx,sum;
}tr[N<<2];
int T=1,n,m,k;
int a[N];
int d[M];
void Get_d()
{
for(int i=1;i<=M-5;++i)
for(int j=i;j<=M-5;j+=i)
++d[j];
}
void Pushup(int now)
{
tr[now].mx=max(tr[now<<1].mx,tr[now<<1|1].mx);
tr[now].sum=tr[now<<1].sum+tr[now<<1|1].sum;
}
void Build(int now,int l,int r)
{
if(l==r)
{
tr[now].sum=a[l];
tr[now].mx=a[l];
return;
}
int mid=l+((r-l)>>1);
Build(now<<1,l,mid);
Build(now<<1|1,mid+1,r);
Pushup(now);
}
int Search_sum(int now,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr)
return tr[now].sum;
int mid=l+((r-l)>>1);
if(rr<=mid)
return Search_sum(now<<1,l,mid,ll,rr);
if(ll>mid)
return Search_sum(now<<1|1,mid+1,r,ll,rr);
return Search_sum(now<<1,l,mid,ll,mid)+Search_sum(now<<1|1,mid+1,r,mid+1,rr);
}
void Update_phi(int now,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr)
{
if(tr[now].mx<=2)
return;
if(l==r)
{
int tmp=tr[now].mx;
tr[now].mx=d[tmp];
tr[now].sum=d[tmp];
return;
}
}
int mid=l+((r-l)>>1);
if(rr<=mid)
{
Update_phi(now<<1,l,mid,ll,rr);
Pushup(now);
return;
}
if(ll>mid)
{
Update_phi(now<<1|1,mid+1,r,ll,rr);
Pushup(now);
return;
}
Update_phi(now<<1,l,mid,ll,mid);
Update_phi(now<<1|1,mid+1,r,mid+1,rr);
Pushup(now);
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&m);
Get_d();
// for(int i=1;i<=10;++i)
// printf("%lld:%lld\n",i,d[i]);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
Build(1,1,n);
for(int i=1;i<=m;++i)
{
int opt,l,r;
scanf("%lld%lld%lld",&opt,&l,&r);
if(opt==1)
Update_phi(1,1,n,l,r);
if(opt==2)
printf("%lld\n",Search_sum(1,1,n,l,r));
}
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
真的会谢,不记得标记清零导致WA了一天,维护加和区间覆盖标记即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 1000007
#define mod 1000000007
#pragma GCC optimize(2)
#pragma GCC optimize(3)
using namespace std;
struct Tree
{
int col,sum,add,box=-1;
}tr[N<<2];
int T=1,n,m,k;
void Pushup(int now,int l,int r)
{
if(l==r)
return;
tr[now].sum=tr[now<<1].sum+tr[now<<1|1].sum;
if(tr[now<<1].col==tr[now<<1|1].col)
tr[now].col=tr[now<<1].col;
else
tr[now].col=-1;
}
void Push_add(int now,int l,int r,int x)
{
tr[now].sum+=x*(r-l+1);
tr[now].add+=x;
}
void Push_box(int now,int l,int r,int x)
{
tr[now].col=tr[now].box=x;
}
void Pushdown(int now,int l,int r)
{
int mid=l+((r-l)>>1);
Push_add(now<<1,l,mid,tr[now].add);
Push_add(now<<1|1,mid+1,r,tr[now].add);
tr[now].add=0;
if(tr[now].box!=-1)
{
Push_box(now<<1,l,mid,tr[now].box);
Push_box(now<<1|1,mid+1,r,tr[now].box);
tr[now].box=-1;
}
}
void Build(int now,int l,int r)
{
if(l==r)
{
tr[now].sum=0;
tr[now].col=l;
tr[now].box=-1;
return;
}
int mid=l+((r-l)>>1);
Build(now<<1,l,mid);
Build(now<<1|1,mid+1,r);
Pushup(now,l,r);
}
int Search_sum(int now,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr)
return tr[now].sum;
int mid=l+((r-l)>>1);
Pushdown(now,l,r);
int ans=-1;
if(rr<=mid)
ans=Search_sum(now<<1,l,mid,ll,rr);
if(ll>mid)
ans=Search_sum(now<<1|1,mid+1,r,ll,rr);
if(ans==-1)
ans=Search_sum(now<<1,l,mid,ll,mid)+Search_sum(now<<1|1,mid+1,r,mid+1,rr);
Pushup(now,l,r);
return ans;
}
void Update(int now,int l,int r,int ll,int rr,int val)
{
int mid=l+((r-l)>>1);
if(ll<=l&&r<=rr)
{
if(tr[now].col!=-1)
{
Push_add(now,l,r,abs(val-tr[now].col));
Push_box(now,l,r,val);
return;
}
Pushdown(now,l,r);
Update(now<<1,l,mid,ll,rr,val);
Update(now<<1|1,mid+1,r,ll,rr,val);
Pushup(now,l,r);
return;
}
Pushdown(now,l,r);
if(rr<=mid)
{
Update(now<<1,l,mid,ll,rr,val);
Pushup(now,l,r);
return;
}
if(ll>mid)
{
Update(now<<1|1,mid+1,r,ll,rr,val);
Pushup(now,l,r);
return;
}
Update(now<<1,l,mid,ll,mid,val);
Update(now<<1|1,mid+1,r,mid+1,rr,val);
Pushup(now,l,r);
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&m);
Build(1,1,n);
for(int i=1;i<=m;++i)
{
int opt,l,r,x;
scanf("%lld%lld%lld",&opt,&l,&r);
if(opt==1)
{
scanf("%lld",&x);
Update(1,1,n,l,r,x);
}
if(opt==2)
printf("%lld\n",Search_sum(1,1,n,l,r));
}
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
推导公式
最后树状数组实现区间修改,区间查询
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 1000007
#define M 1000007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m;
int a[N],b[N],lst[N],d[N];
int tr1[N<<2],tr2[N<<2];
int lowbit(int x)
{
return x&(-x);
}
void Add(int x,int k)
{
int tmp=x;
while(x<=n)
{
tr1[x]+=k;
tr2[x]+=k*tmp;
x+=lowbit(x);
}
}
int Search(int x)
{
int ans=0,tmp=x;
while(x)
{
ans+=tr1[x]*(tmp+1)-tr2[x];
x-=lowbit(x);
}
return ans;
}
bool Solve()
{
scanf("%lld",&n);
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
b[i-1]=a[i];
}
sort(b,b+n);
m=unique(b,b+n)-b;
for(int i=1;i<=n;++i)
{
a[i]=lower_bound(b,b+m,a[i])-b;
lst[i]=d[a[i]];
d[a[i]]=i;
}
int ans=0,now=0;
for(int i=1;i<=n;++i)
{
now=(now+i-lst[i]+2*(Search(i)-Search(lst[i])))%mod;
ans=(ans+now)%mod;
Add(lst[i]+1,1);
Add(i+1,-1);
}
printf("%lld\n",ans);
return 1;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
对着题解写的,自己写目前写不出,之后再来补一下这个题
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 200007
#define M 1000007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Line
{
int x,ymn,ymx,tag;
}line[N];
struct Tree
{
int cnt,len;
}tr[N*6];
int T=1,n,m,lcnt,cnt;
int rk[N],val[N];
bool Cmp(Line x,Line y)
{
return x.x<y.x;
}
void Pushup(int now,int l,int r)
{
if(tr[now].cnt)
tr[now].len=val[r+1]-val[l];
else
tr[now].len=tr[now<<1].len+tr[now<<1|1].len;
}
void Add(int now,int l,int r,int ll,int rr,int val)//线段树中[l,r]表示val[l]~val[r+1]这个区间
{//目的是为了使线段树的区间都与题意匹配
if(ll<=l&&r<=rr)
{
tr[now].cnt+=val;
Pushup(now,l,r);
return;
}
int mid=l+((r-l)>>1);//不需要Pushdown,因此子节点信息是错误的,但是由于只需要知道根节点信息,因此只需要往上更新
if(ll<=mid)
Add(now<<1,l,mid,ll,rr,val);
if(rr>mid)
Add(now<<1|1,mid+1,r,ll,rr,val);
Pushup(now,l,r);
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
{
int x1,x2,y1,y2;
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
line[++lcnt]=(Line){x1,min(y1,y2),max(y1,y2),1};
line[++lcnt]=(Line){x2,min(y1,y2),max(y1,y2),-1};
rk[++cnt]=y1;rk[++cnt]=y2;
}
sort(rk+1,rk+1+cnt);
m=unique(rk+1,rk+1+cnt)-rk-1;
cnt=0;
for(int i=1;i<=lcnt;++i)
{
int pos1=lower_bound(rk+1,rk+1+m,line[i].ymx)-rk;
int pos2=lower_bound(rk+1,rk+1+m,line[i].ymn)-rk;
val[pos1]=line[i].ymx;
val[pos2]=line[i].ymn;
line[i].ymx=pos1,line[i].ymn=pos2;
cnt=max(cnt,pos1);
}
sort(line+1,line+1+lcnt,Cmp);
int ans=0;
for(int i=1;i<lcnt;++i)
{
Add(1,1,lcnt,line[i].ymn,line[i].ymx-1,line[i].tag);
ans+=tr[1].len*(line[i+1].x-line[i].x);
}
printf("%lld\n",ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
有点毒瘤,之后再来做一次
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 200007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m;
int tr[N<<2];
int before[N],record[N],a[N];//before[i]表示位置i的数a[i]的前面,有多少个数比它大
int lowbit(int x)//record[i]表示,有i个数在前面比它大的数的数量
{
return x&(-x);
}
void Add(int x,int k)
{
while(x<=n)
{
tr[x]+=k;
x+=lowbit(x);
}
}
int Search(int x)
{
int ans=0;
while(x)
{
ans+=tr[x];
x-=lowbit(x);
}
return ans;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&m);
int sum=0;
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
before[i]=i-1-Search(a[i]);
sum+=before[i];
++record[before[i]];
Add(a[i],1);
}
memset(tr,0,sizeof(tr));
Add(1,sum);
sum=0;
for(int i=1;i<=n;++i)
{
sum+=record[i-1];
Add(i+1,-(n-sum));
}
for(int i=1;i<=m;++i)
{
int opt,x;
scanf("%lld%lld",&opt,&x);
x=min(x,n-1);
if(opt==1)
{
if(a[x]<a[x+1])
{
swap(a[x],a[x+1]);
swap(before[x],before[x+1]);
++before[x+1];
Add(before[x+1]+1,-1);
Add(1,1);
}
else
{
swap(a[x],a[x+1]);
swap(before[x],before[x+1]);
Add(before[x]+1,1);
--before[x];
Add(1,-1);
}
}
else
printf("%lld\n",Search(x+1));
}
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
![P6186 P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并
动态开点线段树+线段树合并+树上差分
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 19
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt;
}edge[N<<1];
struct Tree
{
int ls,rs,sum,mxnum;
}tr[N*80];
int T=1,n,m,ecnt,tcnt;
int head[N],fa[N][M],dep[N],rt[N],ans[N];
void Add(int u,int v)
{
edge[++ecnt]={v,head[u]};
head[u]=ecnt;
}
void Dfs(int u,int father)
{
fa[u][0]=father;
dep[u]=dep[father]+1;
for(int i=1;i<M;++i)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==father)
continue;
Dfs(v,u);
}
}
int Get_lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=M-1;i>=0;--i)
if(dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if(x==y) return x;
for(int i=M-1;i>=0;--i)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void Pushup(int now)
{
if(!tr[now].ls)
{
tr[now].sum=tr[tr[now].rs].sum;
tr[now].mxnum=tr[tr[now].rs].mxnum;
return;
}
if(!tr[now].rs)
{
tr[now].sum=tr[tr[now].ls].sum;
tr[now].mxnum=tr[tr[now].ls].mxnum;
return;
}
if(tr[tr[now].ls].sum>=tr[tr[now].rs].sum)
{
tr[now].sum=tr[tr[now].ls].sum;
tr[now].mxnum=tr[tr[now].ls].mxnum;
}
else
{
tr[now].sum=tr[tr[now].rs].sum;
tr[now].mxnum=tr[tr[now].rs].mxnum;
}
}
void Update(int &now,int l,int r,int pos,int val)
{
if(!now) now=++tcnt;
if(l==r)
{
tr[now].sum+=val;
tr[now].mxnum=pos;
return;
}
int mid=l+((r-l)>>1);
if(pos<=mid) Update(tr[now].ls,l,mid,pos,val);
else Update(tr[now].rs,mid+1,r,pos,val);
Pushup(now);
}
int Merge(int x,int y,int l,int r)
{
if(!x||!y) return x+y;
if(l==r)
{
tr[x].sum+=tr[y].sum;
return x;
}
int mid=l+((r-l)>>1);
tr[x].ls=Merge(tr[x].ls,tr[y].ls,l,mid);
tr[x].rs=Merge(tr[x].rs,tr[y].rs,mid+1,r);
Pushup(x);
return x;
}
void Search(int u,int father)
{
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==father)
continue;
Search(v,u);
rt[u]=Merge(rt[u],rt[v],1,100000);
}
ans[u]=tr[rt[u]].mxnum;
if(tr[rt[u]].sum==0)
ans[u]=0;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&m);
for(int i=1;i<n;++i)
{
int in1,in2;
scanf("%lld%lld",&in1,&in2);
Add(in1,in2);
Add(in2,in1);
}
Dfs(1,0);
for(int i=1;i<=m;++i)
{
int in1,in2,in3;
scanf("%lld%lld%lld",&in1,&in2,&in3);
int lca=Get_lca(in1,in2);
Update(rt[in1],1,100000,in3,1);
Update(rt[in2],1,100000,in3,1);
Update(rt[lca],1,100000,in3,-1);
Update(rt[fa[lca][0]],1,100000,in3,-1);
}
Search(1,0);
for(int i=1;i<=n;++i)
printf("%lld\n",ans[i]);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
DP练习
暴力DP,
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 3007
#define M 500007
#define mod 100003
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m,k;
int f[N][N],ans[N][N];
string s,t;
void Print(int l,int r)
{
if(!l||!r)
return;
if(ans[l][r]==1)
{
Print(l-1,r-1);
printf("%c",s[l]);
}
if(ans[l][r]==2)
Print(l-1,r);
if(ans[l][r]==3)
Print(l,r-1);
}
bool Solve()
{
//freopen("test.in","r",stdin);
cin>>s>>t;
n=s.size();m=t.size();
s=" "+s,t=" "+t;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
if(s[i]==t[j])
{
f[i][j]=f[i-1][j-1]+1;
ans[i][j]=1;
continue;
}
if(f[i-1][j]>f[i][j-1])
{
f[i][j]=f[i-1][j];
ans[i][j]=2;
}
else
{
f[i][j]=f[i][j-1];
ans[i][j]=3;
}
}
Print(n,m);
printf("\n");
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
有限制的01背包,感觉结构体写的好繁杂。。。。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 40007
#define M 500007
#define mod 100003
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Node
{
int num,w,v;
bool fir;
int son[3];
void Init(int x,int y)
{
w=x,v=y;
}
}a[N];
int T=1,n,m,k,cnt;
int f[N];
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;++i)
{
int in1,in2,in3;
scanf("%lld%lld%lld",&in1,&in2,&in3);
a[i].Init(in1,in2);
if(!in3)
a[i].fir=1;
else
a[in3].son[++a[in3].num]=i;
}
for(int i=1;i<=m;++i)
{
if(!a[i].fir)
continue;
for(int j=n;j>=a[i].w;--j)
{
f[j]=max(f[j],f[j-a[i].w]+a[i].v*a[i].w);
if(a[i].num>=1&&j>=a[i].w+a[a[i].son[1]].w)
f[j]=max(f[j],f[j-a[i].w-a[a[i].son[1]].w]+a[i].w*a[i].v+a[a[i].son[1]].w*a[a[i].son[1]].v);
if(a[i].num>=2)
{
if(j>=a[i].w+a[a[i].son[1]].w+a[a[i].son[2]].w)
f[j]=max(f[j],f[j-a[i].w-a[a[i].son[1]].w-a[a[i].son[2]].w]+a[i].w*a[i].v+a[a[i].son[1]].w*a[a[i].son[1]].v+a[a[i].son[2]].w*a[a[i].son[2]].v);
if(j>=a[i].w+a[a[i].son[2]].w)
f[j]=max(f[j],f[j-a[i].w-a[a[i].son[2]].w]+a[i].w*a[i].v+a[a[i].son[2]].w*a[a[i].son[2]].v);
}
}
}
printf("%lld\n",f[n]);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
很经典的树形dp,没啥好说的
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 10007
#define M 500007
#define mod 100003
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt;
}edge[N<<1];
int T=1,n,ecnt;
int head[N],val[N],f[N][2];
void Add(int u,int v)
{
edge[++ecnt]=(Edge){v,head[u]};
head[u]=ecnt;
}
void Dp(int u,int fa)
{
f[u][1]=val[u];
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==fa)
continue;
Dp(v,u);
f[u][0]+=max(f[v][0],f[v][1]);
f[u][1]+=f[v][0];
}
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&val[i]);
for(int i=1;i<n;++i)
{
int u,v;
scanf("%lld%lld",&u,&v);
Add(u,v);
Add(v,u);
}
Dp(1,0);
printf("%lld\n",max(f[1][1],f[1][0]));
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
感觉题解有问题,但是问题也不是很大,子序列自动机,处理出nxt数组,进行记忆化搜索即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 157
#define M 27
#define mod 100000000
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,ecnt;
string a,b,c;
int la,lb,lc;
int nxta[N][M],nxtb[N][M],nxtc[N][M];
int f[N][N][N];
void Init_nxt(int nxt[N][M],int len,string x)
{
for(int i=len-1;i>=0;--i)
{
for(int j=0;j<26;++j)
nxt[i][j]=nxt[i+1][j];
nxt[i][x[i+1]-'a']=i+1;
}
}
int Dfs(int x,int y,int z)
{
if(f[x][y][z]) return f[x][y][z];
if(x&&y&&z)//个人理解是&&,虽然题解是||,只有同时不为0才表示当前这个字符也是个公共子序列
++f[x][y][z];//但是由于下面的if使得||也能通过,因为x,y,z必不为0(个人理解)
for(int i=0;i<26;++i)
if(nxta[x][i]&&nxtb[y][i]&&nxtc[z][i])
f[x][y][z]=(f[x][y][z]+Dfs(nxta[x][i],nxtb[y][i],nxtc[z][i]))%mod;
return f[x][y][z]%mod;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
cin>>a>>b>>c;
la=a.size(),lb=b.size(),lc=c.size();
a=" "+a,b=" "+b,c=" "+c;
Init_nxt(nxta,la,a);
Init_nxt(nxtb,lb,b);
Init_nxt(nxtc,lc,c);
printf("%lld\n",Dfs(0,0,0)%mod);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
对于我来说还是有点难想到
合法的匹配一定是外面若干层,每一层都是若干个等长的圆弧,最里面一层为若干个等长的圆弧。(引用)
由于每个圆弧要等长,所以假设要匹配 l 个圆弧,则每个圆弧的长度必须是 l 的因数。而对于每一确定的长度,则有唯一对应的一种匹配的方案。所以内层的方案数为 d(l)。(引用)
先把n个点分成里外两部分,里面这部分是等大互不相交的,外面的方案数是(供我自己理解,解释需要图,不想画了)
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 1000007
#define M 27
#define mod 998244353
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,ecnt;
int d[N];
int Pow(int x,int y)
{
int ans=1,cnt=x;
while(y)
{
if(y&1)
ans*=cnt;
cnt*=cnt;
ans%=mod;
cnt%=mod;
y>>=1;
}
return ans;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;++i)
for(int j=i;j<=n;j+=i) ++d[j];
int ans=0;
for(int i=1;i<=n;++i)
ans=(ans+Pow(2,max(n-i-1,(int)0))*d[i]%mod)%mod;
printf("%lld\n",ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
树形背包,要注意初始化负无穷
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 3007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt,cst;
}edge[N<<1];
int T=1,n,m,ecnt;
int val[N],head[N],f[N][N];
void Add(int u,int v,int w)
{
edge[++ecnt]=(Edge){v,head[u],w};
head[u]=ecnt;
}
int Dp(int u,int fa)
{
if(u>n-m)
{
f[u][1]=val[u];
return 1;
}
int num=0;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==fa) continue;
int now=Dp(v,u);
num+=now;
for(int j=num;j>=0;--j)
for(int k=0;k<=now;++k)
if(j-k>=0)
f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]-edge[i].cst);
}
return num;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n-m;++i)
{
int in1;
scanf("%lld",&in1);
for(int j=1;j<=in1;++j)
{
int in2,in3;
scanf("%lld%lld",&in2,&in3);
Add(i,in2,in3);
Add(in2,i,in3);
}
}
for(int i=n-m+1;i<=n;++i)
scanf("%lld",&val[i]);
memset(f,inc,sizeof(f));
for(int i=1;i<=n;++i)
f[i][0]=0;
Dp(1,0);
for(int i=m;i;--i)
if(f[1][i]>=0)
{
printf("%lld\n",i);
return true;
}
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
经典状压,用滚动数组,记得要特判n=1时
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 107
#define M 10
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m;
int a[N][M],num[N],f[1<<M][1<<M][2];
int Get_num(int now)
{
int ans=0;
while(now)
{
if(now&1)
++ans;
now>>=1;
}
return ans;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
num[i]<<=1;
scanf(" %c",&a[i][j]);
if(a[i][j]=='H')
num[i]+=1;
}
if(n==1)
{
int ans=0;
for(int i=0;i<(1<<m);++i)
{
if((i&num[1])||(i&(i>>1))||(i&(i>>2)))
continue;
ans=max(ans,Get_num(i));
}
printf("%lld\n",ans);
return 1;
}
for(int i=0;i<(1<<m);++i)
{
for(int j=0;j<(1<<m);++j)
{
if((j&num[2])||(j&(j>>1))||(j&(j>>2))||(i&j))
continue;
f[j][i][0]=Get_num(j)+Get_num(i);
}
}
for(int i=3;i<=n;++i)
{
for(int now=0;now<(1<<m);++now)
{
if((now&num[i])||(now&(now>>1))||(now&(now>>2)))
continue;
int tmp=Get_num(now);
for(int lst2=0;lst2<(1<<m);++lst2)
{
if((lst2&num[i-2])||(lst2&(lst2>>1))||(lst2&(lst2>>2))||(now&lst2))
continue;
for(int lst1=0;lst1<(1<<m);++lst1)
{
if((lst1&num[i-1])||(lst1&(lst1>>1))||(lst1&(lst1>>2))||(lst1&lst2)||(now&lst1))
continue;
f[now][lst1][i%2]=max(f[now][lst1][i%2],f[lst1][lst2][(i+1)%2]+tmp);
}
}
}
}
int ans=0;
for(int i=0;i<(1<<m);++i)
{
if((i&num[n-1])||(i&(i>>1))||(i&(i>>2)))
continue;
for(int j=0;j<(1<<m);++j)
{
if((j&num[n])||(j&(j>>1))||(j&(j>>2))||(i&j))
continue;
ans=max(ans,f[j][i][n%2]);
}
}
printf("%lld\n",ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
1 1
P
*/
题是真的恶心,被STL搞破防了好久,思路是倍增优化预处理,然后模拟
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 20
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Node
{
int id,val;
bool operator <(const Node x) const
{
return val<x.val;
}
};
int T=1,n,x0,m;
int a[N],nxt[N][M][2],disa[N][M][2],disb[N][M][2];//nxt[i][j][k]表示从第i个地方开始由k先开车,走$2^j$走到的地方
multiset<Node> st;
void Init()
{
st.insert((Node){n+1,(int)-inf});
st.insert((Node){n+1,(int)-inf});
st.insert((Node){0,(int)inf});
st.insert((Node){0,(int)inf});
for(int i=n;i;--i)
{
st.insert((Node){i,a[i]});
auto pos=st.lower_bound((Node){i,a[i]});
--pos;Node l1=*pos;--pos;Node l2=*pos;++pos;++pos;++pos;Node r1=*pos;++pos;Node r2=*pos;
if(abs(r1.val-a[i])<abs(l1.val-a[i]))
{
nxt[i][0][1]=r1.id;
disb[i][0][1]=abs(r1.val-a[i]);
if(abs(r2.val-a[i])<abs(l1.val-a[i]))
{
nxt[i][0][0]=r2.id;
disa[i][0][0]=abs(r2.val-a[i]);
}
else
{
nxt[i][0][0]=l1.id;
disa[i][0][0]=abs(l1.val-a[i]);
}
}
else
{
nxt[i][0][1]=l1.id;
disb[i][0][1]=abs(l1.val-a[i]);
if(abs(l2.val-a[i])<=abs(r1.val-a[i]))
{
nxt[i][0][0]=l2.id;
disa[i][0][0]=abs(l2.val-a[i]);
}
else
{
nxt[i][0][0]=r1.id;
disa[i][0][0]=abs(r1.val-a[i]);
}
}
}
for(int i=1;i<M;++i)
{
for(int j=1;j<=n;++j)
{
for(int k=0;k<=1;++k)
{
if(i==1)
{
nxt[j][i][k]=nxt[nxt[j][i-1][k]][i-1][k^1];
disa[j][i][k]=disa[nxt[j][i-1][k]][i-1][k^1]+disa[j][i-1][k];
disb[j][i][k]=disb[nxt[j][i-1][k]][i-1][k^1]+disb[j][i-1][k];
}
else
{
nxt[j][i][k]=nxt[nxt[j][i-1][k]][i-1][k];
disa[j][i][k]=disa[nxt[j][i-1][k]][i-1][k]+disa[j][i-1][k];
disb[j][i][k]=disb[nxt[j][i-1][k]][i-1][k]+disb[j][i-1][k];
}
}
}
}
}
int la,lb;
void Calc(int s,int len)
{
int now=s;
la=0,lb=0;
for(int i=M-1;i>=0;--i)
{
if(nxt[now][i][0]&&la+lb+disa[now][i][0]+disb[now][i][0]<=len)
{
la+=disa[now][i][0];
lb+=disb[now][i][0];
now=nxt[now][i][0];
}
}
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
scanf("%lld%lld",&x0,&m);
Init();
double ans=inf;
int pos=0;
for(int i=1;i<=n;++i)
{
Calc(i,x0);
double now=(double)la/((double)lb);
if(now<ans)
{
ans=now;pos=i;
}
else
if(ans==now&&a[pos]<a[i])
pos=i;
}
printf("%lld\n",pos);
for(int i=1;i<=m;++i)
{
int in1,in2;
scanf("%lld%lld",&in1,&in2);
Calc(in1,in2);
printf("%lld %lld\n",la,lb);
}
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
*/
滚动数组dp,f[i]表示序列长度为i时的方案数
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n;
int a[N],f[N*10];
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
f[0]=1;
for(int i=1;i<=n;++i)
{
vector<int> d;
int nn=sqrt(a[i]);
for(int j=1;j<=nn;++j)
if(a[i]%j==0)
{
int k=a[i]/j;
d.push_back(k);
if(k!=j)
d.push_back(j);
}
sort(d.begin(),d.end());
for(int j=d.size()-1;j>=0;--j)
{
f[d[j]]=f[d[j]]+f[d[j]-1];
f[d[j]]%=mod;
}
}
int ans=0;
for(int i=1;i<=n;++i)
ans+=f[i],ans%=mod;
printf("%lld\n",ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
真心想不到这个做法,挺玄乎的。
记录每个数最左端和最右端位置,找到最长的非递减序列,答案是数字类别总数-最长长度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 300007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n;
int a[N],l[N],r[N];
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
l[i]=0,r[i]=0;
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
if(!l[a[i]])
l[a[i]]=i;
r[a[i]]=i;
}
int cnt=0,last=0,sum=0,ans=0;
for(int i=1;i<=n;++i)
if(l[i])
{
if(last<l[i])
++cnt;
else
cnt=1;
ans=max(cnt,ans);
++sum;
last=r[i];
}
printf("%lld\n",sum-ans);
return true;
}
signed main()
{
scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
图论
虽然spfa死了,但不影响我继续用
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 300007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt,w;
}edge[M<<1];
int T=1,n,m,cnt;
int head[N],num[N],dis[N];
void Add(int u,int v,int w)
{
edge[++cnt]=(Edge){v,head[u],w};
head[u]=cnt;
}
bool Spfa(int s)
{
queue<int> dui;
dui.push(s);
num[s]=1;
dis[s]=0;
while(!dui.empty())
{
int u=dui.front();
dui.pop();
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].w)
{
dis[v]=dis[u]+edge[i].w;
++num[v];
if(num[v]>n)
return 1;
dui.push(v);
}
}
}
return 0;
}
bool Solve()
{
//freopen("test.in","r",stdin);
memset(num,0,sizeof(num));
memset(dis,0x3f3f3f3f,sizeof(dis));
memset(head,0,sizeof(head));
cnt=0;
//printf("%d %d\n",dis[0],inf);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;++i)
{
int u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
Add(u,v,w);
if(w>=0)
Add(v,u,w);
}
printf("%s\n",Spfa(1)?"YES":"NO");
return true;
}
signed main()
{
scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
将不等式看成最短路松弛,于是新建一个源点,与所有点连接,跑最短路,无环则有解
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 300007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt,w;
}edge[M<<1];
int T=1,n,m,ecnt;
int head[N],num[N],dis[N];
void Add(int u,int v,int w)
{
edge[++ecnt]=(Edge){v,head[u],w};
head[u]=ecnt;
}
bool Spfa(int s)
{
queue<int> que;
que.push(s);
num[s]=1;
dis[s]=0;
while(!que.empty())
{
int u=que.front();
que.pop();
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].w)
{
dis[v]=dis[u]+edge[i].w;
++num[v];
if(num[v]>n+1)
return 1;
que.push(v);
}
}
}
return 0;
}
bool Solve()
{
//freopen("test.in","r",stdin);
memset(dis,0x3f3f3f3f,sizeof(dis));
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;++i)
Add(0,i,0);
for(int i=1;i<=m;++i)
{
int u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
Add(v,u,w);
}
if(Spfa(0))
{
printf("NO\n");
return 1;
}
else
{
for(int i=1;i<=n;++i)
printf("%lld ",dis[i]);
printf("\n");
}
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
开了long long超时了。。调了好一会。
思路是拓扑排序得到拓扑序,无向边改为拓扑序小的节点指向拓扑序大的节点。
无解的情况显然为有向边成环的情况。
点击查看代码
#include<bits/stdc++.h>
//#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 200007
#define M 200007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt;
}edge[M];
int T=1,n,m,ecnt;
int head[N],indeg[N],tnum[N],a[M],b[M],c[M];
void Add(int u,int v)
{
edge[++ecnt]=(Edge){v,head[u]};
head[u]=ecnt;
++indeg[v];
}
bool Topo()
{
int cnt=0;
queue<int> que;
for(int i=1;i<=n;++i)
if(!indeg[i])
que.push(i);
while(!que.empty())
{
int u=que.front();
que.pop();
tnum[u]=++cnt;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
--indeg[v];
if(!indeg[v])
que.push(v);
}
}
return cnt==n;
}
bool Solve()
{
//freopen("test.in","r",stdin);
memset(head,0,sizeof(head));
memset(indeg,0,sizeof(indeg));
memset(tnum,0,sizeof(tnum));
ecnt=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&c[i],&a[i],&b[i]);
if(c[i])
Add(a[i],b[i]);
}
if(Topo())
{
printf("YES\n");
for(int i=1;i<=m;++i)
{
if(c[i])
printf("%d %d\n",a[i],b[i]);
else
{
if(tnum[a[i]]<tnum[b[i]])
printf("%d %d\n",a[i],b[i]);
else
printf("%d %d\n",b[i],a[i]);
}
}
}
else
printf("NO\n");
return true;
}
signed main()
{
scanf("%d",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
完全没想到用floyed,几年没用了,以后看到这种数据范围,以及要求每两个点的最短路有关的就要想到floyed
num[i][j]为i到j的最短路径条数
维护好后答案很好求了
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 107
#define M 4507
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m,ecnt;
int dis[N][N],num[N][N];
double ans[N];
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
dis[i][j]=(i==j)?0:inf;
for(int i=1;i<=m;++i)
{
int u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
dis[u][v]=dis[v][u]=w;
num[u][v]=num[v][u]=1;
}
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
if(dis[i][k]==inf||dis[k][j]==inf)
continue;
if(dis[i][j]>dis[i][k]+dis[k][j])
{
dis[i][j]=dis[i][k]+dis[k][j];
num[i][j]=num[i][k]*num[k][j];
continue;
}
if(dis[i][j]==dis[i][k]+dis[k][j])
num[i][j]+=num[i][k]*num[k][j];
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
if(i==j)
continue;
for(int k=1;k<=n;++k)
{
if(i==k||j==k)
continue;
if(dis[i][j]==dis[i][k]+dis[k][j])
ans[k]+=(((double)num[i][k])*((double)num[k][j]))/((double)num[i][j]);
}
}
for(int i=1;i<=n;++i)
printf("%.3lf\n",ans[i]);
return true;
}
signed main()
{
//scanf("%d",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
还是第一次做同余类最短路,这个数组大小WA了几次,觉得下面这个题解讲的很清楚了,自己就不多废话了,反正也不是自己想出来的做法
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 1000007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m;
int a[N],dis[N];
bool vis[N];
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
int nn=n;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(a[i]-j>0)
a[++nn]=a[i]-j;
sort(a+1,a+nn+1);
int ok=1;
for(int i=2;i<=nn;++i)
if(a[i]%a[1]!=0)
{
ok=0;
break;
}
if(ok)
return 0;
nn=unique(a+1,a+nn+1)-a-1;
memset(dis,0x3f,sizeof(dis));
dis[0]=0;
queue<int> que;
que.push(0);
vis[0]=1;
while(!que.empty())
{
int u=que.front();
que.pop();
for(int i=2;i<=nn;++i)
if(dis[(u+a[i])%a[1]]>dis[u]+a[i])
{
dis[(u+a[i])%a[1]]=dis[u]+a[i];
if(!vis[(u+a[i])%a[1]])
{
vis[(u+a[i])%a[1]]=1;
que.push((u+a[i])%a[1]);
}
}
vis[u]=0;
}
int ans=0;
for(int i=1;i<a[1];++i)
ans=max(ans,dis[i]);
printf("%lld\n",ans-a[1]);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
和差分约束模板题差不多,只需要记住当Xa-Xb<=c时,连一条从b到a权值为c的边,如果是相等则互相连一条权值为0的边
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 300007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt,w;
}edge[M<<1];
int T=1,n,m,ecnt;
int head[N],num[N],dis[N];
void Add(int u,int v,int w)
{
edge[++ecnt]=(Edge){v,head[u],w};
head[u]=ecnt;
}
bool Spfa(int s)
{
queue<int> que;
que.push(s);
num[s]=1;
dis[s]=0;
while(!que.empty())
{
int u=que.front();
que.pop();
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].w)
{
dis[v]=dis[u]+edge[i].w;
++num[v];
if(num[v]>n+2)
return 1;
que.push(v);
}
}
}
return 0;
}
bool Solve()
{
//freopen("test.in","r",stdin);
memset(dis,0x3f3f3f3f,sizeof(dis));
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;++i)
Add(0,i,0),Add(i,n+1,0);
for(int i=1;i<=m;++i)
{
int opt,u,v,w;
scanf("%lld",&opt);
if(opt==1)
{
scanf("%lld%lld%lld",&u,&v,&w);
Add(u,v,-w);
}
if(opt==2)
{
scanf("%lld%lld%lld",&u,&v,&w);
Add(v,u,w);
}
if(opt==3)
{
scanf("%lld%lld",&u,&v);
Add(v,u,0);
Add(u,v,0);
}
}
if(Spfa(0))
printf("No\n");
else
printf("Yes\n");
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
分层最短路模板
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt,dis;
}edge[M*17];
struct Node
{
int val,id;
bool operator < (const Node x) const
{
return val>x.val;
};
}num[N];
int T=1,n,m,k,s,t,ecnt;
int head[N*17],dis[N*17];
bool vis[N*17];
int Dij()
{
priority_queue<Node> pque;
pque.push((Node){0,s});
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
while(!pque.empty())
{
int u=pque.top().id;
pque.pop();
if(vis[u])
continue;
vis[u]=1;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].dis)
{
dis[v]=dis[u]+edge[i].dis;
pque.push((Node){dis[v],v});
}
}
}
}
void Add(int u,int v,int w)
{
edge[++ecnt]=(Edge){v,head[u],w};
head[u]=ecnt;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld%lld%lld%lld",&n,&m,&k,&s,&t);
for(int i=1;i<=m;++i)
{
int u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
for(int j=0;j<=k;++j)
{
Add(u+j*n,v+j*n,w);
Add(v+j*n,u+j*n,w);
}
for(int j=1;j<=k;++j)
{
Add(u+(j-1)*n,v+j*n,0);
Add(v+(j-1)*n,u+j*n,0);
}
}
for(int i=1;i<=k;++i)
{
Add(t+(i-1)*n,t+i*n,0);
}
Dij();
//for(int i=1;i<=n;++i)
// printf("%lld\n",dis[i]);
printf("%lld\n",dis[t+k*n]);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
同余类最短路,记dis[i]为通过第二和第三种操作到达的最小楼层h,其中h%x=i。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt,dis;
}edge[M];
struct Node
{
int val,id;
bool operator < (const Node x) const
{
return val>x.val;
};
}num[N];
int T=1,n,x,y,z,ecnt;
int head[N],dis[N];
bool vis[N];
int Dij()
{
priority_queue<Node> pque;
pque.push((Node){1,1});
memset(dis,0x3f,sizeof(dis));
dis[1]=1;//同余类最短路,记dis[i]为通过第二和第三种操作到达的最小楼层h,其中h%x=i。
while(!pque.empty())
{
int u=pque.top().id;
pque.pop();
if(vis[u])
continue;
vis[u]=1;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].dis)
{
dis[v]=dis[u]+edge[i].dis;
pque.push((Node){dis[v],v});
}
}
}
}
void Add(int u,int v,int w)
{
edge[++ecnt]=(Edge){v,head[u],w};
head[u]=ecnt;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld%lld%lld",&n,&x,&y,&z);
if(x==1||y==1||z==1)
{
printf("%lld\n",n);
return 1;
}
for(int i=0;i<x;++i)
{
Add(i,(i+y)%x,y);
Add(i,(i+z)%x,z);
}
Dij();
int ans=0;
for(int i=0;i<x;++i)
if(dis[i]<=n)
ans+=(n-dis[i])/x+1;
printf("%lld\n",ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
和上面那个分层最短路一模一样,不多废话了
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt,dis;
}edge[M*27];
struct Node
{
int val,id;
bool operator < (const Node x) const
{
return val>x.val;
};
};
int T=1,n,m,k,s,t,ecnt;
int head[N*27],dis[N*27];
bool vis[N*27];
int Dij()
{
priority_queue<Node> pque;
pque.push((Node){0,s});
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
while(!pque.empty())
{
int u=pque.top().id;
pque.pop();
if(vis[u])
continue;
vis[u]=1;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].dis)
{
dis[v]=dis[u]+edge[i].dis;
pque.push((Node){dis[v],v});
}
}
}
}
void Add(int u,int v,int w)
{
edge[++ecnt]=(Edge){v,head[u],w};
head[u]=ecnt;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld%lld",&n,&m,&k);
s=1,t=n;
for(int i=1;i<=m;++i)
{
int u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
for(int j=0;j<=k;++j)
{
Add(u+j*n,v+j*n,w);
Add(v+j*n,u+j*n,w);
}
for(int j=1;j<=k;++j)
{
Add(u+(j-1)*n,v+j*n,0);
Add(v+(j-1)*n,u+j*n,0);
}
}
for(int i=1;i<=k;++i)
Add(t+(i-1)*n,t+i*n,0);
Dij();
//for(int i=1;i<=n;++i)
// printf("%lld\n",dis[i]);
printf("%lld\n",dis[t+k*n]);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
显然BFS搜索树会优,看到数据范围提示可以每个点做根来一次BFS,但是统计答案确实是没想到,下面有种这种统计方法的解释
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 500007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt;
}edge[M];
int T=1,n,ecnt;
int head[N],dep[N];
bool vis[N];
int Bfs(int s)
{
int sum=1,cnt=1;
queue<int> que;
memset(dep,0,sizeof(dep));
memset(vis,0,sizeof(vis));
que.push(s);
vis[s]=1;
dep[s]=1;
while(!que.empty())
{
int u=que.front();
que.pop();
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(vis[v])
continue;
vis[v]=1;
dep[v]=dep[u]+1;
sum+=dep[v];
++cnt;
que.push(v);
}
}
return cnt<n?inf:sum;
}
void Add(int u,int v)
{
edge[++ecnt]=(Edge){v,head[u]};
head[u]=ecnt;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
{
int opt;
scanf("%lld",&opt);
for(int j=1;j<=opt;++j)
{
int in;
scanf("%lld",&in);
Add(in,i);
}
}
int ans=inf;
for(int i=1;i<=n;++i)
ans=min(ans,Bfs(i));
printf("%lld\n",ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
非常有意义的一个题,思路是拓扑+dij最短路。
道路和航线分别存图,道路图为很多个正权连通块,里面进行dij最短路。
再用拓扑来从一个连通块传到下一个连通块
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 25007
#define M 50007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
int to,nxt,dis;
}edge1[M<<1],edge2[M];
struct Node
{
int dis,id;
bool operator <(const Node a)const
{
return dis>a.dis;
}
};
int T=1,n,m1,m2,s,ecnt1,ecnt2,bcnt;
int belong[N],dis[N],indeg[N];
bool vis[N];
int head1[N],head2[N];
vector<int> vec[N];
void Add1(int u,int v,int w)
{
edge1[++ecnt1]=(Edge){v,head1[u],w};
head1[u]=ecnt1;
}
void Add2(int u,int v,int w)
{
edge2[++ecnt2]=(Edge){v,head2[u],w};
head2[u]=ecnt2;
}
void Dfs(int u,int num)
{
belong[u]=num;
vec[num].push_back(u);
for(int i=head1[u];i;i=edge1[i].nxt)
{
int v=edge1[i].to;
if(belong[v])
continue;
Dfs(v,num);
}
}
void Topo_dij()
{
for(int i=1;i<=ecnt2;++i)
++indeg[belong[edge2[i].to]];
queue<int> que;
for(int i=1;i<=bcnt;++i)
if(!indeg[i])
que.push(i);
dis[s]=0;
while(!que.empty())
{
int now=que.front();
que.pop();
priority_queue<Node> kque;
for(int i=0;i<vec[now].size();++i)
if(dis[vec[now][i]]<dis[0])
kque.push((Node){dis[vec[now][i]],vec[now][i]});
while(!kque.empty())
{
int u=kque.top().id;
kque.pop();
if(vis[u])
continue;
vis[u]=1;
for(int i=head1[u];i;i=edge1[i].nxt)
{
int v=edge1[i].to;
if(dis[v]>dis[u]+edge1[i].dis)
{
dis[v]=dis[u]+edge1[i].dis;
kque.push((Node){dis[v],v});
}
}
for(int i=head2[u];i;i=edge2[i].nxt)
{
int v=edge2[i].to;
if(dis[v]>dis[u]+edge2[i].dis)
dis[v]=dis[u]+edge2[i].dis;
}
}
for(int i=0;i<vec[now].size();++i)
{
for(int j=head2[vec[now][i]];j;j=edge2[j].nxt)
{
int v=edge2[j].to;
--indeg[belong[v]];
if(!indeg[belong[v]])
que.push(belong[v]);
}
}
}
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld%lld%lld",&n,&m1,&m2,&s);
for(int i=1;i<=m1;++i)
{
int u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
Add1(u,v,w);
Add1(v,u,w);
}
for(int i=1;i<=m2;++i)
{
int u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
Add2(u,v,w);
}
for(int i=1;i<=n;++i)
if(!belong[i])
Dfs(i,++bcnt);
memset(dis,0x3f,sizeof(dis));
Topo_dij();
for(int i=1;i<=n;++i)
if(dis[i]>=dis[0])
printf("NO PATH\n");
else
printf("%lld\n",dis[i]);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
数论
欧拉筛板子
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100000007
#define M 10000007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m,ecnt;
int a[N],prime[N];
bool vis[N];
void Prim()
{
int cnt=0;
vis[0]=vis[1]=1;
for(int i=2;i<=n+7;++i)
{
if(!vis[i])//不是目前找到的素数的倍数
prime[++cnt]=i;//找到素数~
for(int j=1;j<=cnt&&i*prime[j]<=n+7;++j)
{
vis[i*prime[j]]=1;//找到的素数的倍数不访问
if(i%prime[j]==0)
break;//关键!!!!
}
}
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&m);
Prim();
for(int i=1;i<=m;++i)
{
int in;
scanf("%lld",&in);
printf("%lld\n",prime[in]);
}
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
没话讲,希望以后还能记得怎么做,感觉不太现实,就记住Exgcd能求ax+by=gcd(a,b)的一组特解算了。。。。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 300007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,x,y,X,Y;
void Exgcd(int a,int b)
{
if(!b)
{
x=1;
y=0;
return;
}
Exgcd(b,a%b);
X=y;
Y=x-a/b*y;
x=X;
y=Y;
}
int Get_gcd(int x,int y)
{
return y==0?x:Get_gcd(y,x%y);
}
bool Solve()
{
//freopen("test.in","r",stdin);
int a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
x=0,y=0;
Exgcd(a,b);
int gcd=Get_gcd(a,b);
if(c%gcd!=0)
return 0;
x*=c/gcd,y*=c/gcd;
int p=b/gcd,q=a/gcd,k=0;
if(x<0)
k=ceil((1.0-x)/p),x+=p*k,y-=q*k;
if(x>=0)
k=(x-1)/p,x-=p*k,y+=q*k;
if(y>0)
printf("%lld %lld %lld %lld %lld\n",(y-1)/q+1,x,(y-1)%q+1,x+(y-1)/q*p,y);
else
printf("%lld %lld\n",x,y+q*((int)ceil((1.0-y)/q)));
return true;
}
signed main()
{
scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
记结论算了
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 500007
//#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m,mod;
int Pow(int x,int y)
{
int ans=1,cnt=x;
while(y)
{
if(y&1)
ans*=cnt,ans%=mod;
cnt*=cnt;
cnt%=mod;
y>>=1;
}
return ans%mod;
}
int C(int a,int b)//模mod意义下求组合数
{
if(a<b)
return 0;
if(b>a-b) b=a-b;
int x=1,y=1;
for(int i=0;i<b;++i)
{
x=(x*(a-i))%mod;
y=(y*(i+1))%mod;
}
return x*Pow(y,mod-2)%mod;
}
int Lucas(int a,int b)
{
if(b==0)
return 1;
return Lucas(a/mod,b/mod)*C(a%mod,b%mod)%mod;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld%lld",&n,&m,&mod);
printf("%lld\n",Lucas(n+m,m));
return true;
}
signed main()
{
scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
方法一:高斯消元法,消成上三角矩阵
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 107
#define M 500007
//#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m,mod;
double g[N][N],ans[N];
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
for(int j=1;j<=n+1;++j)
scanf("%lf",&g[i][j]);
for(int i=1;i<=n;++i)
{
int pos=i;
for(int j=i+1;j<=n;++j)
if(fabs(g[pos][i])<fabs(g[j][i]))
pos=j;
if(fabs(g[pos][i])<1e-7)
{
printf("No Solution\n");
return 1;
}
if(pos!=i)
swap(g[pos],g[i]);
double div=g[i][i];
for(int j=i;j<=n+1;++j)//当前方程,前面的未知数已经消去
g[i][j]/=div;
for(int j=i+1;j<=n;++j)//下面的所有方程消去当前系数
{
div=g[j][i];
for(int k=i;k<=n+1;++k)
g[j][k]-=g[i][k]*div;
}
}
ans[n]=g[n][n+1];
for(int i=n-1;i;--i)
{
ans[i]=g[i][n+1];
for(int j=i+1;j<=n;++j)
ans[i]-=g[i][j]*ans[j];
}//回带求出答案
for(int i=1;i<=n;++i)
printf("%.2lf\n",ans[i]);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
方法二:高斯约旦消元法,消成对角矩阵(可以说类单位矩阵???哈哈哈)
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 107
#define M 500007
//#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m,mod;
double g[N][N];
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
for(int j=1;j<=n+1;++j)
scanf("%lf",&g[i][j]);
for(int i=1;i<=n;++i)
{
int pos=i;
for(int j=i+1;j<=n;++j)
if(fabs(g[pos][i])<fabs(g[j][i]))
pos=j;
if(fabs(g[pos][i])<1e-7)
{
printf("No Solution\n");
return 1;
}
if(pos!=i)
swap(g[pos],g[i]);
for(int j=1;j<=n;++j)//把其他行系数变为0
{
if(i==j)
continue;
double tmp=g[j][i]/g[i][i];
for(int k=i+1;k<=n+1;++k)
g[j][k]-=g[i][k]*tmp;
}
}
for(int i=1;i<=n;++i)
printf("%.2lf\n",g[i][n+1]/g[i][i]); //除以系数
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
高斯约旦法求矩阵的逆
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 1007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m;
int g[N][N];
int Pow(int x,int y)
{
int ans=1,cnt=x;
while(y)
{
if(y&1)
ans*=cnt,ans%=mod;
cnt*=cnt;
cnt%=mod;
y>>=1;
}
return ans%mod;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
scanf("%lld",&g[i][j]);
g[i][n+i]=1;
}
for(int i=1;i<=n;++i)
{
int pos=i;
for(int j=i+1;j<=n;++j)
if(abs(g[pos][i])<abs(g[j][i]))
pos=j;
if(!g[pos][i])
{
printf("No Solution\n");
return 1;
}
if(pos!=i)
swap(g[pos],g[i]);
int inv=Pow(g[i][i],mod-2);
for(int j=1;j<=n;++j)//把其他行系数变为0
{
if(i==j)
continue;
int tmp=g[j][i]*inv%mod;
for(int k=i;k<=(n<<1);++k)
g[j][k]=((g[j][k]-g[i][k]*tmp)%mod+mod)%mod;
}
for(int j=1;j<=(n<<1);++j)
g[i][j]=g[i][j]*inv%mod;
}
for(int i=1;i<=n;++i)
{
for(int j=n+1;j<=(n<<1);++j)
printf("%lld ",g[i][j]);
printf("\n");
}
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 1007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m,x,y,X,Y;
int a[N],b[N];
void Exgcd(int a,int b)
{
if(!b)
{
x=1;
y=0;
return;
}
Exgcd(b,a%b);
X=y;
Y=x-a/b*y;
x=X;
y=Y;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
int sum=1;
for(int i=1;i<=n;++i)
scanf("%lld%lld",&a[i],&b[i]),sum*=a[i];
int ans=0;
for(int i=1;i<=n;++i)
{
int now=sum/a[i];
Exgcd(now,a[i]);//求逆元,x是a%b意义下的逆元
if(x<0)
x+=a[i];
ans+=x*now*b[i];
}
printf("%lld\n",ans%sum);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
推式子
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 1007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n;
int a[N];
bool Solve()
{
//freopen("test.in","r",stdin);
for(int i=1;i<=7;++i)
{
scanf("%lld",&a[i]);
n+=a[i];
}
double ans=a[1]*1.0/n*a[2]/(n-1)*a[3]/(n-2)*a[4]/(n-3)*a[5]/(n-4)*a[6]/(n-5)*a[7]*5040;
printf("%.3lf\n",ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
收获就是掌握最大公约数和最小公倍数的约束条件吧!
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 1007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n;
int Get_gcd(int x,int y)
{
return y==0?x:Get_gcd(y,x%y);
}
bool Solve()
{
//freopen("test.in","r",stdin);
int a0,a1,b0,b1;
scanf("%lld%lld%lld%lld",&a0,&a1,&b0,&b1);
int ans=0,p=a0/a1,q=b1/b0;
for(int i=1;i*i<=b1;++i)
if(b1%i==0)
{
if(i%a1==0&&Get_gcd(i/a1,p)==1&&Get_gcd(q,b1/i)==1)
++ans;
int x=b1/i;
if(x==i)
continue;
if(x%a1==0&&Get_gcd(x/a1,p)==1&&Get_gcd(q,b1/x)==1)
++ans;
}
printf("%lld\n",ans);
return true;
}
signed main()
{
scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
一语惊醒梦中人
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 1000007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n;
int a[N];
bool vis[N];
int Get_gcd(int x,int y)
{
return y==0?x:Get_gcd(y,x%y);
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
vis[a[i]]=1;
}
int ans=0;
for(int i=1;i<=N-7;++i)
{
int gcd=-1;
if(vis[i])
continue;
for(int j=1;j*i<=N-7;++j)
{
if(!vis[i*j])
continue;
if(gcd==-1)
gcd=j*i;
else
gcd=Get_gcd(gcd,i*j);
}
if(gcd==i)
++ans;
}
printf("%lld\n",ans);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 1000007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,m,k;
int a[N],phi[N],prime[N];
bool vis[N],flag[N];
void Euler(int mxn)
{
int num=0;
phi[1]=1;//1要特判
for(int i=2;i<=mxn;i++)
{
if(flag[i]==0)//这代表i是质数
{
prime[++num]=i;
phi[i]=i-1;
}
for(int j=1;j<=num&&prime[j]*i<=mxn;j++)//经典的欧拉筛写法
{
flag[i*prime[j]]=1;//先把这个合数标记掉
if (i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];//若prime[j]是i的质因子,则根据计算公式,i已经包括i*prime[j]的所有质因子
break;//经典欧拉筛的核心语句,这样能保证每个数只会被自己最小的因子筛掉一次
}
else
phi[i*prime[j]]=phi[i]*phi[prime[j]];//利用了欧拉函数是个积性函数的性质
}
}
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld",&n);
if(n==1)
{
printf("0\n");
return 1;
}
Euler(n);
int ans=0;
for(int i=1;i<n;++i)
ans+=phi[i];
printf("%lld\n",ans*2+1);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
容斥+组合数
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 1000007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,s;
int inv[N],a[N];
void Get_inv(int mxn)
{
inv[1]=1;
for(int i=2;i<=mxn;++i)
inv[i]=inv[mod%i]*(mod-mod/i)%mod;
}
int C(int y,int x)//模mod意义下求组合数 y在下
{
if(y<0||x<0||y<x)
return 0;
y%=mod;
if(y==0||x==0)
return 1;
int ans=1;
for(int i=0;i<x;++i)
ans=ans*(y-i)%mod;
for(int i=1;i<=x;++i)
ans=ans*inv[i]%mod;
return ans;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&s);
Get_inv(N-7);
int ans=C(n+s-1,n-1);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
for(int i=1;i<(1<<n);++i)
{
int tmp=n+s,num=0;
for(int j=0;j<n;++j)
if(i>>j&1)
++num,tmp-=a[j+1];
tmp-=num+1;
if(num&1)
ans=(ans-C(tmp,n-1))%mod;
else
ans=(ans+C(tmp,n-1))%mod;
}
printf("%lld\n",(ans+mod)%mod);
return true;
}
signed main()
{
//scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 200007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
int T=1,n,k;
int fac[N],invfac[N];
int Pow(int x,int y)
{
int ans=1,cnt=x;
while(y)
{
if(y&1)
ans*=cnt,ans%=mod;
cnt*=cnt;
cnt%=mod;
y>>=1;
}
return ans%mod;
}
int C(int a,int b)
{
return (fac[a]*invfac[b]%mod)*invfac[a-b]%mod;
}
void Init()
{
fac[0]=invfac[0]=1;
for(int i=1;i<=N-7;++i)
fac[i]=1ll*fac[i-1]*i%mod;
invfac[N-7]=Pow(fac[N-7],mod-2);
for(int i=N-8;i;--i)
invfac[i]=1ll*invfac[i+1]*(i+1)%mod;
}
bool Solve()
{
//freopen("test.in","r",stdin);
scanf("%lld%lld",&n,&k);
if(n&1)
{
int tmp=1;
for(int i=1;i<=((n+1)>>1);++i)
tmp=(tmp+C(n,2*i-1))%mod;
printf("%lld\n",Pow(tmp,k));
}
else
{
int tmp=0,t1=0,t2=0;
for(int i=2;i<=n;i+=2)
t1=(t1+C(n,i))%mod;
for(int i=1;i<=n;i+=2)
t2=(t2+C(n,i))%mod;
for(int i=1;i<=k;++i)
tmp=(tmp+1ll*t2*Pow(t1,k-i)%mod*Pow(Pow(2,i-1),n)%mod)%mod;
printf("%lld\n",(Pow(Pow(2,k),n)-tmp+mod)%mod);
}
return true;
}
signed main()
{
Init();
scanf("%lld",&T);
while(T--)
if(!Solve())
printf("-1\n");
return 0;
}
/*
-std=c++11
-std=c99
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2019-01-03 [HNOI2008]玩具装箱TOY